/[gxemul]/upstream/0.3.8/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

Annotation of /upstream/0.3.8/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26