/[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

Contents of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (12 years ago) by dpavlin
File MIME type: text/plain
File size: 40656 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26