/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43364 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26