/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 21 - (hide annotations)
Mon Oct 8 16:19:28 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 40733 byte(s)
0.3.7
1 dpavlin 2 /*
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 dpavlin 20 * $Id: emul.c,v 1.238 2005/11/19 18:53:06 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 2 /*
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 dpavlin 20 if (m->arch == ARCH_MIPS) {
116     if ((dp >> 32) == 0 && ((dp >> 31) & 1))
117     dp |= 0xffffffff00000000ULL;
118     }
119    
120 dpavlin 2 m->breakpoint_addr[i] = dp;
121    
122 dpavlin 20 debug("breakpoint %i: 0x%llx", i, (long long)dp);
123 dpavlin 2 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 dpavlin 6 * 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 dpavlin 14 * 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 dpavlin 2 * 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 dpavlin 6 *
512     * Returns 1 on success, 0 on failure.
513 dpavlin 2 */
514 dpavlin 6 static int load_bootblock(struct machine *m, struct cpu *cpu,
515     int *n_loadp, char ***load_namesp)
516 dpavlin 2 {
517 dpavlin 6 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
518     iso_type, retval = 0;
519 dpavlin 2 unsigned char minibuf[0x20];
520     unsigned char *bootblock_buf;
521     uint64_t bootblock_offset;
522     uint64_t bootblock_loadaddr, bootblock_pc;
523    
524 dpavlin 6 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
525 dpavlin 2 if (boot_disk_id < 0)
526 dpavlin 6 return 0;
527 dpavlin 2
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 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
547 dpavlin 2 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 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type,
574     0, readofs, minibuf, sizeof(minibuf));
575 dpavlin 2 if (!res) {
576 dpavlin 6 fatal("Couldn't read the disk image. "
577     "Aborting.\n");
578     return 0;
579 dpavlin 2 }
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 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type,
604     0, bootblock_offset, bootblock_buf, n_blocks * 512);
605 dpavlin 2 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 dpavlin 6 return 1;
621 dpavlin 4
622     case MACHINE_X86:
623 dpavlin 6 /* TODO: "El Torito" etc? */
624     if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
625     boot_disk_type))
626     break;
627 dpavlin 4
628     bootblock_buf = malloc(512);
629     if (bootblock_buf == NULL) {
630     fprintf(stderr, "Out of memory.\n");
631     exit(1);
632     }
633    
634 dpavlin 6 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 dpavlin 4 bootblock_buf, 512);
639     if (!res) {
640 dpavlin 6 fatal("Couldn't read the disk image. Aborting.\n");
641     return 0;
642 dpavlin 4 }
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 dpavlin 6 return 1;
651     }
652    
653    
654     /*
655     * Try reading a kernel manually from the disk. The code here
656 dpavlin 18 * does not rely on machine-dependent boot blocks etc.
657 dpavlin 6 */
658     /* ISO9660: (0x800 bytes at 0x8000) */
659     bootblock_buf = malloc(0x800);
660     if (bootblock_buf == NULL) {
661     fprintf(stderr, "Out of memory.\n");
662 dpavlin 2 exit(1);
663     }
664 dpavlin 6
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 dpavlin 14 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 dpavlin 6 free(bootblock_buf);
718     return retval;
719 dpavlin 2 }
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 dpavlin 10 e->next_serial_nr = 1;
741 dpavlin 2
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 dpavlin 12 /*
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 dpavlin 2 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 dpavlin 12 #endif
814 dpavlin 2 arcbios_add_memory_descriptor(cpu,
815     start, len, ARCBIOS_MEM_LoadedProgram);
816    
817 dpavlin 6 scsicontroller = arcbios_get_scsicontroller(m);
818 dpavlin 2 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 dpavlin 6 arcbios_add_string_to_component(m,
866 dpavlin 2 component_string, scsidevice);
867    
868     snprintf(component_string,
869     sizeof(component_string),
870     "scsi(0)cdrom(%i)fdisk(0)", d->id);
871 dpavlin 6 arcbios_add_string_to_component(m,
872 dpavlin 2 component_string, scsidisk);
873     } else {
874     snprintf(component_string,
875     sizeof(component_string),
876     "scsi(0)disk(%i)", d->id);
877 dpavlin 6 arcbios_add_string_to_component(m,
878 dpavlin 2 component_string, scsidevice);
879    
880     snprintf(component_string,
881     sizeof(component_string),
882     "scsi(0)disk(%i)rdisk(0)", d->id);
883 dpavlin 6 arcbios_add_string_to_component(m,
884 dpavlin 2 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 dpavlin 6 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
910 dpavlin 2 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 dpavlin 12 if (m->arch == ARCH_ALPHA)
935     m->arch_pagesize = 8192;
936    
937 dpavlin 10 if (m->arch != ARCH_MIPS)
938     m->bintrans_enable = 0;
939    
940 dpavlin 2 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 dpavlin 12 m->memory = memory_new(memory_amount, m->arch);
961 dpavlin 2 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 dpavlin 10 #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 dpavlin 2 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 dpavlin 12
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 dpavlin 2 }
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 dpavlin 6 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
1049     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
1050 dpavlin 2 }
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 dpavlin 6 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 dpavlin 2 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 dpavlin 6 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 dpavlin 10 * gzipped files are automagically gunzipped:
1097     * NOTE/TODO: This isn't secure. system() is used.
1098 dpavlin 6 */
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 dpavlin 10 size_t zzlen = strlen(name_to_load)*2 + 100;
1106     char *zz = malloc(zzlen);
1107 dpavlin 6 debug("gunziping %s\n", name_to_load);
1108 dpavlin 10 /*
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 dpavlin 6 free(zz);
1135     }
1136     fclose(tmp_f);
1137     }
1138    
1139 dpavlin 10 /*
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 dpavlin 6 /* 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 dpavlin 2 byte_order = NO_BYTE_ORDER_OVERRIDE;
1196    
1197 dpavlin 6 /*
1198     * Load the file: :-)
1199     */
1200     file_load(m, m->memory, name_to_load, &entrypoint,
1201 dpavlin 2 m->arch, &gp, &byte_order, &toc);
1202    
1203 dpavlin 6 if (remove_after_load) {
1204     debug("removing %s\n", name_to_load);
1205     unlink(name_to_load);
1206     }
1207    
1208 dpavlin 2 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
1209     cpu->byte_order = byte_order;
1210    
1211     cpu->pc = entrypoint;
1212    
1213     switch (m->arch) {
1214 dpavlin 14
1215     case ARCH_ALPHA:
1216 dpavlin 18 /* For position-independent code: */
1217 dpavlin 14 cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
1218     break;
1219    
1220     case ARCH_ARM:
1221 dpavlin 20 if (cpu->pc & 3) {
1222     fatal("ARM: lowest bits of pc set: TODO\n");
1223     exit(1);
1224     }
1225 dpavlin 14 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 dpavlin 2 case ARCH_MIPS:
1249 dpavlin 20 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
1250 dpavlin 2 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 dpavlin 4
1260 dpavlin 2 case ARCH_PPC:
1261 dpavlin 6 /* See http://www.linuxbase.org/spec/ELF/ppc64/
1262     spec/x458.html for more info. */
1263 dpavlin 2 cpu->cd.ppc.gpr[2] = toc;
1264 dpavlin 6 /* TODO */
1265 dpavlin 14 if (cpu->cd.ppc.bits == 32)
1266     cpu->pc &= 0xffffffffULL;
1267 dpavlin 2 break;
1268 dpavlin 4
1269 dpavlin 14 case ARCH_SH:
1270     if (cpu->cd.sh.bits == 32)
1271     cpu->pc &= 0xffffffffULL;
1272     cpu->pc &= ~1;
1273 dpavlin 12 break;
1274    
1275 dpavlin 2 case ARCH_SPARC:
1276     break;
1277 dpavlin 4
1278     case ARCH_X86:
1279     /*
1280 dpavlin 6 * NOTE: The toc field is used to indicate an ELF32
1281     * or ELF64 load.
1282 dpavlin 4 */
1283 dpavlin 6 switch (toc) {
1284     case 0: /* 16-bit? TODO */
1285 dpavlin 4 cpu->pc &= 0xffffffffULL;
1286 dpavlin 6 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 dpavlin 2 break;
1295 dpavlin 4
1296 dpavlin 2 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 dpavlin 12 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
1348 dpavlin 2
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 dpavlin 20
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 dpavlin 2 debug("starting cpu%i at ", m->bootstrap_cpu);
1370     switch (m->arch) {
1371 dpavlin 14
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 dpavlin 2 case ARCH_MIPS:
1383 dpavlin 12 if (cpu->is_32bit) {
1384 dpavlin 2 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 dpavlin 14
1399 dpavlin 2 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 dpavlin 14
1406 dpavlin 4 case ARCH_X86:
1407 dpavlin 6 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1408     (long long)cpu->pc);
1409 dpavlin 4 break;
1410 dpavlin 14
1411 dpavlin 2 default:
1412 dpavlin 4 debug("0x%016llx", (long long)cpu->pc);
1413 dpavlin 2 }
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 dpavlin 10 /* Create a simple network: */
1471 dpavlin 2 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1472 dpavlin 10 "10.0.0.0", 8, NULL, 0, 0);
1473 dpavlin 2 } 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 dpavlin 12 cpu_run_init(e->machines[j]);
1580 dpavlin 2 }
1581    
1582 dpavlin 12 /* 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 dpavlin 2 /*
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 dpavlin 12 cpu_run_deinit(e->machines[j]);
1620 dpavlin 2 }
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