/[gxemul]/upstream/0.3.8/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 /upstream/0.3.8/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26