/[gxemul]/trunk/src/emul.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 40733 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: emul.c,v 1.238 2005/11/19 18:53:06 debug Exp $
29 *
30 * Emulation startup and misc. routines.
31 */
32
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "arcbios.h"
42 #include "bintrans.h"
43 #include "cpu.h"
44 #include "emul.h"
45 #include "console.h"
46 #include "debugger.h"
47 #include "device.h"
48 #include "diskimage.h"
49 #include "exec_elf.h"
50 #include "machine.h"
51 #include "memory.h"
52 #include "mips_cpu_types.h"
53 #include "misc.h"
54 #include "net.h"
55 #include "sgi_arcbios.h"
56 #include "x11.h"
57
58
59 extern int force_debugger_at_exit;
60
61 extern int extra_argc;
62 extern char **extra_argv;
63
64 extern int verbose;
65 extern int quiet_mode;
66
67 extern struct emul *debugger_emul;
68 extern struct diskimage *diskimages[];
69
70 static char *diskimage_types[] = DISKIMAGE_TYPES;
71
72
73 /*
74 * add_dump_points():
75 *
76 * Take the strings breakpoint_string[] and convert to addresses
77 * (and store them in breakpoint_addr[]).
78 *
79 * TODO: This function should be moved elsewhere.
80 */
81 static void add_dump_points(struct machine *m)
82 {
83 int i;
84 int string_flag;
85 uint64_t dp;
86
87 for (i=0; i<m->n_breakpoints; i++) {
88 string_flag = 0;
89 dp = strtoull(m->breakpoint_string[i], NULL, 0);
90
91 /*
92 * If conversion resulted in 0, then perhaps it is a
93 * symbol:
94 */
95 if (dp == 0) {
96 uint64_t addr;
97 int res = get_symbol_addr(&m->symbol_context,
98 m->breakpoint_string[i], &addr);
99 if (!res)
100 fprintf(stderr,
101 "WARNING! Breakpoint '%s' could not be"
102 " parsed\n",
103 m->breakpoint_string[i]);
104 else {
105 dp = addr;
106 string_flag = 1;
107 }
108 }
109
110 /*
111 * TODO: It would be nice if things like symbolname+0x1234
112 * were automatically converted into the correct address.
113 */
114
115 if (m->arch == ARCH_MIPS) {
116 if ((dp >> 32) == 0 && ((dp >> 31) & 1))
117 dp |= 0xffffffff00000000ULL;
118 }
119
120 m->breakpoint_addr[i] = dp;
121
122 debug("breakpoint %i: 0x%llx", i, (long long)dp);
123 if (string_flag)
124 debug(" (%s)", m->breakpoint_string[i]);
125 debug("\n");
126 }
127 }
128
129
130 /*
131 * fix_console():
132 */
133 static void fix_console(void)
134 {
135 console_deinit();
136 }
137
138
139 /*
140 * iso_load_bootblock():
141 *
142 * Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for
143 * "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra).
144 *
145 * TODO: This function uses too many magic offsets and so on; it should be
146 * cleaned up some day.
147 *
148 * Returns 1 on success, 0 on failure.
149 */
150 static int iso_load_bootblock(struct machine *m, struct cpu *cpu,
151 int disk_id, int disk_type, int iso_type, unsigned char *buf,
152 int *n_loadp, char ***load_namesp)
153 {
154 char str[35];
155 int filenr, i, ofs, dirlen, res = 0, res2, iadd = 4;
156 int found_dir;
157 uint64_t dirofs;
158 uint64_t fileofs, filelen;
159 unsigned char *dirbuf = NULL, *dp;
160 unsigned char *match_entry = NULL;
161 char *p, *filename_orig;
162 char *filename = strdup(cpu->machine->boot_kernel_filename);
163 unsigned char *filebuf = NULL;
164 char *tmpfilename = NULL;
165 char **new_array;
166 int tmpfile_handle;
167
168 if (filename == NULL) {
169 fatal("out of memory\n");
170 exit(1);
171 }
172 filename_orig = filename;
173
174 debug("ISO9660 boot:\n");
175 debug_indentation(iadd);
176
177 /* Volume ID: */
178 ofs = iso_type == 3? 48 : 40;
179 memcpy(str, buf + ofs, sizeof(str));
180 str[32] = '\0'; i = 31;
181 while (i >= 0 && str[i]==' ')
182 str[i--] = '\0';
183 if (str[0])
184 debug("\"%s\"", str);
185 else {
186 /* System ID: */
187 ofs = iso_type == 3? 16 : 8;
188 memcpy(str, buf + ofs, sizeof(str));
189 str[32] = '\0'; i = 31;
190 while (i >= 0 && str[i]==' ')
191 str[i--] = '\0';
192 if (str[0])
193 debug("\"%s\"", str);
194 else
195 debug("(no ID)");
196 }
197
198 debug(":%s\n", filename);
199
200
201 /*
202 * Traverse the directory structure to find the kernel.
203 */
204
205 dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86];
206 if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89])
207 fatal("WARNING: Root directory length mismatch?\n");
208
209 dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) +
210 (buf[0x8f] << 24)) * 2048;
211
212 /* debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs); */
213
214 dirbuf = malloc(dirlen);
215 if (dirbuf == NULL) {
216 fatal("out of memory in iso_load_bootblock()\n");
217 exit(1);
218 }
219
220 res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf,
221 dirlen);
222 if (!res2) {
223 fatal("Couldn't read the disk image. Aborting.\n");
224 goto ret;
225 }
226
227 found_dir = 1; /* Assume root dir */
228 dp = dirbuf; filenr = 1;
229 p = NULL;
230 while (dp < dirbuf + dirlen) {
231 int i, nlen = dp[0];
232 int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) + (dp[5] << 24);
233 int y = dp[6] + (dp[7] << 8);
234 char direntry[65];
235
236 dp += 8;
237
238 /*
239 * As long as there is an \ or / in the filename, then we
240 * have not yet found the directory.
241 */
242 p = strchr(filename, '/');
243 if (p == NULL)
244 p = strchr(filename, '\\');
245
246 /* debug("%i%s: %i, %i, \"", filenr, filenr == found_dir?
247 " [CURRENT]" : "", x, y); */
248 for (i=0; i<nlen && i<sizeof(direntry)-1; i++)
249 if (dp[i]) {
250 direntry[i] = dp[i];
251 /* debug("%c", dp[i]); */
252 } else
253 break;
254 /* debug("\"\n"); */
255 direntry[i] = '\0';
256
257 /* A directory name match? */
258 if (p != NULL && strncasecmp(filename, direntry, nlen) == 0
259 && nlen == (size_t)p - (size_t)filename && found_dir == y) {
260 found_dir = filenr;
261 filename = p+1;
262 dirofs = 2048 * (int64_t)x;
263 }
264
265 dp += nlen;
266
267 /* 16-bit aligned lenght: */
268 if (nlen & 1)
269 dp ++;
270
271 filenr ++;
272 }
273
274 p = strchr(filename, '/');
275 if (p == NULL)
276 p = strchr(filename, '\\');
277
278 if (p != NULL) {
279 char *blah = filename_orig;
280
281 fatal("could not find '%s' in /", filename);
282
283 /* Print the first part of the filename: */
284 while (blah != filename)
285 fatal("%c", *blah++);
286
287 fatal("\n");
288 goto ret;
289 }
290
291 /* debug("dirofs = 0x%llx\n", (long long)dirofs); */
292
293 /* Free the old dirbuf, and allocate a new one: */
294 free(dirbuf);
295 dirbuf = malloc(512);
296 if (dirbuf == NULL) {
297 fatal("out of memory in iso_load_bootblock()\n");
298 exit(1);
299 }
300
301 for (;;) {
302 int len, i;
303
304 /* Too close to another sector? Then realign. */
305 if ((dirofs & 2047) + 70 > 2047) {
306 dirofs = (dirofs | 2047) + 1;
307 /* debug("realign dirofs = 0x%llx\n", dirofs); */
308 }
309
310 res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs,
311 dirbuf, 256);
312 if (!res2) {
313 fatal("Couldn't read the disk image. Aborting.\n");
314 goto ret;
315 }
316
317 dp = dirbuf;
318 len = dp[0];
319 if (len < 2)
320 break;
321
322 /*
323 * TODO: Actually parse the directory entry!
324 *
325 * Haha, this must be rewritten.
326 */
327 for (i=32; i<len; i++) {
328 if (i < len - strlen(filename))
329 if (strncasecmp(filename, (char *)dp + i,
330 strlen(filename)) == 0) {
331 /* The filename was found somewhere
332 in the directory entry. */
333 if (match_entry != NULL) {
334 fatal("TODO: I'm too lazy to"
335 " implement a correct "
336 "directory parser right "
337 "now... (BUG)\n");
338 exit(1);
339 }
340 match_entry = malloc(512);
341 if (match_entry == NULL) {
342 fatal("out of memory\n");
343 exit(1);
344 }
345 memcpy(match_entry, dp, 512);
346 break;
347 }
348 }
349
350 dirofs += len;
351 }
352
353 if (match_entry == NULL) {
354 char *blah = filename_orig;
355
356 fatal("could not find '%s' in /", filename);
357
358 /* Print the first part of the filename: */
359 while (blah != filename)
360 fatal("%c", *blah++);
361
362 fatal("\n");
363 goto ret;
364 }
365
366 fileofs = match_entry[2] + (match_entry[3] << 8) +
367 (match_entry[4] << 16) + (match_entry[5] << 24);
368 filelen = match_entry[10] + (match_entry[11] << 8) +
369 (match_entry[12] << 16) + (match_entry[13] << 24);
370 fileofs *= 2048;
371
372 /* debug("filelen=%llx fileofs=%llx\n", (long long)filelen,
373 (long long)fileofs); */
374
375 filebuf = malloc(filelen);
376 if (filebuf == NULL) {
377 fatal("could not allocate %lli bytes to read the file"
378 " from the disk image!\n", (long long)filelen);
379 goto ret;
380 }
381
382 tmpfilename = strdup("/tmp/gxemul.XXXXXXXXXXXX");
383
384 debug("extracting %lli bytes into %s\n",
385 (long long)filelen, tmpfilename);
386
387 res2 = diskimage_access(m, disk_id, disk_type, 0, fileofs, filebuf,
388 filelen);
389 if (!res2) {
390 fatal("could not read the file from the disk image!\n");
391 goto ret;
392 }
393
394 tmpfile_handle = mkstemp(tmpfilename);
395 if (tmpfile_handle < 0) {
396 fatal("could not create %s\n", tmpfilename);
397 exit(1);
398 }
399 write(tmpfile_handle, filebuf, filelen);
400 close(tmpfile_handle);
401
402 /* Add the temporary filename to the load_namesp array: */
403 (*n_loadp)++;
404 new_array = malloc(sizeof(char *) * (*n_loadp));
405 if (new_array == NULL) {
406 fatal("out of memory\n");
407 exit(1);
408 }
409 memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));
410 *load_namesp = new_array;
411
412 /* This adds a Backspace char in front of the filename; this
413 is a special hack which causes the file to be removed once
414 it has been loaded. */
415 tmpfilename = realloc(tmpfilename, strlen(tmpfilename) + 2);
416 memmove(tmpfilename + 1, tmpfilename, strlen(tmpfilename) + 1);
417 tmpfilename[0] = 8;
418
419 (*load_namesp)[*n_loadp - 1] = tmpfilename;
420
421 res = 1;
422
423 ret:
424 if (dirbuf != NULL)
425 free(dirbuf);
426
427 if (filebuf != NULL)
428 free(filebuf);
429
430 if (match_entry != NULL)
431 free(match_entry);
432
433 free(filename_orig);
434
435 debug_indentation(-iadd);
436 return res;
437 }
438
439
440 /*
441 * apple_load_bootblock():
442 *
443 * Try to load a kernel from a disk image with an Apple Partition Table.
444 *
445 * TODO: This function uses too many magic offsets and so on; it should be
446 * cleaned up some day. See http://www.awprofessional.com/articles/
447 * article.asp?p=376123&seqNum=3&rl=1 for some info on the Apple
448 * partition format.
449 *
450 * Returns 1 on success, 0 on failure.
451 */
452 static int apple_load_bootblock(struct machine *m, struct cpu *cpu,
453 int disk_id, int disk_type, int *n_loadp, char ***load_namesp)
454 {
455 unsigned char buf[0x8000];
456 int res, partnr, n_partitions = 0, n_hfs_partitions = 0;
457 uint64_t hfs_start, hfs_length;
458
459 res = diskimage_access(m, disk_id, disk_type, 0, 0x0, buf, sizeof(buf));
460 if (!res) {
461 fatal("apple_load_bootblock: couldn't read the disk "
462 "image. Aborting.\n");
463 return 0;
464 }
465
466 partnr = 0;
467 do {
468 int start, length;
469 int ofs = 0x200 * (partnr + 1);
470 if (partnr == 0)
471 n_partitions = buf[ofs + 7];
472 start = (buf[ofs + 8] << 24) + (buf[ofs + 9] << 16) +
473 (buf[ofs + 10] << 8) + buf[ofs + 11];
474 length = (buf[ofs + 12] << 24) + (buf[ofs + 13] << 16) +
475 (buf[ofs + 14] << 8) + buf[ofs + 15];
476
477 debug("partition %i: '%s', type '%s', start %i, length %i\n",
478 partnr, buf + ofs + 0x10, buf + ofs + 0x30,
479 start, length);
480
481 if (strcmp((char *)buf + ofs + 0x30, "Apple_HFS") == 0) {
482 n_hfs_partitions ++;
483 hfs_start = 512 * start;
484 hfs_length = 512 * length;
485 }
486
487 /* Any more partitions? */
488 partnr ++;
489 } while (partnr < n_partitions);
490
491 if (n_hfs_partitions == 0) {
492 fatal("Error: No HFS partition found! TODO\n");
493 return 0;
494 }
495 if (n_hfs_partitions >= 2) {
496 fatal("Error: Too many HFS partitions found! TODO\n");
497 return 0;
498 }
499
500 return 0;
501 }
502
503
504 /*
505 * load_bootblock():
506 *
507 * For some emulation modes, it is possible to boot from a harddisk image by
508 * loading a bootblock from a specific disk offset into memory, and executing
509 * that, instead of requiring a separate kernel file. It is then up to the
510 * bootblock to load a kernel.
511 *
512 * Returns 1 on success, 0 on failure.
513 */
514 static int load_bootblock(struct machine *m, struct cpu *cpu,
515 int *n_loadp, char ***load_namesp)
516 {
517 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
518 iso_type, retval = 0;
519 unsigned char minibuf[0x20];
520 unsigned char *bootblock_buf;
521 uint64_t bootblock_offset;
522 uint64_t bootblock_loadaddr, bootblock_pc;
523
524 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
525 if (boot_disk_id < 0)
526 return 0;
527
528 switch (m->machine_type) {
529 case MACHINE_DEC:
530 /*
531 * The first few bytes of a disk contains information about
532 * where the bootblock(s) are located. (These are all 32-bit
533 * little-endian words.)
534 *
535 * Offset 0x10 = load address
536 * 0x14 = initial PC value
537 * 0x18 = nr of 512-byte blocks to read
538 * 0x1c = offset on disk to where the bootblocks
539 * are (in 512-byte units)
540 * 0x20 = nr of blocks to read...
541 * 0x24 = offset...
542 *
543 * nr of blocks to read and offset are repeated until nr of
544 * blocks to read is zero.
545 */
546 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
547 minibuf, sizeof(minibuf));
548
549 bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
550 + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);
551
552 /* Convert loadaddr to uncached: */
553 if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
554 (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)
555 fatal("\nWARNING! Weird load address 0x%08x.\n\n",
556 (int)bootblock_loadaddr);
557 bootblock_loadaddr &= 0x0fffffffULL;
558 bootblock_loadaddr |= 0xffffffffa0000000ULL;
559
560 bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
561 + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);
562
563 bootblock_pc &= 0x0fffffffULL;
564 bootblock_pc |= 0xffffffffa0000000ULL;
565 cpu->pc = bootblock_pc;
566
567 debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",
568 (int)bootblock_loadaddr, (int)bootblock_pc);
569
570 readofs = 0x18;
571
572 for (;;) {
573 res = diskimage_access(m, boot_disk_id, boot_disk_type,
574 0, readofs, minibuf, sizeof(minibuf));
575 if (!res) {
576 fatal("Couldn't read the disk image. "
577 "Aborting.\n");
578 return 0;
579 }
580
581 n_blocks = minibuf[0] + (minibuf[1] << 8)
582 + (minibuf[2] << 16) + (minibuf[3] << 24);
583
584 bootblock_offset = (minibuf[4] + (minibuf[5] << 8)
585 + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;
586
587 if (n_blocks < 1)
588 break;
589
590 debug(readofs == 0x18? ": %i" : " + %i", n_blocks);
591
592 if (n_blocks * 512 > 65536)
593 fatal("\nWARNING! Unusually large bootblock "
594 "(%i bytes)\n\n", n_blocks * 512);
595
596 bootblock_buf = malloc(n_blocks * 512);
597 if (bootblock_buf == NULL) {
598 fprintf(stderr, "out of memory in "
599 "load_bootblock()\n");
600 exit(1);
601 }
602
603 res = diskimage_access(m, boot_disk_id, boot_disk_type,
604 0, bootblock_offset, bootblock_buf, n_blocks * 512);
605 if (!res) {
606 fatal("WARNING: could not load bootblocks from"
607 " disk offset 0x%llx\n",
608 (long long)bootblock_offset);
609 }
610
611 store_buf(cpu, bootblock_loadaddr,
612 (char *)bootblock_buf, n_blocks * 512);
613
614 bootblock_loadaddr += 512*n_blocks;
615 free(bootblock_buf);
616 readofs += 8;
617 }
618
619 debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
620 return 1;
621
622 case MACHINE_X86:
623 /* TODO: "El Torito" etc? */
624 if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
625 boot_disk_type))
626 break;
627
628 bootblock_buf = malloc(512);
629 if (bootblock_buf == NULL) {
630 fprintf(stderr, "Out of memory.\n");
631 exit(1);
632 }
633
634 debug("loading PC bootsector from %s id %i\n",
635 diskimage_types[boot_disk_type], boot_disk_id);
636
637 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
638 bootblock_buf, 512);
639 if (!res) {
640 fatal("Couldn't read the disk image. Aborting.\n");
641 return 0;
642 }
643
644 if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)
645 debug("WARNING! The 0x55,0xAA marker is missing! "
646 "Booting anyway.\n");
647 store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);
648 free(bootblock_buf);
649
650 return 1;
651 }
652
653
654 /*
655 * Try reading a kernel manually from the disk. The code here
656 * does not rely on machine-dependent boot blocks etc.
657 */
658 /* ISO9660: (0x800 bytes at 0x8000) */
659 bootblock_buf = malloc(0x800);
660 if (bootblock_buf == NULL) {
661 fprintf(stderr, "Out of memory.\n");
662 exit(1);
663 }
664
665 res = diskimage_access(m, boot_disk_id, boot_disk_type,
666 0, 0x8000, bootblock_buf, 0x800);
667 if (!res) {
668 fatal("Couldn't read the disk image. Aborting.\n");
669 return 0;
670 }
671
672 iso_type = 0;
673 if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)
674 iso_type = 1;
675 if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)
676 iso_type = 2;
677 if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)
678 iso_type = 3;
679
680 if (iso_type != 0) {
681 /* We can't load a kernel if the name
682 isn't specified. */
683 if (cpu->machine->boot_kernel_filename == NULL ||
684 cpu->machine->boot_kernel_filename[0] == '\0')
685 fatal("\nISO9660 filesystem, but no kernel "
686 "specified? (Use the -j option.)\n");
687 else
688 retval = iso_load_bootblock(m, cpu, boot_disk_id,
689 boot_disk_type, iso_type, bootblock_buf,
690 n_loadp, load_namesp);
691 }
692
693 if (retval != 0)
694 goto ret_ok;
695
696 /* Apple parition table: */
697 res = diskimage_access(m, boot_disk_id, boot_disk_type,
698 0, 0x0, bootblock_buf, 0x800);
699 if (!res) {
700 fatal("Couldn't read the disk image. Aborting.\n");
701 return 0;
702 }
703 if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' &&
704 bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') {
705 /* We can't load a kernel if the name
706 isn't specified. */
707 if (cpu->machine->boot_kernel_filename == NULL ||
708 cpu->machine->boot_kernel_filename[0] == '\0')
709 fatal("\nApple partition table, but no kernel "
710 "specified? (Use the -j option.)\n");
711 else
712 retval = apple_load_bootblock(m, cpu, boot_disk_id,
713 boot_disk_type, n_loadp, load_namesp);
714 }
715
716 ret_ok:
717 free(bootblock_buf);
718 return retval;
719 }
720
721
722 /*
723 * emul_new():
724 *
725 * Returns a reasonably initialized struct emul.
726 */
727 struct emul *emul_new(char *name)
728 {
729 struct emul *e;
730 e = malloc(sizeof(struct emul));
731 if (e == NULL) {
732 fprintf(stderr, "out of memory in emul_new()\n");
733 exit(1);
734 }
735
736 memset(e, 0, sizeof(struct emul));
737
738 /* Sane default values: */
739 e->n_machines = 0;
740 e->next_serial_nr = 1;
741
742 if (name != NULL) {
743 e->name = strdup(name);
744 if (e->name == NULL) {
745 fprintf(stderr, "out of memory in emul_new()\n");
746 exit(1);
747 }
748 }
749
750 return e;
751 }
752
753
754 /*
755 * emul_add_machine():
756 *
757 * Calls machine_new(), adds the new machine into the emul struct, and
758 * returns a pointer to the new machine.
759 *
760 * This function should be used instead of manually calling machine_new().
761 */
762 struct machine *emul_add_machine(struct emul *e, char *name)
763 {
764 struct machine *m;
765
766 m = machine_new(name, e);
767 m->serial_nr = (e->next_serial_nr ++);
768
769 e->n_machines ++;
770 e->machines = realloc(e->machines,
771 sizeof(struct machine *) * e->n_machines);
772 if (e->machines == NULL) {
773 fprintf(stderr, "emul_add_machine(): out of memory\n");
774 exit(1);
775 }
776
777 e->machines[e->n_machines - 1] = m;
778 return m;
779 }
780
781
782 /*
783 * add_arc_components():
784 *
785 * This function adds ARCBIOS memory descriptors for the loaded program,
786 * and ARCBIOS components for SCSI devices.
787 */
788 static void add_arc_components(struct machine *m)
789 {
790 struct cpu *cpu = m->cpus[m->bootstrap_cpu];
791 uint64_t start = cpu->pc & 0x1fffffff;
792 uint64_t len = 0xc00000 - start;
793 struct diskimage *d;
794 uint64_t scsicontroller, scsidevice, scsidisk;
795
796 if ((cpu->pc >> 60) != 0xf) {
797 start = cpu->pc & 0xffffffffffULL;
798 len = 0xc00000 - start;
799 }
800
801 len += 1048576 * m->memory_offset_in_mb;
802
803 /*
804 * NOTE/TODO: magic 12MB end of load program area
805 *
806 * Hm. This breaks the old FreeBSD/MIPS snapshots...
807 */
808 #if 0
809 arcbios_add_memory_descriptor(cpu,
810 0x60000 + m->memory_offset_in_mb * 1048576,
811 start-0x60000 - m->memory_offset_in_mb * 1048576,
812 ARCBIOS_MEM_FreeMemory);
813 #endif
814 arcbios_add_memory_descriptor(cpu,
815 start, len, ARCBIOS_MEM_LoadedProgram);
816
817 scsicontroller = arcbios_get_scsicontroller(m);
818 if (scsicontroller == 0)
819 return;
820
821 /* TODO: The device 'name' should defined be somewhere else. */
822
823 d = m->first_diskimage;
824 while (d != NULL) {
825 if (d->type == DISKIMAGE_SCSI) {
826 int a, b, flags = COMPONENT_FLAG_Input;
827 char component_string[100];
828 char *name = "DEC RZ58 (C) DEC2000";
829
830 /* Read-write, or read-only? */
831 if (d->writable)
832 flags |= COMPONENT_FLAG_Output;
833 else
834 flags |= COMPONENT_FLAG_ReadOnly;
835
836 a = COMPONENT_TYPE_DiskController;
837 b = COMPONENT_TYPE_DiskPeripheral;
838
839 if (d->is_a_cdrom) {
840 flags |= COMPONENT_FLAG_Removable;
841 a = COMPONENT_TYPE_CDROMController;
842 b = COMPONENT_TYPE_FloppyDiskPeripheral;
843 name = "NEC CD-ROM CDR-210P 1.0 ";
844 }
845
846 scsidevice = arcbios_addchild_manual(cpu,
847 COMPONENT_CLASS_ControllerClass,
848 a, flags, 1, 2, d->id, 0xffffffff,
849 name, scsicontroller, NULL, 0);
850
851 scsidisk = arcbios_addchild_manual(cpu,
852 COMPONENT_CLASS_PeripheralClass,
853 b, flags, 1, 2, 0, 0xffffffff, NULL,
854 scsidevice, NULL, 0);
855
856 /*
857 * Add device string to component address mappings:
858 * "scsi(0)disk(0)rdisk(0)partition(0)"
859 */
860
861 if (d->is_a_cdrom) {
862 snprintf(component_string,
863 sizeof(component_string),
864 "scsi(0)cdrom(%i)", d->id);
865 arcbios_add_string_to_component(m,
866 component_string, scsidevice);
867
868 snprintf(component_string,
869 sizeof(component_string),
870 "scsi(0)cdrom(%i)fdisk(0)", d->id);
871 arcbios_add_string_to_component(m,
872 component_string, scsidisk);
873 } else {
874 snprintf(component_string,
875 sizeof(component_string),
876 "scsi(0)disk(%i)", d->id);
877 arcbios_add_string_to_component(m,
878 component_string, scsidevice);
879
880 snprintf(component_string,
881 sizeof(component_string),
882 "scsi(0)disk(%i)rdisk(0)", d->id);
883 arcbios_add_string_to_component(m,
884 component_string, scsidisk);
885 }
886 }
887
888 d = d->next;
889 }
890 }
891
892
893 /*
894 * emul_machine_setup():
895 *
896 * o) Initialize the hardware (RAM, devices, CPUs, ...) which
897 * will be emulated in this machine.
898 *
899 * o) Load ROM code and/or other programs into emulated memory.
900 *
901 * o) Special hacks needed after programs have been loaded.
902 */
903 void emul_machine_setup(struct machine *m, int n_load, char **load_names,
904 int n_devices, char **device_names)
905 {
906 struct emul *emul;
907 struct cpu *cpu;
908 int i, iadd=4;
909 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
910 int byte_order;
911
912 emul = m->emul;
913
914 debug("machine \"%s\":\n", m->name);
915 debug_indentation(iadd);
916
917 /* For userland-only, this decides which ARCH/cpu_name to use: */
918 if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
919 useremul_name_to_useremul(NULL, m->userland_emul,
920 &m->arch, &m->machine_name, &m->cpu_name);
921 if (m->arch == ARCH_NOARCH) {
922 printf("Unsupported userland emulation mode.\n");
923 exit(1);
924 }
925 }
926
927 if (m->machine_type == MACHINE_NONE) {
928 fatal("No machine type specified?\n");
929 exit(1);
930 }
931
932 m->cpu_family = cpu_family_ptr_by_number(m->arch);
933
934 if (m->arch == ARCH_ALPHA)
935 m->arch_pagesize = 8192;
936
937 if (m->arch != ARCH_MIPS)
938 m->bintrans_enable = 0;
939
940 machine_memsize_fix(m);
941
942 /*
943 * Create the system's memory:
944 *
945 * (Don't print the amount for userland-only emulation; the
946 * size doesn't matter.)
947 */
948 if (m->machine_type != MACHINE_USERLAND)
949 debug("memory: %i MB", m->physical_ram_in_mb);
950 memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
951 if (m->memory_offset_in_mb > 0) {
952 /*
953 * A special hack is used for some SGI models,
954 * where memory is offset by 128MB to leave room for
955 * EISA space and other things.
956 */
957 debug(" (offset by %iMB)", m->memory_offset_in_mb);
958 memory_amount += 1048576 * m->memory_offset_in_mb;
959 }
960 m->memory = memory_new(memory_amount, m->arch);
961 if (m->machine_type != MACHINE_USERLAND)
962 debug("\n");
963
964 /* Create CPUs: */
965 if (m->cpu_name == NULL)
966 machine_default_cputype(m);
967 if (m->ncpus == 0) {
968 /* TODO: This should be moved elsewhere... */
969 if (m->machine_type == MACHINE_BEBOX)
970 m->ncpus = 2;
971 else if (m->machine_type == MACHINE_ARC &&
972 m->machine_subtype == MACHINE_ARC_NEC_R96)
973 m->ncpus = 2;
974 else if (m->machine_type == MACHINE_ARC &&
975 m->machine_subtype == MACHINE_ARC_NEC_R98)
976 m->ncpus = 4;
977 else
978 m->ncpus = 1;
979 }
980 m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);
981 if (m->cpus == NULL) {
982 fprintf(stderr, "out of memory\n");
983 exit(1);
984 }
985 memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
986
987 /* Initialize dynamic binary translation, if available: */
988 if (m->bintrans_enable)
989 bintrans_init(m, m->memory);
990
991 debug("cpu0");
992 if (m->ncpus > 1)
993 debug(" .. cpu%i", m->ncpus - 1);
994 debug(": ");
995 for (i=0; i<m->ncpus; i++) {
996 m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
997 if (m->bintrans_enable)
998 bintrans_init_cpu(m->cpus[i]);
999 }
1000 debug("\n");
1001
1002 #if 0
1003 /* Special case: The Playstation Portable has an additional CPU: */
1004 if (m->machine_type == MACHINE_PSP) {
1005 debug("cpu%i: ", m->ncpus);
1006 m->cpus[m->ncpus] = cpu_new(m->memory, m,
1007 0 /* use 0 here to show info with debug() */,
1008 "Allegrex" /* TODO */);
1009 if (m->bintrans_enable)
1010 bintrans_init_cpu(m->cpus[m->ncpus]);
1011 debug("\n");
1012 m->ncpus ++;
1013 }
1014 #endif
1015
1016 if (m->use_random_bootstrap_cpu)
1017 m->bootstrap_cpu = random() % m->ncpus;
1018 else
1019 m->bootstrap_cpu = 0;
1020
1021 cpu = m->cpus[m->bootstrap_cpu];
1022
1023 /* Set cpu->useremul_syscall, and use userland_memory_rw: */
1024 if (m->userland_emul != NULL) {
1025 useremul_name_to_useremul(cpu,
1026 m->userland_emul, NULL, NULL, NULL);
1027
1028 switch (m->arch) {
1029 #ifdef ENABLE_ALPHA
1030 case ARCH_ALPHA:
1031 cpu->memory_rw = alpha_userland_memory_rw;
1032 break;
1033 #endif
1034 default:cpu->memory_rw = userland_memory_rw;
1035 }
1036 }
1037
1038 if (m->use_x11)
1039 x11_init(m);
1040
1041 /* Fill memory with random bytes: */
1042 if (m->random_mem_contents) {
1043 for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
1044 unsigned char data[256];
1045 unsigned int j;
1046 for (j=0; j<sizeof(data); j++)
1047 data[j] = random() & 255;
1048 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
1049 MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
1050 }
1051 }
1052
1053 if (m->userland_emul != NULL) {
1054 /*
1055 * For userland-only emulation, no machine emulation
1056 * is needed.
1057 */
1058 } else {
1059 for (i=0; i<n_devices; i++)
1060 device_add(m, device_names[i]);
1061
1062 machine_setup(m);
1063 }
1064
1065 diskimage_dump_info(m);
1066
1067 /* Load files (ROM code, boot code, ...) into memory: */
1068 if (n_load == 0) {
1069 if (m->first_diskimage != NULL) {
1070 if (!load_bootblock(m, cpu, &n_load, &load_names)) {
1071 fprintf(stderr, "\nNo executable files were"
1072 " specified, and booting directly from disk"
1073 " failed.\n");
1074 exit(1);
1075 }
1076 } else {
1077 fprintf(stderr, "No executable file(s) loaded, and "
1078 "we are not booting directly from a disk image."
1079 "\nAborting.\n");
1080 exit(1);
1081 }
1082 }
1083
1084 while (n_load > 0) {
1085 FILE *tmp_f;
1086 char *name_to_load = *load_names;
1087 int remove_after_load = 0;
1088
1089 /* Special hack for removing temporary files: */
1090 if (name_to_load[0] == 8) {
1091 name_to_load ++;
1092 remove_after_load = 1;
1093 }
1094
1095 /*
1096 * gzipped files are automagically gunzipped:
1097 * NOTE/TODO: This isn't secure. system() is used.
1098 */
1099 tmp_f = fopen(name_to_load, "r");
1100 if (tmp_f != NULL) {
1101 unsigned char buf[2]; /* gzip header */
1102 memset(buf, 0, sizeof(buf));
1103 fread(buf, 1, sizeof(buf), tmp_f);
1104 if (buf[0]==0x1f && buf[1]==0x8b) {
1105 size_t zzlen = strlen(name_to_load)*2 + 100;
1106 char *zz = malloc(zzlen);
1107 debug("gunziping %s\n", name_to_load);
1108 /*
1109 * gzip header found. If this was a file
1110 * extracted from, say, a CDROM image, then it
1111 * already has a temporary name. Otherwise we
1112 * have to gunzip into a temporary file.
1113 */
1114 if (remove_after_load) {
1115 snprintf(zz, zzlen, "mv %s %s.gz",
1116 name_to_load, name_to_load);
1117 system(zz);
1118 snprintf(zz, zzlen, "gunzip %s.gz",
1119 name_to_load);
1120 system(zz);
1121 } else {
1122 /* gunzip into new temp file: */
1123 int tmpfile_handle;
1124 char *new_temp_name =
1125 strdup("/tmp/gxemul.XXXXXXXXXXXX");
1126 tmpfile_handle = mkstemp(new_temp_name);
1127 close(tmpfile_handle);
1128 snprintf(zz, zzlen, "gunzip -c '%s' > "
1129 "%s", name_to_load, new_temp_name);
1130 system(zz);
1131 name_to_load = new_temp_name;
1132 remove_after_load = 1;
1133 }
1134 free(zz);
1135 }
1136 fclose(tmp_f);
1137 }
1138
1139 /*
1140 * Ugly (but usable) hack for Playstation Portable: If the
1141 * filename ends with ".pbp" and the file contains an ELF
1142 * header, then extract the ELF file into a temporary file.
1143 */
1144 if (strlen(name_to_load) > 4 && strcasecmp(name_to_load +
1145 strlen(name_to_load) - 4, ".pbp") == 0 &&
1146 (tmp_f = fopen(name_to_load, "r")) != NULL) {
1147 off_t filesize, j, found=0;
1148 unsigned char *buf;
1149 fseek(tmp_f, 0, SEEK_END);
1150 filesize = ftello(tmp_f);
1151 fseek(tmp_f, 0, SEEK_SET);
1152 buf = malloc(filesize);
1153 if (buf == NULL) {
1154 fprintf(stderr, "out of memory while trying"
1155 " to read %s\n", name_to_load);
1156 exit(1);
1157 }
1158 fread(buf, 1, filesize, tmp_f);
1159 fclose(tmp_f);
1160 /* Search for the ELF header, from offset 1 (!): */
1161 for (j=1; j<filesize - 4; j++)
1162 if (memcmp(buf + j, ELFMAG, SELFMAG) == 0) {
1163 found = j;
1164 break;
1165 }
1166 if (found != 0) {
1167 int tmpfile_handle;
1168 char *new_temp_name =
1169 strdup("/tmp/gxemul.XXXXXXXXXXXX");
1170 debug("extracting ELF from %s (offset 0x%x)\n",
1171 name_to_load, (int)found);
1172 tmpfile_handle = mkstemp(new_temp_name);
1173 write(tmpfile_handle, buf + found,
1174 filesize - found);
1175 close(tmpfile_handle);
1176 name_to_load = new_temp_name;
1177 remove_after_load = 1;
1178 }
1179 }
1180
1181 /* Special things required _before_ loading the file: */
1182 switch (m->arch) {
1183 case ARCH_X86:
1184 /*
1185 * X86 machines normally don't need to load any files,
1186 * they can boot from disk directly. Therefore, an x86
1187 * machine usually boots up in 16-bit real mode. When
1188 * loading a 32-bit (or even 64-bit) ELF, that's not
1189 * very nice, hence this special case.
1190 */
1191 pc_bios_simple_pmode_setup(cpu);
1192 break;
1193 }
1194
1195 byte_order = NO_BYTE_ORDER_OVERRIDE;
1196
1197 /*
1198 * Load the file: :-)
1199 */
1200 file_load(m, m->memory, name_to_load, &entrypoint,
1201 m->arch, &gp, &byte_order, &toc);
1202
1203 if (remove_after_load) {
1204 debug("removing %s\n", name_to_load);
1205 unlink(name_to_load);
1206 }
1207
1208 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
1209 cpu->byte_order = byte_order;
1210
1211 cpu->pc = entrypoint;
1212
1213 switch (m->arch) {
1214
1215 case ARCH_ALPHA:
1216 /* For position-independent code: */
1217 cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
1218 break;
1219
1220 case ARCH_ARM:
1221 if (cpu->pc & 3) {
1222 fatal("ARM: lowest bits of pc set: TODO\n");
1223 exit(1);
1224 }
1225 cpu->pc &= 0xfffffffc;
1226 break;
1227
1228 case ARCH_AVR:
1229 cpu->pc &= 0xfffff;
1230 if (cpu->pc & 1) {
1231 fatal("AVR: lowest bit of pc set: TODO\n");
1232 exit(1);
1233 }
1234 break;
1235
1236 case ARCH_HPPA:
1237 break;
1238
1239 case ARCH_I960:
1240 break;
1241
1242 case ARCH_IA64:
1243 break;
1244
1245 case ARCH_M68K:
1246 break;
1247
1248 case ARCH_MIPS:
1249 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
1250 cpu->pc |= 0xffffffff00000000ULL;
1251
1252 cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
1253
1254 if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
1255 (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
1256 cpu->cd.mips.gpr[MIPS_GPR_GP] |=
1257 0xffffffff00000000ULL;
1258 break;
1259
1260 case ARCH_PPC:
1261 /* See http://www.linuxbase.org/spec/ELF/ppc64/
1262 spec/x458.html for more info. */
1263 cpu->cd.ppc.gpr[2] = toc;
1264 /* TODO */
1265 if (cpu->cd.ppc.bits == 32)
1266 cpu->pc &= 0xffffffffULL;
1267 break;
1268
1269 case ARCH_SH:
1270 if (cpu->cd.sh.bits == 32)
1271 cpu->pc &= 0xffffffffULL;
1272 cpu->pc &= ~1;
1273 break;
1274
1275 case ARCH_SPARC:
1276 break;
1277
1278 case ARCH_X86:
1279 /*
1280 * NOTE: The toc field is used to indicate an ELF32
1281 * or ELF64 load.
1282 */
1283 switch (toc) {
1284 case 0: /* 16-bit? TODO */
1285 cpu->pc &= 0xffffffffULL;
1286 break;
1287 case 1: /* 32-bit. */
1288 cpu->pc &= 0xffffffffULL;
1289 break;
1290 case 2: /* 64-bit: TODO */
1291 fatal("64-bit x86 load. TODO\n");
1292 exit(1);
1293 }
1294 break;
1295
1296 default:
1297 fatal("emul_machine_setup(): Internal error: "
1298 "Unimplemented arch %i\n", m->arch);
1299 exit(1);
1300 }
1301
1302 /*
1303 * For userland emulation, the remaining items
1304 * on the command line will be passed as parameters
1305 * to the emulated program, and will not be treated
1306 * as filenames to load into the emulator.
1307 * The program's name will be in load_names[0], and the
1308 * rest of the parameters in load_names[1] and up.
1309 */
1310 if (m->userland_emul != NULL)
1311 break;
1312
1313 n_load --;
1314 load_names ++;
1315 }
1316
1317 if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
1318 cpu->byte_order = m->byte_order_override;
1319
1320 /* Same byte order and entrypoint for all CPUs: */
1321 for (i=0; i<m->ncpus; i++)
1322 if (i != m->bootstrap_cpu) {
1323 m->cpus[i]->byte_order = cpu->byte_order;
1324 m->cpus[i]->pc = cpu->pc;
1325 }
1326
1327 if (m->userland_emul != NULL)
1328 useremul_setup(cpu, n_load, load_names);
1329
1330 /* Startup the bootstrap CPU: */
1331 cpu->bootstrap_cpu_flag = 1;
1332 cpu->running = 1;
1333
1334 /* ... or pause all CPUs, if start_paused is set: */
1335 if (m->start_paused) {
1336 for (i=0; i<m->ncpus; i++)
1337 m->cpus[i]->running = 0;
1338 }
1339
1340 /* Add PC dump points: */
1341 add_dump_points(m);
1342
1343 /* TODO: This is MIPS-specific! */
1344 if (m->machine_type == MACHINE_DEC &&
1345 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1346 add_symbol_name(&m->symbol_context,
1347 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
1348
1349 symbol_recalc_sizes(&m->symbol_context);
1350
1351 if (m->max_random_cycles_per_chunk > 0)
1352 debug("using random cycle chunks (1 to %i cycles)\n",
1353 m->max_random_cycles_per_chunk);
1354
1355 /* Special hack for ARC/SGI emulation: */
1356 if ((m->machine_type == MACHINE_ARC ||
1357 m->machine_type == MACHINE_SGI) && m->prom_emulation)
1358 add_arc_components(m);
1359
1360
1361 #if 0
1362 if (m->machine_type == MACHINE_IQ80321) {
1363 store_32bit_word(cpu, 0xc0200000, 0);
1364 store_32bit_word(cpu, 0xc0200004, 0xd0000000);
1365 }
1366 #endif
1367
1368
1369 debug("starting cpu%i at ", m->bootstrap_cpu);
1370 switch (m->arch) {
1371
1372 case ARCH_ARM:
1373 /* ARM cpus aren't 64-bit: */
1374 debug("0x%08x", (int)entrypoint);
1375 break;
1376
1377 case ARCH_AVR:
1378 /* Atmel AVR uses a 16-bit or 22-bit program counter: */
1379 debug("0x%04x", (int)entrypoint);
1380 break;
1381
1382 case ARCH_MIPS:
1383 if (cpu->is_32bit) {
1384 debug("0x%08x", (int)m->cpus[
1385 m->bootstrap_cpu]->pc);
1386 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1387 debug(" (gp=0x%08x)", (int)m->cpus[
1388 m->bootstrap_cpu]->cd.mips.gpr[
1389 MIPS_GPR_GP]);
1390 } else {
1391 debug("0x%016llx", (long long)m->cpus[
1392 m->bootstrap_cpu]->pc);
1393 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1394 debug(" (gp=0x%016llx)", (long long)
1395 cpu->cd.mips.gpr[MIPS_GPR_GP]);
1396 }
1397 break;
1398
1399 case ARCH_PPC:
1400 if (cpu->cd.ppc.bits == 32)
1401 debug("0x%08x", (int)entrypoint);
1402 else
1403 debug("0x%016llx", (long long)entrypoint);
1404 break;
1405
1406 case ARCH_X86:
1407 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1408 (long long)cpu->pc);
1409 break;
1410
1411 default:
1412 debug("0x%016llx", (long long)cpu->pc);
1413 }
1414 debug("\n");
1415
1416 debug_indentation(-iadd);
1417 }
1418
1419
1420 /*
1421 * emul_dumpinfo():
1422 *
1423 * Dump info about all machines in an emul.
1424 */
1425 void emul_dumpinfo(struct emul *e)
1426 {
1427 int j, nm, iadd = 4;
1428
1429 if (e->net != NULL)
1430 net_dumpinfo(e->net);
1431
1432 nm = e->n_machines;
1433 for (j=0; j<nm; j++) {
1434 debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
1435 debug_indentation(iadd);
1436 machine_dumpinfo(e->machines[j]);
1437 debug_indentation(-iadd);
1438 }
1439 }
1440
1441
1442 /*
1443 * emul_simple_init():
1444 *
1445 * For a normal setup:
1446 *
1447 * o) Initialize a network.
1448 * o) Initialize one machine.
1449 *
1450 * For a userland-only setup:
1451 *
1452 * o) Initialize a "pseudo"-machine.
1453 */
1454 void emul_simple_init(struct emul *emul)
1455 {
1456 int iadd=4;
1457 struct machine *m;
1458
1459 if (emul->n_machines != 1) {
1460 fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
1461 exit(1);
1462 }
1463
1464 m = emul->machines[0];
1465
1466 if (m->userland_emul == NULL) {
1467 debug("Simple setup...\n");
1468 debug_indentation(iadd);
1469
1470 /* Create a simple network: */
1471 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1472 "10.0.0.0", 8, NULL, 0, 0);
1473 } else {
1474 /* Userland pseudo-machine: */
1475 debug("Syscall emulation (userland-only) setup...\n");
1476 debug_indentation(iadd);
1477 }
1478
1479 /* Create the machine: */
1480 emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
1481
1482 debug_indentation(-iadd);
1483 }
1484
1485
1486 /*
1487 * emul_create_from_configfile():
1488 *
1489 * Create an emul struct by reading settings from a configuration file.
1490 */
1491 struct emul *emul_create_from_configfile(char *fname)
1492 {
1493 int iadd = 4;
1494 struct emul *e = emul_new(fname);
1495 FILE *f;
1496 char buf[128];
1497 size_t len;
1498
1499 debug("Creating emulation from configfile \"%s\":\n", fname);
1500 debug_indentation(iadd);
1501
1502 f = fopen(fname, "r");
1503 if (f == NULL) {
1504 perror(fname);
1505 exit(1);
1506 }
1507
1508 /* Read header: (must be !!gxemul) */
1509 len = fread(buf, 1, 8, f);
1510 if (len != 8 || strncmp(buf, "!!gxemul", 8) != 0) {
1511 fprintf(stderr, "%s: must start with '!!gxemul'\n", fname);
1512 exit(1);
1513 }
1514
1515 /* Restart from beginning: */
1516 rewind(f);
1517
1518 emul_parse_config(e, f);
1519
1520 fclose(f);
1521 debug_indentation(-iadd);
1522 return e;
1523 }
1524
1525
1526 /*
1527 * emul_run():
1528 *
1529 * o) Set up things needed before running emulations.
1530 *
1531 * o) Run emulations (one or more, in parallel).
1532 *
1533 * o) De-initialize things.
1534 */
1535 void emul_run(struct emul **emuls, int n_emuls)
1536 {
1537 struct emul *e;
1538 int i = 0, j, go = 1, n, anything;
1539
1540 if (n_emuls < 1) {
1541 fprintf(stderr, "emul_run(): no thing to do\n");
1542 return;
1543 }
1544
1545 atexit(fix_console);
1546
1547 i = 79;
1548 while (i-- > 0)
1549 debug("-");
1550 debug("\n\n");
1551
1552 /* Initialize the interactive debugger: */
1553 debugger_init(emuls, n_emuls);
1554
1555 /*
1556 * console_init_main() makes sure that the terminal is in a
1557 * reasonable state.
1558 *
1559 * The SIGINT handler is for CTRL-C (enter the interactive debugger).
1560 *
1561 * The SIGCONT handler is invoked whenever the user presses CTRL-Z
1562 * (or sends SIGSTOP) and then continues. It makes sure that the
1563 * terminal is in an expected state.
1564 */
1565 console_init_main(emuls[0]); /* TODO: what is a good argument? */
1566 signal(SIGINT, debugger_activate);
1567 signal(SIGCONT, console_sigcont);
1568
1569 /* Not in verbose mode? Then set quiet_mode. */
1570 if (!verbose)
1571 quiet_mode = 1;
1572
1573 /* Initialize all CPUs in all machines in all emulations: */
1574 for (i=0; i<n_emuls; i++) {
1575 e = emuls[i];
1576 if (e == NULL)
1577 continue;
1578 for (j=0; j<e->n_machines; j++)
1579 cpu_run_init(e->machines[j]);
1580 }
1581
1582 /* TODO: Generalize: */
1583 if (emuls[0]->machines[0]->show_trace_tree)
1584 cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1585 emuls[0]->machines[0]->cpus[0]->pc);
1586
1587 /*
1588 * MAIN LOOP:
1589 *
1590 * Run all emulations in parallel, running each machine in
1591 * each emulation.
1592 */
1593 while (go) {
1594 go = 0;
1595
1596 x11_check_event(emuls, n_emuls);
1597
1598 for (i=0; i<n_emuls; i++) {
1599 e = emuls[i];
1600 if (e == NULL)
1601 continue;
1602
1603 for (j=0; j<e->n_machines; j++) {
1604 /* TODO: cpu_run() is a strange name, since
1605 there can be multiple cpus in a machine */
1606 anything = cpu_run(e, e->machines[j]);
1607 if (anything)
1608 go = 1;
1609 }
1610 }
1611 }
1612
1613 /* Deinitialize all CPUs in all machines in all emulations: */
1614 for (i=0; i<n_emuls; i++) {
1615 e = emuls[i];
1616 if (e == NULL)
1617 continue;
1618 for (j=0; j<e->n_machines; j++)
1619 cpu_run_deinit(e->machines[j]);
1620 }
1621
1622 /* force_debugger_at_exit flag set? Then enter the debugger: */
1623 if (force_debugger_at_exit) {
1624 quiet_mode = 0;
1625 debugger_reset();
1626 debugger();
1627 }
1628
1629 /* Any machine using X11? Then we should wait before exiting: */
1630 n = 0;
1631 for (i=0; i<n_emuls; i++)
1632 for (j=0; j<emuls[i]->n_machines; j++)
1633 if (emuls[i]->machines[j]->use_x11)
1634 n++;
1635 if (n > 0) {
1636 printf("Press enter to quit.\n");
1637 while (!console_charavail(MAIN_CONSOLE)) {
1638 x11_check_event(emuls, n_emuls);
1639 usleep(1);
1640 }
1641 console_readchar(MAIN_CONSOLE);
1642 }
1643
1644 console_deinit();
1645 }
1646

  ViewVC Help
Powered by ViewVC 1.1.26