/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (12 years ago) by dpavlin
File MIME type: text/plain
File size: 41779 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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 30 * $Id: emul.c,v 1.260 2006/07/26 23:21:47 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 dpavlin 30 if (cpu->cd.sh.cpu_type.bits == 32)
1275 dpavlin 14 cpu->pc &= 0xffffffffULL;
1276     cpu->pc &= ~1;
1277 dpavlin 12 break;
1278    
1279 dpavlin 2 case ARCH_SPARC:
1280     break;
1281 dpavlin 4
1282 dpavlin 28 case ARCH_TRANSPUTER:
1283     cpu->pc &= 0xffffffffULL;
1284     break;
1285    
1286 dpavlin 4 case ARCH_X86:
1287     /*
1288 dpavlin 6 * NOTE: The toc field is used to indicate an ELF32
1289     * or ELF64 load.
1290 dpavlin 4 */
1291 dpavlin 6 switch (toc) {
1292     case 0: /* 16-bit? TODO */
1293 dpavlin 4 cpu->pc &= 0xffffffffULL;
1294 dpavlin 6 break;
1295     case 1: /* 32-bit. */
1296     cpu->pc &= 0xffffffffULL;
1297     break;
1298     case 2: /* 64-bit: TODO */
1299     fatal("64-bit x86 load. TODO\n");
1300     exit(1);
1301     }
1302 dpavlin 2 break;
1303 dpavlin 4
1304 dpavlin 2 default:
1305     fatal("emul_machine_setup(): Internal error: "
1306     "Unimplemented arch %i\n", m->arch);
1307     exit(1);
1308     }
1309    
1310     /*
1311     * For userland emulation, the remaining items
1312     * on the command line will be passed as parameters
1313     * to the emulated program, and will not be treated
1314     * as filenames to load into the emulator.
1315     * The program's name will be in load_names[0], and the
1316     * rest of the parameters in load_names[1] and up.
1317     */
1318     if (m->userland_emul != NULL)
1319     break;
1320    
1321     n_load --;
1322     load_names ++;
1323     }
1324    
1325     if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
1326     cpu->byte_order = m->byte_order_override;
1327    
1328     /* Same byte order and entrypoint for all CPUs: */
1329     for (i=0; i<m->ncpus; i++)
1330     if (i != m->bootstrap_cpu) {
1331     m->cpus[i]->byte_order = cpu->byte_order;
1332     m->cpus[i]->pc = cpu->pc;
1333     }
1334    
1335     if (m->userland_emul != NULL)
1336     useremul_setup(cpu, n_load, load_names);
1337    
1338     /* Startup the bootstrap CPU: */
1339 dpavlin 30 cpu->running = 1;
1340 dpavlin 2
1341     /* ... or pause all CPUs, if start_paused is set: */
1342     if (m->start_paused) {
1343     for (i=0; i<m->ncpus; i++)
1344     m->cpus[i]->running = 0;
1345     }
1346    
1347     /* Add PC dump points: */
1348     add_dump_points(m);
1349    
1350     /* TODO: This is MIPS-specific! */
1351 dpavlin 22 if (m->machine_type == MACHINE_PMAX &&
1352 dpavlin 2 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1353     add_symbol_name(&m->symbol_context,
1354 dpavlin 12 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
1355 dpavlin 2
1356     symbol_recalc_sizes(&m->symbol_context);
1357    
1358     /* Special hack for ARC/SGI emulation: */
1359     if ((m->machine_type == MACHINE_ARC ||
1360     m->machine_type == MACHINE_SGI) && m->prom_emulation)
1361     add_arc_components(m);
1362    
1363     debug("starting cpu%i at ", m->bootstrap_cpu);
1364     switch (m->arch) {
1365 dpavlin 14
1366     case ARCH_ARM:
1367     /* ARM cpus aren't 64-bit: */
1368     debug("0x%08x", (int)entrypoint);
1369     break;
1370    
1371     case ARCH_AVR:
1372     /* Atmel AVR uses a 16-bit or 22-bit program counter: */
1373     debug("0x%04x", (int)entrypoint);
1374     break;
1375    
1376 dpavlin 2 case ARCH_MIPS:
1377 dpavlin 12 if (cpu->is_32bit) {
1378 dpavlin 2 debug("0x%08x", (int)m->cpus[
1379     m->bootstrap_cpu]->pc);
1380     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1381     debug(" (gp=0x%08x)", (int)m->cpus[
1382     m->bootstrap_cpu]->cd.mips.gpr[
1383     MIPS_GPR_GP]);
1384     } else {
1385     debug("0x%016llx", (long long)m->cpus[
1386     m->bootstrap_cpu]->pc);
1387     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1388     debug(" (gp=0x%016llx)", (long long)
1389     cpu->cd.mips.gpr[MIPS_GPR_GP]);
1390     }
1391     break;
1392 dpavlin 14
1393 dpavlin 2 case ARCH_PPC:
1394     if (cpu->cd.ppc.bits == 32)
1395     debug("0x%08x", (int)entrypoint);
1396     else
1397     debug("0x%016llx", (long long)entrypoint);
1398     break;
1399 dpavlin 14
1400 dpavlin 4 case ARCH_X86:
1401 dpavlin 6 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1402     (long long)cpu->pc);
1403 dpavlin 4 break;
1404 dpavlin 14
1405 dpavlin 2 default:
1406 dpavlin 22 if (cpu->is_32bit)
1407     debug("0x%08x", (int)cpu->pc);
1408     else
1409     debug("0x%016llx", (long long)cpu->pc);
1410 dpavlin 2 }
1411     debug("\n");
1412    
1413     debug_indentation(-iadd);
1414     }
1415    
1416    
1417     /*
1418     * emul_dumpinfo():
1419     *
1420     * Dump info about all machines in an emul.
1421     */
1422     void emul_dumpinfo(struct emul *e)
1423     {
1424 dpavlin 22 int j, nm, iadd = DEBUG_INDENTATION;
1425 dpavlin 2
1426     if (e->net != NULL)
1427     net_dumpinfo(e->net);
1428    
1429     nm = e->n_machines;
1430     for (j=0; j<nm; j++) {
1431     debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
1432     debug_indentation(iadd);
1433     machine_dumpinfo(e->machines[j]);
1434     debug_indentation(-iadd);
1435     }
1436     }
1437    
1438    
1439     /*
1440     * emul_simple_init():
1441     *
1442     * For a normal setup:
1443     *
1444     * o) Initialize a network.
1445     * o) Initialize one machine.
1446     *
1447     * For a userland-only setup:
1448     *
1449     * o) Initialize a "pseudo"-machine.
1450     */
1451     void emul_simple_init(struct emul *emul)
1452     {
1453 dpavlin 22 int iadd = DEBUG_INDENTATION;
1454 dpavlin 2 struct machine *m;
1455    
1456     if (emul->n_machines != 1) {
1457     fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
1458     exit(1);
1459     }
1460    
1461     m = emul->machines[0];
1462    
1463     if (m->userland_emul == NULL) {
1464     debug("Simple setup...\n");
1465     debug_indentation(iadd);
1466    
1467 dpavlin 10 /* Create a simple network: */
1468 dpavlin 2 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1469 dpavlin 10 "10.0.0.0", 8, NULL, 0, 0);
1470 dpavlin 2 } else {
1471     /* Userland pseudo-machine: */
1472     debug("Syscall emulation (userland-only) setup...\n");
1473     debug_indentation(iadd);
1474     }
1475    
1476     /* Create the machine: */
1477     emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
1478    
1479     debug_indentation(-iadd);
1480     }
1481    
1482    
1483     /*
1484     * emul_create_from_configfile():
1485     *
1486     * Create an emul struct by reading settings from a configuration file.
1487     */
1488     struct emul *emul_create_from_configfile(char *fname)
1489     {
1490 dpavlin 22 int iadd = DEBUG_INDENTATION;
1491 dpavlin 2 struct emul *e = emul_new(fname);
1492    
1493     debug("Creating emulation from configfile \"%s\":\n", fname);
1494     debug_indentation(iadd);
1495    
1496 dpavlin 24 emul_parse_config(e, fname);
1497 dpavlin 2
1498     debug_indentation(-iadd);
1499     return e;
1500     }
1501    
1502    
1503     /*
1504     * emul_run():
1505     *
1506     * o) Set up things needed before running emulations.
1507     *
1508     * o) Run emulations (one or more, in parallel).
1509     *
1510     * o) De-initialize things.
1511     */
1512     void emul_run(struct emul **emuls, int n_emuls)
1513     {
1514     struct emul *e;
1515     int i = 0, j, go = 1, n, anything;
1516    
1517     if (n_emuls < 1) {
1518     fprintf(stderr, "emul_run(): no thing to do\n");
1519     return;
1520     }
1521    
1522     atexit(fix_console);
1523    
1524     /* Initialize the interactive debugger: */
1525     debugger_init(emuls, n_emuls);
1526    
1527 dpavlin 22 /* Run any additional debugger commands before starting: */
1528     for (i=0; i<n_emuls; i++) {
1529     struct emul *emul = emuls[i];
1530     if (emul->n_debugger_cmds > 0) {
1531     int j;
1532     if (i == 0)
1533     print_separator();
1534     for (j = 0; j < emul->n_debugger_cmds; j ++) {
1535     debug("> %s\n", emul->debugger_cmds[j]);
1536     debugger_execute_cmd(emul->debugger_cmds[j],
1537     strlen(emul->debugger_cmds[j]));
1538     }
1539     }
1540     }
1541    
1542     print_separator();
1543     debug("\n");
1544    
1545    
1546 dpavlin 2 /*
1547     * console_init_main() makes sure that the terminal is in a
1548     * reasonable state.
1549     *
1550     * The SIGINT handler is for CTRL-C (enter the interactive debugger).
1551     *
1552     * The SIGCONT handler is invoked whenever the user presses CTRL-Z
1553     * (or sends SIGSTOP) and then continues. It makes sure that the
1554     * terminal is in an expected state.
1555     */
1556     console_init_main(emuls[0]); /* TODO: what is a good argument? */
1557     signal(SIGINT, debugger_activate);
1558     signal(SIGCONT, console_sigcont);
1559    
1560     /* Not in verbose mode? Then set quiet_mode. */
1561     if (!verbose)
1562     quiet_mode = 1;
1563    
1564     /* Initialize all CPUs in all machines in all emulations: */
1565     for (i=0; i<n_emuls; i++) {
1566     e = emuls[i];
1567     if (e == NULL)
1568     continue;
1569     for (j=0; j<e->n_machines; j++)
1570 dpavlin 12 cpu_run_init(e->machines[j]);
1571 dpavlin 2 }
1572    
1573 dpavlin 12 /* TODO: Generalize: */
1574     if (emuls[0]->machines[0]->show_trace_tree)
1575     cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1576     emuls[0]->machines[0]->cpus[0]->pc);
1577    
1578 dpavlin 2 /*
1579     * MAIN LOOP:
1580     *
1581     * Run all emulations in parallel, running each machine in
1582     * each emulation.
1583     */
1584     while (go) {
1585     go = 0;
1586    
1587 dpavlin 26 /* Flush X11 and serial console output every now and then: */
1588 dpavlin 28 if (emuls[0]->machines[0]->ninstrs >
1589     emuls[0]->machines[0]->ninstrs_flush + (1<<19)) {
1590 dpavlin 26 x11_check_event(emuls, n_emuls);
1591     console_flush();
1592 dpavlin 28 emuls[0]->machines[0]->ninstrs_flush =
1593     emuls[0]->machines[0]->ninstrs;
1594 dpavlin 26 }
1595 dpavlin 2
1596 dpavlin 28 if (emuls[0]->machines[0]->ninstrs >
1597     emuls[0]->machines[0]->ninstrs_show + (1<<25)) {
1598     emuls[0]->machines[0]->ninstrs_since_gettimeofday +=
1599     (emuls[0]->machines[0]->ninstrs -
1600     emuls[0]->machines[0]->ninstrs_show);
1601 dpavlin 26 cpu_show_cycles(emuls[0]->machines[0], 0);
1602 dpavlin 28 emuls[0]->machines[0]->ninstrs_show =
1603     emuls[0]->machines[0]->ninstrs;
1604 dpavlin 26 }
1605 dpavlin 2
1606 dpavlin 26 if (single_step == ENTER_SINGLE_STEPPING) {
1607     /* TODO: Cleanup! */
1608     old_instruction_trace =
1609     emuls[0]->machines[0]->instruction_trace;
1610     old_quiet_mode = quiet_mode;
1611     old_show_trace_tree =
1612     emuls[0]->machines[0]->show_trace_tree;
1613     emuls[0]->machines[0]->instruction_trace = 1;
1614     emuls[0]->machines[0]->show_trace_tree = 1;
1615     quiet_mode = 0;
1616     single_step = SINGLE_STEPPING;
1617     }
1618 dpavlin 24
1619 dpavlin 26 if (single_step == SINGLE_STEPPING)
1620     debugger();
1621    
1622     e = emuls[0]; /* Note: Only 1 emul supported now. */
1623    
1624     for (j=0; j<e->n_machines; j++) {
1625     if (e->machines[j]->gdb.port > 0)
1626     debugger_gdb_check_incoming(e->machines[j]);
1627    
1628     anything = machine_run(e->machines[j]);
1629     if (anything)
1630     go = 1;
1631 dpavlin 2 }
1632     }
1633    
1634     /* Deinitialize all CPUs in all machines in all emulations: */
1635     for (i=0; i<n_emuls; i++) {
1636     e = emuls[i];
1637     if (e == NULL)
1638     continue;
1639     for (j=0; j<e->n_machines; j++)
1640 dpavlin 12 cpu_run_deinit(e->machines[j]);
1641 dpavlin 2 }
1642    
1643     /* force_debugger_at_exit flag set? Then enter the debugger: */
1644     if (force_debugger_at_exit) {
1645     quiet_mode = 0;
1646     debugger_reset();
1647     debugger();
1648     }
1649    
1650     /* Any machine using X11? Then we should wait before exiting: */
1651     n = 0;
1652     for (i=0; i<n_emuls; i++)
1653     for (j=0; j<emuls[i]->n_machines; j++)
1654     if (emuls[i]->machines[j]->use_x11)
1655     n++;
1656     if (n > 0) {
1657     printf("Press enter to quit.\n");
1658     while (!console_charavail(MAIN_CONSOLE)) {
1659     x11_check_event(emuls, n_emuls);
1660     usleep(1);
1661     }
1662     console_readchar(MAIN_CONSOLE);
1663     }
1664    
1665     console_deinit();
1666     }
1667    

  ViewVC Help
Powered by ViewVC 1.1.26