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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 41747 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26