/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40506 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26