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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (show annotations)
Mon Oct 8 16:20:03 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 40656 byte(s)
0.4.0
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.254 2006/06/22 13:22:40 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 "cpu.h"
43 #include "emul.h"
44 #include "console.h"
45 #include "debugger.h"
46 #include "device.h"
47 #include "diskimage.h"
48 #include "exec_elf.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "mips_cpu_types.h"
52 #include "misc.h"
53 #include "net.h"
54 #include "sgi_arcbios.h"
55 #include "x11.h"
56
57
58 extern int force_debugger_at_exit;
59
60 extern int extra_argc;
61 extern char **extra_argv;
62
63 extern int verbose;
64 extern int quiet_mode;
65
66 extern struct emul *debugger_emul;
67 extern struct diskimage *diskimages[];
68
69 static char *diskimage_types[] = DISKIMAGE_TYPES;
70
71
72 static void print_separator(void)
73 {
74 int i = 79;
75 while (i-- > 0)
76 debug("-");
77 debug("\n");
78 }
79
80
81 /*
82 * add_dump_points():
83 *
84 * Take the strings breakpoint_string[] and convert to addresses
85 * (and store them in breakpoint_addr[]).
86 *
87 * TODO: This function should be moved elsewhere.
88 */
89 static void add_dump_points(struct machine *m)
90 {
91 int i;
92 int string_flag;
93 uint64_t dp;
94
95 for (i=0; i<m->n_breakpoints; i++) {
96 string_flag = 0;
97 dp = strtoull(m->breakpoint_string[i], NULL, 0);
98
99 /*
100 * If conversion resulted in 0, then perhaps it is a
101 * symbol:
102 */
103 if (dp == 0) {
104 uint64_t addr;
105 int res = get_symbol_addr(&m->symbol_context,
106 m->breakpoint_string[i], &addr);
107 if (!res) {
108 fprintf(stderr,
109 "ERROR! Breakpoint '%s' could not be"
110 " parsed\n",
111 m->breakpoint_string[i]);
112 } else {
113 dp = addr;
114 string_flag = 1;
115 }
116 }
117
118 /*
119 * TODO: It would be nice if things like symbolname+0x1234
120 * were automatically converted into the correct address.
121 */
122
123 if (m->arch == ARCH_MIPS) {
124 if ((dp >> 32) == 0 && ((dp >> 31) & 1))
125 dp |= 0xffffffff00000000ULL;
126 }
127
128 m->breakpoint_addr[i] = dp;
129
130 debug("breakpoint %i: 0x%llx", i, (long long)dp);
131 if (string_flag)
132 debug(" (%s)", m->breakpoint_string[i]);
133 debug("\n");
134 }
135 }
136
137
138 /*
139 * fix_console():
140 */
141 static void fix_console(void)
142 {
143 console_deinit();
144 }
145
146
147 /*
148 * iso_load_bootblock():
149 *
150 * Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for
151 * "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra).
152 *
153 * TODO: This function uses too many magic offsets and so on; it should be
154 * cleaned up some day.
155 *
156 * Returns 1 on success, 0 on failure.
157 */
158 static int iso_load_bootblock(struct machine *m, struct cpu *cpu,
159 int disk_id, int disk_type, int iso_type, unsigned char *buf,
160 int *n_loadp, char ***load_namesp)
161 {
162 char str[35];
163 int filenr, i, ofs, dirlen, res = 0, res2, iadd = DEBUG_INDENTATION;
164 int found_dir;
165 uint64_t dirofs;
166 uint64_t fileofs, filelen;
167 unsigned char *dirbuf = NULL, *dp;
168 unsigned char *match_entry = NULL;
169 char *p, *filename_orig;
170 char *filename = strdup(cpu->machine->boot_kernel_filename);
171 unsigned char *filebuf = NULL;
172 char *tmpfname = NULL;
173 char **new_array;
174 int tmpfile_handle;
175
176 if (filename == NULL) {
177 fatal("out of memory\n");
178 exit(1);
179 }
180 filename_orig = filename;
181
182 debug("ISO9660 boot:\n");
183 debug_indentation(iadd);
184
185 /* Volume ID: */
186 ofs = iso_type == 3? 48 : 40;
187 memcpy(str, buf + ofs, sizeof(str));
188 str[32] = '\0'; i = 31;
189 while (i >= 0 && str[i]==' ')
190 str[i--] = '\0';
191 if (str[0])
192 debug("\"%s\"", str);
193 else {
194 /* System ID: */
195 ofs = iso_type == 3? 16 : 8;
196 memcpy(str, buf + ofs, sizeof(str));
197 str[32] = '\0'; i = 31;
198 while (i >= 0 && str[i]==' ')
199 str[i--] = '\0';
200 if (str[0])
201 debug("\"%s\"", str);
202 else
203 debug("(no ID)");
204 }
205
206 debug(":%s\n", filename);
207
208
209 /*
210 * Traverse the directory structure to find the kernel.
211 */
212
213 dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86];
214 if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89])
215 fatal("WARNING: Root directory length mismatch?\n");
216
217 dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) +
218 ((uint64_t)buf[0x8f] << 24)) * 2048;
219
220 /* debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs); */
221
222 dirbuf = malloc(dirlen);
223 if (dirbuf == NULL) {
224 fatal("out of memory in iso_load_bootblock()\n");
225 exit(1);
226 }
227
228 res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf,
229 dirlen);
230 if (!res2) {
231 fatal("Couldn't read the disk image. Aborting.\n");
232 goto ret;
233 }
234
235 found_dir = 1; /* Assume root dir */
236 dp = dirbuf; filenr = 1;
237 p = NULL;
238 while (dp < dirbuf + dirlen) {
239 size_t i, nlen = dp[0];
240 int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) +
241 ((uint64_t)dp[5] << 24);
242 int y = dp[6] + (dp[7] << 8);
243 char direntry[65];
244
245 dp += 8;
246
247 /*
248 * As long as there is an \ or / in the filename, then we
249 * have not yet found the directory.
250 */
251 p = strchr(filename, '/');
252 if (p == NULL)
253 p = strchr(filename, '\\');
254
255 /* debug("%i%s: %i, %i, \"", filenr, filenr == found_dir?
256 " [CURRENT]" : "", x, y); */
257 for (i=0; i<nlen && i<sizeof(direntry)-1; i++)
258 if (dp[i]) {
259 direntry[i] = dp[i];
260 /* debug("%c", dp[i]); */
261 } else
262 break;
263 /* debug("\"\n"); */
264 direntry[i] = '\0';
265
266 /* A directory name match? */
267 if (p != NULL && strncasecmp(filename, direntry, nlen) == 0
268 && nlen == (size_t)p - (size_t)filename && found_dir == y) {
269 found_dir = filenr;
270 filename = p+1;
271 dirofs = 2048 * (int64_t)x;
272 }
273
274 dp += nlen;
275
276 /* 16-bit aligned lenght: */
277 if (nlen & 1)
278 dp ++;
279
280 filenr ++;
281 }
282
283 p = strchr(filename, '/');
284 if (p == NULL)
285 p = strchr(filename, '\\');
286
287 if (p != NULL) {
288 char *blah = filename_orig;
289
290 fatal("could not find '%s' in /", filename);
291
292 /* Print the first part of the filename: */
293 while (blah != filename)
294 fatal("%c", *blah++);
295
296 fatal("\n");
297 goto ret;
298 }
299
300 /* debug("dirofs = 0x%llx\n", (long long)dirofs); */
301
302 /* Free the old dirbuf, and allocate a new one: */
303 free(dirbuf);
304 dirbuf = malloc(512);
305 if (dirbuf == NULL) {
306 fatal("out of memory in iso_load_bootblock()\n");
307 exit(1);
308 }
309
310 for (;;) {
311 size_t len, i;
312
313 /* Too close to another sector? Then realign. */
314 if ((dirofs & 2047) + 70 > 2047) {
315 dirofs = (dirofs | 2047) + 1;
316 /* debug("realign dirofs = 0x%llx\n", dirofs); */
317 }
318
319 res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs,
320 dirbuf, 256);
321 if (!res2) {
322 fatal("Couldn't read the disk image. Aborting.\n");
323 goto ret;
324 }
325
326 dp = dirbuf;
327 len = dp[0];
328 if (len < 2)
329 break;
330
331 /*
332 * TODO: Actually parse the directory entry!
333 *
334 * Haha, this must be rewritten.
335 */
336 for (i=32; i<len; i++) {
337 if (i < len - strlen(filename))
338 if (strncasecmp(filename, (char *)dp + i,
339 strlen(filename)) == 0) {
340 /* The filename was found somewhere
341 in the directory entry. */
342 if (match_entry != NULL) {
343 fatal("TODO: I'm too lazy to"
344 " implement a correct "
345 "directory parser right "
346 "now... (BUG)\n");
347 exit(1);
348 }
349 match_entry = malloc(512);
350 if (match_entry == NULL) {
351 fatal("out of memory\n");
352 exit(1);
353 }
354 memcpy(match_entry, dp, 512);
355 break;
356 }
357 }
358
359 dirofs += len;
360 }
361
362 if (match_entry == NULL) {
363 char *blah = filename_orig;
364
365 fatal("could not find '%s' in /", filename);
366
367 /* Print the first part of the filename: */
368 while (blah != filename)
369 fatal("%c", *blah++);
370
371 fatal("\n");
372 goto ret;
373 }
374
375 fileofs = match_entry[2] + (match_entry[3] << 8) +
376 (match_entry[4] << 16) + ((uint64_t)match_entry[5] << 24);
377 filelen = match_entry[10] + (match_entry[11] << 8) +
378 (match_entry[12] << 16) + ((uint64_t)match_entry[13] << 24);
379 fileofs *= 2048;
380
381 /* debug("filelen=%llx fileofs=%llx\n", (long long)filelen,
382 (long long)fileofs); */
383
384 filebuf = malloc(filelen);
385 if (filebuf == NULL) {
386 fatal("could not allocate %lli bytes to read the file"
387 " from the disk image!\n", (long long)filelen);
388 goto ret;
389 }
390
391 tmpfname = strdup("/tmp/gxemul.XXXXXXXXXXXX");
392
393 res2 = diskimage_access(m, disk_id, disk_type, 0, fileofs, filebuf,
394 filelen);
395 if (!res2) {
396 fatal("could not read the file from the disk image!\n");
397 goto ret;
398 }
399
400 tmpfile_handle = mkstemp(tmpfname);
401 if (tmpfile_handle < 0) {
402 fatal("could not create %s\n", tmpfname);
403 exit(1);
404 }
405 write(tmpfile_handle, filebuf, filelen);
406 close(tmpfile_handle);
407
408 debug("extracted %lli bytes into %s\n", (long long)filelen, tmpfname);
409
410 /* Add the temporary filename to the load_namesp array: */
411 (*n_loadp)++;
412 new_array = malloc(sizeof(char *) * (*n_loadp));
413 if (new_array == NULL) {
414 fatal("out of memory\n");
415 exit(1);
416 }
417 memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));
418 *load_namesp = new_array;
419
420 /* This adds a Backspace char in front of the filename; this
421 is a special hack which causes the file to be removed once
422 it has been loaded. */
423 tmpfname = realloc(tmpfname, strlen(tmpfname) + 2);
424 memmove(tmpfname + 1, tmpfname, strlen(tmpfname) + 1);
425 tmpfname[0] = 8;
426
427 (*load_namesp)[*n_loadp - 1] = tmpfname;
428
429 res = 1;
430
431 ret:
432 if (dirbuf != NULL)
433 free(dirbuf);
434
435 if (filebuf != NULL)
436 free(filebuf);
437
438 if (match_entry != NULL)
439 free(match_entry);
440
441 free(filename_orig);
442
443 debug_indentation(-iadd);
444 return res;
445 }
446
447
448 /*
449 * apple_load_bootblock():
450 *
451 * Try to load a kernel from a disk image with an Apple Partition Table.
452 *
453 * TODO: This function uses too many magic offsets and so on; it should be
454 * cleaned up some day. See http://www.awprofessional.com/articles/
455 * article.asp?p=376123&seqNum=3&rl=1 for some info on the Apple
456 * partition format.
457 *
458 * Returns 1 on success, 0 on failure.
459 */
460 static int apple_load_bootblock(struct machine *m, struct cpu *cpu,
461 int disk_id, int disk_type, int *n_loadp, char ***load_namesp)
462 {
463 unsigned char buf[0x8000];
464 int res, partnr, n_partitions = 0, n_hfs_partitions = 0;
465 uint64_t hfs_start, hfs_length;
466
467 res = diskimage_access(m, disk_id, disk_type, 0, 0x0, buf, sizeof(buf));
468 if (!res) {
469 fatal("apple_load_bootblock: couldn't read the disk "
470 "image. Aborting.\n");
471 return 0;
472 }
473
474 partnr = 0;
475 do {
476 int start, length;
477 int ofs = 0x200 * (partnr + 1);
478 if (partnr == 0)
479 n_partitions = buf[ofs + 7];
480 start = ((uint64_t)buf[ofs + 8] << 24) + (buf[ofs + 9] << 16) +
481 (buf[ofs + 10] << 8) + buf[ofs + 11];
482 length = ((uint64_t)buf[ofs+12] << 24) + (buf[ofs + 13] << 16) +
483 (buf[ofs + 14] << 8) + buf[ofs + 15];
484
485 debug("partition %i: '%s', type '%s', start %i, length %i\n",
486 partnr, buf + ofs + 0x10, buf + ofs + 0x30,
487 start, length);
488
489 if (strcmp((char *)buf + ofs + 0x30, "Apple_HFS") == 0) {
490 n_hfs_partitions ++;
491 hfs_start = 512 * start;
492 hfs_length = 512 * length;
493 }
494
495 /* Any more partitions? */
496 partnr ++;
497 } while (partnr < n_partitions);
498
499 if (n_hfs_partitions == 0) {
500 fatal("Error: No HFS partition found! TODO\n");
501 return 0;
502 }
503 if (n_hfs_partitions >= 2) {
504 fatal("Error: Too many HFS partitions found! TODO\n");
505 return 0;
506 }
507
508 return 0;
509 }
510
511
512 /*
513 * load_bootblock():
514 *
515 * For some emulation modes, it is possible to boot from a harddisk image by
516 * loading a bootblock from a specific disk offset into memory, and executing
517 * that, instead of requiring a separate kernel file. It is then up to the
518 * bootblock to load a kernel.
519 *
520 * Returns 1 on success, 0 on failure.
521 */
522 static int load_bootblock(struct machine *m, struct cpu *cpu,
523 int *n_loadp, char ***load_namesp)
524 {
525 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
526 iso_type, retval = 0;
527 unsigned char minibuf[0x20];
528 unsigned char *bootblock_buf;
529 uint64_t bootblock_offset;
530 uint64_t bootblock_loadaddr, bootblock_pc;
531
532 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
533 if (boot_disk_id < 0)
534 return 0;
535
536 switch (m->machine_type) {
537 case MACHINE_PMAX:
538 /*
539 * The first few bytes of a disk contains information about
540 * where the bootblock(s) are located. (These are all 32-bit
541 * little-endian words.)
542 *
543 * Offset 0x10 = load address
544 * 0x14 = initial PC value
545 * 0x18 = nr of 512-byte blocks to read
546 * 0x1c = offset on disk to where the bootblocks
547 * are (in 512-byte units)
548 * 0x20 = nr of blocks to read...
549 * 0x24 = offset...
550 *
551 * nr of blocks to read and offset are repeated until nr of
552 * blocks to read is zero.
553 */
554 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
555 minibuf, sizeof(minibuf));
556
557 bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
558 + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24);
559
560 /* Convert loadaddr to uncached: */
561 if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
562 (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)
563 fatal("\nWARNING! Weird load address 0x%08x.\n\n",
564 (int)bootblock_loadaddr);
565 bootblock_loadaddr &= 0x0fffffffULL;
566 bootblock_loadaddr |= 0xffffffffa0000000ULL;
567
568 bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
569 + (minibuf[0x16] << 16) + ((uint64_t)minibuf[0x17] << 24);
570
571 bootblock_pc &= 0x0fffffffULL;
572 bootblock_pc |= 0xffffffffa0000000ULL;
573 cpu->pc = bootblock_pc;
574
575 debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",
576 (int)bootblock_loadaddr, (int)bootblock_pc);
577
578 readofs = 0x18;
579
580 for (;;) {
581 res = diskimage_access(m, boot_disk_id, boot_disk_type,
582 0, readofs, minibuf, sizeof(minibuf));
583 if (!res) {
584 fatal("Couldn't read the disk image. "
585 "Aborting.\n");
586 return 0;
587 }
588
589 n_blocks = minibuf[0] + (minibuf[1] << 8)
590 + (minibuf[2] << 16) + ((uint64_t)minibuf[3] << 24);
591
592 bootblock_offset = (minibuf[4] + (minibuf[5] << 8) +
593 (minibuf[6]<<16) + ((uint64_t)minibuf[7]<<24)) * 512;
594
595 if (n_blocks < 1)
596 break;
597
598 debug(readofs == 0x18? ": %i" : " + %i", n_blocks);
599
600 if (n_blocks * 512 > 65536)
601 fatal("\nWARNING! Unusually large bootblock "
602 "(%i bytes)\n\n", n_blocks * 512);
603
604 bootblock_buf = malloc(n_blocks * 512);
605 if (bootblock_buf == NULL) {
606 fprintf(stderr, "out of memory in "
607 "load_bootblock()\n");
608 exit(1);
609 }
610
611 res = diskimage_access(m, boot_disk_id, boot_disk_type,
612 0, bootblock_offset, bootblock_buf, n_blocks * 512);
613 if (!res) {
614 fatal("WARNING: could not load bootblocks from"
615 " disk offset 0x%llx\n",
616 (long long)bootblock_offset);
617 }
618
619 store_buf(cpu, bootblock_loadaddr,
620 (char *)bootblock_buf, n_blocks * 512);
621
622 bootblock_loadaddr += 512*n_blocks;
623 free(bootblock_buf);
624 readofs += 8;
625 }
626
627 debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
628 return 1;
629
630 case MACHINE_X86:
631 /* TODO: "El Torito" etc? */
632 if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
633 boot_disk_type))
634 break;
635
636 bootblock_buf = malloc(512);
637 if (bootblock_buf == NULL) {
638 fprintf(stderr, "Out of memory.\n");
639 exit(1);
640 }
641
642 debug("loading PC bootsector from %s id %i\n",
643 diskimage_types[boot_disk_type], boot_disk_id);
644
645 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
646 bootblock_buf, 512);
647 if (!res) {
648 fatal("Couldn't read the disk image. Aborting.\n");
649 return 0;
650 }
651
652 if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)
653 debug("WARNING! The 0x55,0xAA marker is missing! "
654 "Booting anyway.\n");
655 store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);
656 free(bootblock_buf);
657
658 return 1;
659 }
660
661
662 /*
663 * Try reading a kernel manually from the disk. The code here
664 * does not rely on machine-dependent boot blocks etc.
665 */
666 /* ISO9660: (0x800 bytes at 0x8000) */
667 bootblock_buf = malloc(0x800);
668 if (bootblock_buf == NULL) {
669 fprintf(stderr, "Out of memory.\n");
670 exit(1);
671 }
672
673 res = diskimage_access(m, boot_disk_id, boot_disk_type,
674 0, 0x8000, bootblock_buf, 0x800);
675 if (!res) {
676 fatal("Couldn't read the disk image. Aborting.\n");
677 return 0;
678 }
679
680 iso_type = 0;
681 if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)
682 iso_type = 1;
683 if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)
684 iso_type = 2;
685 if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)
686 iso_type = 3;
687
688 if (iso_type != 0) {
689 /* We can't load a kernel if the name
690 isn't specified. */
691 if (cpu->machine->boot_kernel_filename == NULL ||
692 cpu->machine->boot_kernel_filename[0] == '\0')
693 fatal("\nISO9660 filesystem, but no kernel "
694 "specified? (Use the -j option.)\n");
695 else
696 retval = iso_load_bootblock(m, cpu, boot_disk_id,
697 boot_disk_type, iso_type, bootblock_buf,
698 n_loadp, load_namesp);
699 }
700
701 if (retval != 0)
702 goto ret_ok;
703
704 /* Apple parition table: */
705 res = diskimage_access(m, boot_disk_id, boot_disk_type,
706 0, 0x0, bootblock_buf, 0x800);
707 if (!res) {
708 fatal("Couldn't read the disk image. Aborting.\n");
709 return 0;
710 }
711 if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' &&
712 bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') {
713 /* We can't load a kernel if the name
714 isn't specified. */
715 if (cpu->machine->boot_kernel_filename == NULL ||
716 cpu->machine->boot_kernel_filename[0] == '\0')
717 fatal("\nApple partition table, but no kernel "
718 "specified? (Use the -j option.)\n");
719 else
720 retval = apple_load_bootblock(m, cpu, boot_disk_id,
721 boot_disk_type, n_loadp, load_namesp);
722 }
723
724 ret_ok:
725 free(bootblock_buf);
726 return retval;
727 }
728
729
730 /*
731 * emul_new():
732 *
733 * Returns a reasonably initialized struct emul.
734 */
735 struct emul *emul_new(char *name)
736 {
737 struct emul *e;
738 e = malloc(sizeof(struct emul));
739 if (e == NULL) {
740 fprintf(stderr, "out of memory in emul_new()\n");
741 exit(1);
742 }
743
744 memset(e, 0, sizeof(struct emul));
745
746 /* Sane default values: */
747 e->n_machines = 0;
748 e->next_serial_nr = 1;
749
750 if (name != NULL) {
751 e->name = strdup(name);
752 if (e->name == NULL) {
753 fprintf(stderr, "out of memory in emul_new()\n");
754 exit(1);
755 }
756 }
757
758 return e;
759 }
760
761
762 /*
763 * emul_add_machine():
764 *
765 * Calls machine_new(), adds the new machine into the emul struct, and
766 * returns a pointer to the new machine.
767 *
768 * This function should be used instead of manually calling machine_new().
769 */
770 struct machine *emul_add_machine(struct emul *e, char *name)
771 {
772 struct machine *m;
773
774 m = machine_new(name, e);
775 m->serial_nr = (e->next_serial_nr ++);
776
777 e->n_machines ++;
778 e->machines = realloc(e->machines,
779 sizeof(struct machine *) * e->n_machines);
780 if (e->machines == NULL) {
781 fprintf(stderr, "emul_add_machine(): out of memory\n");
782 exit(1);
783 }
784
785 e->machines[e->n_machines - 1] = m;
786 return m;
787 }
788
789
790 /*
791 * add_arc_components():
792 *
793 * This function adds ARCBIOS memory descriptors for the loaded program,
794 * and ARCBIOS components for SCSI devices.
795 */
796 static void add_arc_components(struct machine *m)
797 {
798 struct cpu *cpu = m->cpus[m->bootstrap_cpu];
799 uint64_t start = cpu->pc & 0x1fffffff;
800 uint64_t len = 0xc00000 - start;
801 struct diskimage *d;
802 uint64_t scsicontroller, scsidevice, scsidisk;
803
804 if ((cpu->pc >> 60) != 0xf) {
805 start = cpu->pc & 0xffffffffffULL;
806 len = 0xc00000 - start;
807 }
808
809 len += 1048576 * m->memory_offset_in_mb;
810
811 /*
812 * NOTE/TODO: magic 12MB end of load program area
813 *
814 * Hm. This breaks the old FreeBSD/MIPS snapshots...
815 */
816 #if 0
817 arcbios_add_memory_descriptor(cpu,
818 0x60000 + m->memory_offset_in_mb * 1048576,
819 start-0x60000 - m->memory_offset_in_mb * 1048576,
820 ARCBIOS_MEM_FreeMemory);
821 #endif
822 arcbios_add_memory_descriptor(cpu,
823 start, len, ARCBIOS_MEM_LoadedProgram);
824
825 scsicontroller = arcbios_get_scsicontroller(m);
826 if (scsicontroller == 0)
827 return;
828
829 /* TODO: The device 'name' should defined be somewhere else. */
830
831 d = m->first_diskimage;
832 while (d != NULL) {
833 if (d->type == DISKIMAGE_SCSI) {
834 int a, b, flags = COMPONENT_FLAG_Input;
835 char component_string[100];
836 char *name = "DEC RZ58 (C) DEC2000";
837
838 /* Read-write, or read-only? */
839 if (d->writable)
840 flags |= COMPONENT_FLAG_Output;
841 else
842 flags |= COMPONENT_FLAG_ReadOnly;
843
844 a = COMPONENT_TYPE_DiskController;
845 b = COMPONENT_TYPE_DiskPeripheral;
846
847 if (d->is_a_cdrom) {
848 flags |= COMPONENT_FLAG_Removable;
849 a = COMPONENT_TYPE_CDROMController;
850 b = COMPONENT_TYPE_FloppyDiskPeripheral;
851 name = "NEC CD-ROM CDR-210P 1.0 ";
852 }
853
854 scsidevice = arcbios_addchild_manual(cpu,
855 COMPONENT_CLASS_ControllerClass,
856 a, flags, 1, 2, d->id, 0xffffffff,
857 name, scsicontroller, NULL, 0);
858
859 scsidisk = arcbios_addchild_manual(cpu,
860 COMPONENT_CLASS_PeripheralClass,
861 b, flags, 1, 2, 0, 0xffffffff, NULL,
862 scsidevice, NULL, 0);
863
864 /*
865 * Add device string to component address mappings:
866 * "scsi(0)disk(0)rdisk(0)partition(0)"
867 */
868
869 if (d->is_a_cdrom) {
870 snprintf(component_string,
871 sizeof(component_string),
872 "scsi(0)cdrom(%i)", d->id);
873 arcbios_add_string_to_component(m,
874 component_string, scsidevice);
875
876 snprintf(component_string,
877 sizeof(component_string),
878 "scsi(0)cdrom(%i)fdisk(0)", d->id);
879 arcbios_add_string_to_component(m,
880 component_string, scsidisk);
881 } else {
882 snprintf(component_string,
883 sizeof(component_string),
884 "scsi(0)disk(%i)", d->id);
885 arcbios_add_string_to_component(m,
886 component_string, scsidevice);
887
888 snprintf(component_string,
889 sizeof(component_string),
890 "scsi(0)disk(%i)rdisk(0)", d->id);
891 arcbios_add_string_to_component(m,
892 component_string, scsidisk);
893 }
894 }
895
896 d = d->next;
897 }
898 }
899
900
901 /*
902 * emul_machine_setup():
903 *
904 * o) Initialize the hardware (RAM, devices, CPUs, ...) which
905 * will be emulated in this machine.
906 *
907 * o) Load ROM code and/or other programs into emulated memory.
908 *
909 * o) Special hacks needed after programs have been loaded.
910 */
911 void emul_machine_setup(struct machine *m, int n_load, char **load_names,
912 int n_devices, char **device_names)
913 {
914 struct cpu *cpu;
915 int i, iadd = DEBUG_INDENTATION;
916 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
917 int byte_order;
918
919 debug("machine \"%s\":\n", m->name);
920 debug_indentation(iadd);
921
922 /* For userland-only, this decides which ARCH/cpu_name to use: */
923 if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
924 useremul_name_to_useremul(NULL, m->userland_emul,
925 &m->arch, &m->machine_name, &m->cpu_name);
926 if (m->arch == ARCH_NOARCH) {
927 printf("Unsupported userland emulation mode.\n");
928 exit(1);
929 }
930 }
931
932 if (m->machine_type == MACHINE_NONE) {
933 fatal("No machine type specified?\n");
934 exit(1);
935 }
936
937 m->cpu_family = cpu_family_ptr_by_number(m->arch);
938
939 if (m->arch == ARCH_ALPHA)
940 m->arch_pagesize = 8192;
941
942 machine_memsize_fix(m);
943
944 /*
945 * Create the system's memory:
946 *
947 * (Don't print the amount for userland-only emulation; the
948 * size doesn't matter.)
949 */
950 if (m->machine_type != MACHINE_USERLAND)
951 debug("memory: %i MB", m->physical_ram_in_mb);
952 memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
953 if (m->memory_offset_in_mb > 0) {
954 /*
955 * A special hack is used for some SGI models,
956 * where memory is offset by 128MB to leave room for
957 * EISA space and other things.
958 */
959 debug(" (offset by %iMB)", m->memory_offset_in_mb);
960 memory_amount += 1048576 * m->memory_offset_in_mb;
961 }
962 m->memory = memory_new(memory_amount, m->arch);
963 if (m->machine_type != MACHINE_USERLAND)
964 debug("\n");
965
966 /* Create CPUs: */
967 if (m->cpu_name == NULL)
968 machine_default_cputype(m);
969 if (m->ncpus == 0) {
970 /* TODO: This should be moved elsewhere... */
971 if (m->machine_type == MACHINE_BEBOX)
972 m->ncpus = 2;
973 else if (m->machine_type == MACHINE_ARC &&
974 m->machine_subtype == MACHINE_ARC_NEC_R96)
975 m->ncpus = 2;
976 else if (m->machine_type == MACHINE_ARC &&
977 m->machine_subtype == MACHINE_ARC_NEC_R98)
978 m->ncpus = 4;
979 else
980 m->ncpus = 1;
981 }
982 m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);
983 if (m->cpus == NULL) {
984 fprintf(stderr, "out of memory\n");
985 exit(1);
986 }
987 memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
988
989 debug("cpu0");
990 if (m->ncpus > 1)
991 debug(" .. cpu%i", m->ncpus - 1);
992 debug(": ");
993 for (i=0; i<m->ncpus; i++) {
994 m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
995 if (m->cpus[i] == NULL) {
996 fprintf(stderr, "Unable to create CPU object. "
997 "Aborting.");
998 exit(1);
999 }
1000 }
1001 debug("\n");
1002
1003 #if 0
1004 /* Special case: The Playstation Portable has an additional CPU: */
1005 if (m->machine_type == MACHINE_PSP) {
1006 debug("cpu%i: ", m->ncpus);
1007 m->cpus[m->ncpus] = cpu_new(m->memory, m,
1008 0 /* use 0 here to show info with debug() */,
1009 "Allegrex" /* TODO */);
1010 debug("\n");
1011 m->ncpus ++;
1012 }
1013 #endif
1014
1015 if (m->use_random_bootstrap_cpu)
1016 m->bootstrap_cpu = random() % m->ncpus;
1017 else
1018 m->bootstrap_cpu = 0;
1019
1020 cpu = m->cpus[m->bootstrap_cpu];
1021
1022 /* Set cpu->useremul_syscall, and use userland_memory_rw: */
1023 if (m->userland_emul != NULL) {
1024 useremul_name_to_useremul(cpu,
1025 m->userland_emul, NULL, NULL, NULL);
1026
1027 switch (m->arch) {
1028 #ifdef ENABLE_ALPHA
1029 case ARCH_ALPHA:
1030 cpu->memory_rw = alpha_userland_memory_rw;
1031 break;
1032 #endif
1033 default:cpu->memory_rw = userland_memory_rw;
1034 }
1035 }
1036
1037 if (m->use_x11)
1038 x11_init(m);
1039
1040 /* Fill memory with random bytes: */
1041 if (m->random_mem_contents) {
1042 for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
1043 unsigned char data[256];
1044 unsigned int j;
1045 for (j=0; j<sizeof(data); j++)
1046 data[j] = random() & 255;
1047 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
1048 MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
1049 }
1050 }
1051
1052 if (m->userland_emul != NULL) {
1053 /*
1054 * For userland-only emulation, no machine emulation
1055 * is needed.
1056 */
1057 } else {
1058 for (i=0; i<n_devices; i++)
1059 device_add(m, device_names[i]);
1060
1061 machine_setup(m);
1062 }
1063
1064 diskimage_dump_info(m);
1065 console_debug_dump(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_PMAX &&
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 /* Special hack for ARC/SGI emulation: */
1352 if ((m->machine_type == MACHINE_ARC ||
1353 m->machine_type == MACHINE_SGI) && m->prom_emulation)
1354 add_arc_components(m);
1355
1356 debug("starting cpu%i at ", m->bootstrap_cpu);
1357 switch (m->arch) {
1358
1359 case ARCH_ARM:
1360 /* ARM cpus aren't 64-bit: */
1361 debug("0x%08x", (int)entrypoint);
1362 break;
1363
1364 case ARCH_AVR:
1365 /* Atmel AVR uses a 16-bit or 22-bit program counter: */
1366 debug("0x%04x", (int)entrypoint);
1367 break;
1368
1369 case ARCH_MIPS:
1370 if (cpu->is_32bit) {
1371 debug("0x%08x", (int)m->cpus[
1372 m->bootstrap_cpu]->pc);
1373 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1374 debug(" (gp=0x%08x)", (int)m->cpus[
1375 m->bootstrap_cpu]->cd.mips.gpr[
1376 MIPS_GPR_GP]);
1377 } else {
1378 debug("0x%016llx", (long long)m->cpus[
1379 m->bootstrap_cpu]->pc);
1380 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1381 debug(" (gp=0x%016llx)", (long long)
1382 cpu->cd.mips.gpr[MIPS_GPR_GP]);
1383 }
1384 break;
1385
1386 case ARCH_PPC:
1387 if (cpu->cd.ppc.bits == 32)
1388 debug("0x%08x", (int)entrypoint);
1389 else
1390 debug("0x%016llx", (long long)entrypoint);
1391 break;
1392
1393 case ARCH_X86:
1394 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1395 (long long)cpu->pc);
1396 break;
1397
1398 default:
1399 if (cpu->is_32bit)
1400 debug("0x%08x", (int)cpu->pc);
1401 else
1402 debug("0x%016llx", (long long)cpu->pc);
1403 }
1404 debug("\n");
1405
1406 debug_indentation(-iadd);
1407 }
1408
1409
1410 /*
1411 * emul_dumpinfo():
1412 *
1413 * Dump info about all machines in an emul.
1414 */
1415 void emul_dumpinfo(struct emul *e)
1416 {
1417 int j, nm, iadd = DEBUG_INDENTATION;
1418
1419 if (e->net != NULL)
1420 net_dumpinfo(e->net);
1421
1422 nm = e->n_machines;
1423 for (j=0; j<nm; j++) {
1424 debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
1425 debug_indentation(iadd);
1426 machine_dumpinfo(e->machines[j]);
1427 debug_indentation(-iadd);
1428 }
1429 }
1430
1431
1432 /*
1433 * emul_simple_init():
1434 *
1435 * For a normal setup:
1436 *
1437 * o) Initialize a network.
1438 * o) Initialize one machine.
1439 *
1440 * For a userland-only setup:
1441 *
1442 * o) Initialize a "pseudo"-machine.
1443 */
1444 void emul_simple_init(struct emul *emul)
1445 {
1446 int iadd = DEBUG_INDENTATION;
1447 struct machine *m;
1448
1449 if (emul->n_machines != 1) {
1450 fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
1451 exit(1);
1452 }
1453
1454 m = emul->machines[0];
1455
1456 if (m->userland_emul == NULL) {
1457 debug("Simple setup...\n");
1458 debug_indentation(iadd);
1459
1460 /* Create a simple network: */
1461 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1462 "10.0.0.0", 8, NULL, 0, 0);
1463 } else {
1464 /* Userland pseudo-machine: */
1465 debug("Syscall emulation (userland-only) setup...\n");
1466 debug_indentation(iadd);
1467 }
1468
1469 /* Create the machine: */
1470 emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
1471
1472 debug_indentation(-iadd);
1473 }
1474
1475
1476 /*
1477 * emul_create_from_configfile():
1478 *
1479 * Create an emul struct by reading settings from a configuration file.
1480 */
1481 struct emul *emul_create_from_configfile(char *fname)
1482 {
1483 int iadd = DEBUG_INDENTATION;
1484 struct emul *e = emul_new(fname);
1485
1486 debug("Creating emulation from configfile \"%s\":\n", fname);
1487 debug_indentation(iadd);
1488
1489 emul_parse_config(e, fname);
1490
1491 debug_indentation(-iadd);
1492 return e;
1493 }
1494
1495
1496 /*
1497 * emul_run():
1498 *
1499 * o) Set up things needed before running emulations.
1500 *
1501 * o) Run emulations (one or more, in parallel).
1502 *
1503 * o) De-initialize things.
1504 */
1505 void emul_run(struct emul **emuls, int n_emuls)
1506 {
1507 struct emul *e;
1508 int i = 0, j, go = 1, n, anything;
1509
1510 if (n_emuls < 1) {
1511 fprintf(stderr, "emul_run(): no thing to do\n");
1512 return;
1513 }
1514
1515 atexit(fix_console);
1516
1517 /* Initialize the interactive debugger: */
1518 debugger_init(emuls, n_emuls);
1519
1520 /* Run any additional debugger commands before starting: */
1521 for (i=0; i<n_emuls; i++) {
1522 struct emul *emul = emuls[i];
1523 if (emul->n_debugger_cmds > 0) {
1524 int j;
1525 if (i == 0)
1526 print_separator();
1527 for (j = 0; j < emul->n_debugger_cmds; j ++) {
1528 debug("> %s\n", emul->debugger_cmds[j]);
1529 debugger_execute_cmd(emul->debugger_cmds[j],
1530 strlen(emul->debugger_cmds[j]));
1531 }
1532 }
1533 }
1534
1535 print_separator();
1536 debug("\n");
1537
1538
1539 /*
1540 * console_init_main() makes sure that the terminal is in a
1541 * reasonable state.
1542 *
1543 * The SIGINT handler is for CTRL-C (enter the interactive debugger).
1544 *
1545 * The SIGCONT handler is invoked whenever the user presses CTRL-Z
1546 * (or sends SIGSTOP) and then continues. It makes sure that the
1547 * terminal is in an expected state.
1548 */
1549 console_init_main(emuls[0]); /* TODO: what is a good argument? */
1550 signal(SIGINT, debugger_activate);
1551 signal(SIGCONT, console_sigcont);
1552
1553 /* Not in verbose mode? Then set quiet_mode. */
1554 if (!verbose)
1555 quiet_mode = 1;
1556
1557 /* Initialize all CPUs in all machines in all emulations: */
1558 for (i=0; i<n_emuls; i++) {
1559 e = emuls[i];
1560 if (e == NULL)
1561 continue;
1562 for (j=0; j<e->n_machines; j++)
1563 cpu_run_init(e->machines[j]);
1564 }
1565
1566 /* TODO: Generalize: */
1567 if (emuls[0]->machines[0]->show_trace_tree)
1568 cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1569 emuls[0]->machines[0]->cpus[0]->pc);
1570
1571 /*
1572 * MAIN LOOP:
1573 *
1574 * Run all emulations in parallel, running each machine in
1575 * each emulation.
1576 */
1577 while (go) {
1578 go = 0;
1579
1580 x11_check_event(emuls, n_emuls);
1581
1582 for (i=0; i<n_emuls; i++) {
1583 e = emuls[i];
1584 if (e == NULL)
1585 continue;
1586
1587 for (j=0; j<e->n_machines; j++) {
1588 if (e->machines[j]->gdb.port > 0)
1589 debugger_gdb_check_incoming(
1590 e->machines[j]);
1591
1592 /* TODO: cpu_run() is a strange name, since
1593 there can be multiple cpus in a machine */
1594 anything = cpu_run(e, e->machines[j]);
1595 if (anything)
1596 go = 1;
1597 }
1598 }
1599 }
1600
1601 /* Deinitialize all CPUs in all machines in all emulations: */
1602 for (i=0; i<n_emuls; i++) {
1603 e = emuls[i];
1604 if (e == NULL)
1605 continue;
1606 for (j=0; j<e->n_machines; j++)
1607 cpu_run_deinit(e->machines[j]);
1608 }
1609
1610 /* force_debugger_at_exit flag set? Then enter the debugger: */
1611 if (force_debugger_at_exit) {
1612 quiet_mode = 0;
1613 debugger_reset();
1614 debugger();
1615 }
1616
1617 /* Any machine using X11? Then we should wait before exiting: */
1618 n = 0;
1619 for (i=0; i<n_emuls; i++)
1620 for (j=0; j<emuls[i]->n_machines; j++)
1621 if (emuls[i]->machines[j]->use_x11)
1622 n++;
1623 if (n > 0) {
1624 printf("Press enter to quit.\n");
1625 while (!console_charavail(MAIN_CONSOLE)) {
1626 x11_check_event(emuls, n_emuls);
1627 usleep(1);
1628 }
1629 console_readchar(MAIN_CONSOLE);
1630 }
1631
1632 console_deinit();
1633 }
1634

  ViewVC Help
Powered by ViewVC 1.1.26