/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 41264 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26