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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26