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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26