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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26