/[gxemul]/upstream/0.3.6/src/emul.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.6/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26