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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26