/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 41811 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

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

  ViewVC Help
Powered by ViewVC 1.1.26