/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24404 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 dpavlin 2 /*
2 dpavlin 34 * Copyright (C) 2003-2007 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 42 * $Id: emul.c,v 1.297 2007/06/15 17:02:37 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     #include "timer.h"
56 dpavlin 42 #include "useremul.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 42 extern int native_code_translation_enabled;
72 dpavlin 2
73    
74     /*
75 dpavlin 42 * add_breakpoints():
76 dpavlin 2 *
77     * Take the strings breakpoint_string[] and convert to addresses
78     * (and store them in breakpoint_addr[]).
79     *
80     * TODO: This function should be moved elsewhere.
81     */
82 dpavlin 42 static void add_breakpoints(struct machine *m)
83 dpavlin 2 {
84     int i;
85     int string_flag;
86     uint64_t dp;
87    
88 dpavlin 42 for (i=0; i<m->breakpoints.n; i++) {
89 dpavlin 2 string_flag = 0;
90 dpavlin 42 dp = strtoull(m->breakpoints.string[i], NULL, 0);
91 dpavlin 2
92     /*
93     * If conversion resulted in 0, then perhaps it is a
94     * symbol:
95     */
96     if (dp == 0) {
97     uint64_t addr;
98     int res = get_symbol_addr(&m->symbol_context,
99 dpavlin 42 m->breakpoints.string[i], &addr);
100 dpavlin 24 if (!res) {
101 dpavlin 2 fprintf(stderr,
102 dpavlin 24 "ERROR! Breakpoint '%s' could not be"
103 dpavlin 2 " parsed\n",
104 dpavlin 42 m->breakpoints.string[i]);
105     exit(1);
106 dpavlin 24 } else {
107 dpavlin 2 dp = addr;
108     string_flag = 1;
109     }
110     }
111    
112     /*
113     * TODO: It would be nice if things like symbolname+0x1234
114     * were automatically converted into the correct address.
115     */
116    
117 dpavlin 20 if (m->arch == ARCH_MIPS) {
118     if ((dp >> 32) == 0 && ((dp >> 31) & 1))
119     dp |= 0xffffffff00000000ULL;
120     }
121    
122 dpavlin 42 m->breakpoints.addr[i] = dp;
123 dpavlin 2
124 dpavlin 20 debug("breakpoint %i: 0x%llx", i, (long long)dp);
125 dpavlin 2 if (string_flag)
126 dpavlin 42 debug(" (%s)", m->breakpoints.string[i]);
127 dpavlin 2 debug("\n");
128     }
129     }
130    
131    
132     /*
133     * fix_console():
134     */
135     static void fix_console(void)
136     {
137 dpavlin 32 console_deinit_main();
138 dpavlin 2 }
139    
140    
141     /*
142     * emul_new():
143     *
144     * Returns a reasonably initialized struct emul.
145     */
146 dpavlin 34 struct emul *emul_new(char *name, int id)
147 dpavlin 2 {
148     struct emul *e;
149    
150 dpavlin 42 CHECK_ALLOCATION(e = malloc(sizeof(struct emul)));
151 dpavlin 2 memset(e, 0, sizeof(struct emul));
152    
153 dpavlin 42 CHECK_ALLOCATION(e->path = malloc(15));
154 dpavlin 34 snprintf(e->path, 15, "emul[%i]", id);
155    
156 dpavlin 32 e->settings = settings_new();
157    
158     settings_add(e->settings, "n_machines", 0,
159     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
160     (void *) &e->n_machines);
161    
162     /* TODO: More settings? */
163    
164 dpavlin 2 /* Sane default values: */
165     e->n_machines = 0;
166 dpavlin 10 e->next_serial_nr = 1;
167 dpavlin 2
168     if (name != NULL) {
169 dpavlin 42 CHECK_ALLOCATION(e->name = strdup(name));
170 dpavlin 32 settings_add(e->settings, "name", 0,
171     SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
172     (void *) &e->name);
173 dpavlin 2 }
174    
175     return e;
176     }
177    
178    
179     /*
180 dpavlin 32 * emul_destroy():
181     *
182     * Destroys a previously created emul object.
183     */
184     void emul_destroy(struct emul *emul)
185     {
186     int i;
187    
188     if (emul->name != NULL) {
189     settings_remove(emul->settings, "name");
190     free(emul->name);
191     }
192    
193     for (i=0; i<emul->n_machines; i++)
194     machine_destroy(emul->machines[i]);
195    
196     if (emul->machines != NULL)
197     free(emul->machines);
198    
199     /* Remove any remaining level-1 settings: */
200     settings_remove_all(emul->settings);
201     settings_destroy(emul->settings);
202    
203     free(emul);
204     }
205    
206    
207     /*
208 dpavlin 2 * emul_add_machine():
209     *
210     * Calls machine_new(), adds the new machine into the emul struct, and
211     * returns a pointer to the new machine.
212     *
213     * This function should be used instead of manually calling machine_new().
214     */
215     struct machine *emul_add_machine(struct emul *e, char *name)
216     {
217     struct machine *m;
218 dpavlin 32 char tmpstr[20];
219     int i;
220 dpavlin 2
221 dpavlin 34 m = machine_new(name, e, e->n_machines);
222 dpavlin 2 m->serial_nr = (e->next_serial_nr ++);
223    
224 dpavlin 42 i = e->n_machines ++;
225 dpavlin 32
226 dpavlin 42 CHECK_ALLOCATION(e->machines = realloc(e->machines,
227     sizeof(struct machine *) * e->n_machines));
228 dpavlin 2
229 dpavlin 32 e->machines[i] = m;
230    
231     snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
232     settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
233     e->machines[i]->settings);
234    
235 dpavlin 2 return m;
236     }
237    
238    
239     /*
240     * add_arc_components():
241     *
242     * This function adds ARCBIOS memory descriptors for the loaded program,
243     * and ARCBIOS components for SCSI devices.
244     */
245     static void add_arc_components(struct machine *m)
246     {
247     struct cpu *cpu = m->cpus[m->bootstrap_cpu];
248     uint64_t start = cpu->pc & 0x1fffffff;
249     uint64_t len = 0xc00000 - start;
250     struct diskimage *d;
251     uint64_t scsicontroller, scsidevice, scsidisk;
252    
253     if ((cpu->pc >> 60) != 0xf) {
254     start = cpu->pc & 0xffffffffffULL;
255     len = 0xc00000 - start;
256     }
257    
258     len += 1048576 * m->memory_offset_in_mb;
259    
260 dpavlin 12 /*
261     * NOTE/TODO: magic 12MB end of load program area
262     *
263     * Hm. This breaks the old FreeBSD/MIPS snapshots...
264     */
265     #if 0
266 dpavlin 2 arcbios_add_memory_descriptor(cpu,
267     0x60000 + m->memory_offset_in_mb * 1048576,
268     start-0x60000 - m->memory_offset_in_mb * 1048576,
269     ARCBIOS_MEM_FreeMemory);
270 dpavlin 12 #endif
271 dpavlin 2 arcbios_add_memory_descriptor(cpu,
272     start, len, ARCBIOS_MEM_LoadedProgram);
273    
274 dpavlin 6 scsicontroller = arcbios_get_scsicontroller(m);
275 dpavlin 2 if (scsicontroller == 0)
276     return;
277    
278     /* TODO: The device 'name' should defined be somewhere else. */
279    
280     d = m->first_diskimage;
281     while (d != NULL) {
282     if (d->type == DISKIMAGE_SCSI) {
283     int a, b, flags = COMPONENT_FLAG_Input;
284     char component_string[100];
285     char *name = "DEC RZ58 (C) DEC2000";
286    
287     /* Read-write, or read-only? */
288     if (d->writable)
289     flags |= COMPONENT_FLAG_Output;
290     else
291     flags |= COMPONENT_FLAG_ReadOnly;
292    
293     a = COMPONENT_TYPE_DiskController;
294     b = COMPONENT_TYPE_DiskPeripheral;
295    
296     if (d->is_a_cdrom) {
297     flags |= COMPONENT_FLAG_Removable;
298     a = COMPONENT_TYPE_CDROMController;
299     b = COMPONENT_TYPE_FloppyDiskPeripheral;
300     name = "NEC CD-ROM CDR-210P 1.0 ";
301     }
302    
303     scsidevice = arcbios_addchild_manual(cpu,
304     COMPONENT_CLASS_ControllerClass,
305     a, flags, 1, 2, d->id, 0xffffffff,
306     name, scsicontroller, NULL, 0);
307    
308     scsidisk = arcbios_addchild_manual(cpu,
309     COMPONENT_CLASS_PeripheralClass,
310     b, flags, 1, 2, 0, 0xffffffff, NULL,
311     scsidevice, NULL, 0);
312    
313     /*
314     * Add device string to component address mappings:
315     * "scsi(0)disk(0)rdisk(0)partition(0)"
316     */
317    
318     if (d->is_a_cdrom) {
319     snprintf(component_string,
320     sizeof(component_string),
321     "scsi(0)cdrom(%i)", d->id);
322 dpavlin 6 arcbios_add_string_to_component(m,
323 dpavlin 2 component_string, scsidevice);
324    
325     snprintf(component_string,
326     sizeof(component_string),
327     "scsi(0)cdrom(%i)fdisk(0)", d->id);
328 dpavlin 6 arcbios_add_string_to_component(m,
329 dpavlin 2 component_string, scsidisk);
330     } else {
331     snprintf(component_string,
332     sizeof(component_string),
333     "scsi(0)disk(%i)", d->id);
334 dpavlin 6 arcbios_add_string_to_component(m,
335 dpavlin 2 component_string, scsidevice);
336    
337     snprintf(component_string,
338     sizeof(component_string),
339     "scsi(0)disk(%i)rdisk(0)", d->id);
340 dpavlin 6 arcbios_add_string_to_component(m,
341 dpavlin 2 component_string, scsidisk);
342     }
343     }
344    
345     d = d->next;
346     }
347     }
348    
349    
350     /*
351     * emul_machine_setup():
352     *
353     * o) Initialize the hardware (RAM, devices, CPUs, ...) which
354     * will be emulated in this machine.
355     *
356     * o) Load ROM code and/or other programs into emulated memory.
357     *
358     * o) Special hacks needed after programs have been loaded.
359     */
360     void emul_machine_setup(struct machine *m, int n_load, char **load_names,
361     int n_devices, char **device_names)
362     {
363     struct cpu *cpu;
364 dpavlin 22 int i, iadd = DEBUG_INDENTATION;
365 dpavlin 6 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
366 dpavlin 2 int byte_order;
367    
368     debug("machine \"%s\":\n", m->name);
369     debug_indentation(iadd);
370    
371     /* For userland-only, this decides which ARCH/cpu_name to use: */
372     if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
373     useremul_name_to_useremul(NULL, m->userland_emul,
374     &m->arch, &m->machine_name, &m->cpu_name);
375     if (m->arch == ARCH_NOARCH) {
376     printf("Unsupported userland emulation mode.\n");
377     exit(1);
378     }
379     }
380    
381     if (m->machine_type == MACHINE_NONE) {
382     fatal("No machine type specified?\n");
383     exit(1);
384     }
385    
386     m->cpu_family = cpu_family_ptr_by_number(m->arch);
387    
388 dpavlin 12 if (m->arch == ARCH_ALPHA)
389     m->arch_pagesize = 8192;
390    
391 dpavlin 2 machine_memsize_fix(m);
392    
393     /*
394     * Create the system's memory:
395     *
396     * (Don't print the amount for userland-only emulation; the
397     * size doesn't matter.)
398     */
399     if (m->machine_type != MACHINE_USERLAND)
400     debug("memory: %i MB", m->physical_ram_in_mb);
401     memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
402     if (m->memory_offset_in_mb > 0) {
403     /*
404     * A special hack is used for some SGI models,
405     * where memory is offset by 128MB to leave room for
406     * EISA space and other things.
407     */
408     debug(" (offset by %iMB)", m->memory_offset_in_mb);
409     memory_amount += 1048576 * m->memory_offset_in_mb;
410     }
411 dpavlin 12 m->memory = memory_new(memory_amount, m->arch);
412 dpavlin 2 if (m->machine_type != MACHINE_USERLAND)
413     debug("\n");
414    
415     /* Create CPUs: */
416     if (m->cpu_name == NULL)
417     machine_default_cputype(m);
418     if (m->ncpus == 0) {
419     /* TODO: This should be moved elsewhere... */
420     if (m->machine_type == MACHINE_BEBOX)
421     m->ncpus = 2;
422     else
423     m->ncpus = 1;
424     }
425 dpavlin 42
426     CHECK_ALLOCATION(m->cpus = malloc(sizeof(struct cpu *) * m->ncpus));
427 dpavlin 2 memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
428    
429     debug("cpu0");
430     if (m->ncpus > 1)
431     debug(" .. cpu%i", m->ncpus - 1);
432     debug(": ");
433     for (i=0; i<m->ncpus; i++) {
434     m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
435 dpavlin 24 if (m->cpus[i] == NULL) {
436     fprintf(stderr, "Unable to create CPU object. "
437     "Aborting.");
438     exit(1);
439     }
440 dpavlin 2 }
441     debug("\n");
442    
443     if (m->use_random_bootstrap_cpu)
444     m->bootstrap_cpu = random() % m->ncpus;
445     else
446     m->bootstrap_cpu = 0;
447    
448     cpu = m->cpus[m->bootstrap_cpu];
449    
450     /* Set cpu->useremul_syscall, and use userland_memory_rw: */
451     if (m->userland_emul != NULL) {
452     useremul_name_to_useremul(cpu,
453     m->userland_emul, NULL, NULL, NULL);
454 dpavlin 12
455     switch (m->arch) {
456 dpavlin 42
457 dpavlin 12 case ARCH_ALPHA:
458     cpu->memory_rw = alpha_userland_memory_rw;
459     break;
460 dpavlin 42
461     default:
462     cpu->memory_rw = userland_memory_rw;
463 dpavlin 12 }
464 dpavlin 2 }
465    
466 dpavlin 42 if (m->x11_md.in_use)
467 dpavlin 2 x11_init(m);
468    
469     /* Fill memory with random bytes: */
470     if (m->random_mem_contents) {
471     for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
472     unsigned char data[256];
473     unsigned int j;
474     for (j=0; j<sizeof(data); j++)
475     data[j] = random() & 255;
476 dpavlin 6 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
477     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
478 dpavlin 2 }
479     }
480    
481     if (m->userland_emul != NULL) {
482     /*
483     * For userland-only emulation, no machine emulation
484     * is needed.
485     */
486     } else {
487     for (i=0; i<n_devices; i++)
488     device_add(m, device_names[i]);
489    
490     machine_setup(m);
491     }
492    
493     diskimage_dump_info(m);
494 dpavlin 22 console_debug_dump(m);
495 dpavlin 2
496     /* Load files (ROM code, boot code, ...) into memory: */
497     if (n_load == 0) {
498 dpavlin 6 if (m->first_diskimage != NULL) {
499     if (!load_bootblock(m, cpu, &n_load, &load_names)) {
500     fprintf(stderr, "\nNo executable files were"
501     " specified, and booting directly from disk"
502     " failed.\n");
503     exit(1);
504     }
505     } else {
506 dpavlin 2 fprintf(stderr, "No executable file(s) loaded, and "
507     "we are not booting directly from a disk image."
508     "\nAborting.\n");
509     exit(1);
510     }
511     }
512    
513     while (n_load > 0) {
514 dpavlin 6 FILE *tmp_f;
515     char *name_to_load = *load_names;
516     int remove_after_load = 0;
517    
518     /* Special hack for removing temporary files: */
519     if (name_to_load[0] == 8) {
520     name_to_load ++;
521     remove_after_load = 1;
522     }
523    
524     /*
525 dpavlin 10 * gzipped files are automagically gunzipped:
526     * NOTE/TODO: This isn't secure. system() is used.
527 dpavlin 6 */
528     tmp_f = fopen(name_to_load, "r");
529     if (tmp_f != NULL) {
530     unsigned char buf[2]; /* gzip header */
531     memset(buf, 0, sizeof(buf));
532     fread(buf, 1, sizeof(buf), tmp_f);
533     if (buf[0]==0x1f && buf[1]==0x8b) {
534 dpavlin 10 size_t zzlen = strlen(name_to_load)*2 + 100;
535 dpavlin 42 char *zz;
536    
537     CHECK_ALLOCATION(zz = malloc(zzlen));
538 dpavlin 6 debug("gunziping %s\n", name_to_load);
539 dpavlin 42
540 dpavlin 10 /*
541     * gzip header found. If this was a file
542     * extracted from, say, a CDROM image, then it
543     * already has a temporary name. Otherwise we
544     * have to gunzip into a temporary file.
545     */
546     if (remove_after_load) {
547     snprintf(zz, zzlen, "mv %s %s.gz",
548     name_to_load, name_to_load);
549     system(zz);
550     snprintf(zz, zzlen, "gunzip %s.gz",
551     name_to_load);
552     system(zz);
553     } else {
554     /* gunzip into new temp file: */
555     int tmpfile_handle;
556 dpavlin 42 char *new_temp_name;
557     CHECK_ALLOCATION(new_temp_name =
558     strdup("/tmp/gxemul.XXXXXXXXXXXX"));
559 dpavlin 10 tmpfile_handle = mkstemp(new_temp_name);
560     close(tmpfile_handle);
561     snprintf(zz, zzlen, "gunzip -c '%s' > "
562     "%s", name_to_load, new_temp_name);
563     system(zz);
564     name_to_load = new_temp_name;
565     remove_after_load = 1;
566     }
567 dpavlin 6 free(zz);
568     }
569     fclose(tmp_f);
570     }
571    
572 dpavlin 2 byte_order = NO_BYTE_ORDER_OVERRIDE;
573    
574 dpavlin 6 /*
575     * Load the file: :-)
576     */
577     file_load(m, m->memory, name_to_load, &entrypoint,
578 dpavlin 2 m->arch, &gp, &byte_order, &toc);
579    
580 dpavlin 6 if (remove_after_load) {
581     debug("removing %s\n", name_to_load);
582     unlink(name_to_load);
583     }
584    
585 dpavlin 2 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
586     cpu->byte_order = byte_order;
587    
588     cpu->pc = entrypoint;
589    
590     switch (m->arch) {
591 dpavlin 14
592     case ARCH_ALPHA:
593 dpavlin 18 /* For position-independent code: */
594 dpavlin 14 cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
595     break;
596    
597     case ARCH_ARM:
598 dpavlin 20 if (cpu->pc & 3) {
599     fatal("ARM: lowest bits of pc set: TODO\n");
600     exit(1);
601     }
602 dpavlin 14 cpu->pc &= 0xfffffffc;
603     break;
604    
605 dpavlin 42 case ARCH_M88K:
606     if (cpu->pc & 3) {
607     fatal("M88K: lowest bits of pc set: TODO\n");
608 dpavlin 14 exit(1);
609     }
610 dpavlin 42 cpu->pc &= 0xfffffffc;
611 dpavlin 14 break;
612    
613 dpavlin 2 case ARCH_MIPS:
614 dpavlin 20 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
615 dpavlin 2 cpu->pc |= 0xffffffff00000000ULL;
616    
617     cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
618    
619     if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
620     (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
621     cpu->cd.mips.gpr[MIPS_GPR_GP] |=
622     0xffffffff00000000ULL;
623     break;
624 dpavlin 4
625 dpavlin 2 case ARCH_PPC:
626 dpavlin 6 /* See http://www.linuxbase.org/spec/ELF/ppc64/
627     spec/x458.html for more info. */
628 dpavlin 2 cpu->cd.ppc.gpr[2] = toc;
629 dpavlin 6 /* TODO */
630 dpavlin 14 if (cpu->cd.ppc.bits == 32)
631     cpu->pc &= 0xffffffffULL;
632 dpavlin 2 break;
633 dpavlin 4
634 dpavlin 14 case ARCH_SH:
635 dpavlin 30 if (cpu->cd.sh.cpu_type.bits == 32)
636 dpavlin 14 cpu->pc &= 0xffffffffULL;
637     cpu->pc &= ~1;
638 dpavlin 12 break;
639    
640 dpavlin 2 case ARCH_SPARC:
641     break;
642 dpavlin 4
643 dpavlin 2 default:
644     fatal("emul_machine_setup(): Internal error: "
645     "Unimplemented arch %i\n", m->arch);
646     exit(1);
647     }
648    
649     /*
650     * For userland emulation, the remaining items
651     * on the command line will be passed as parameters
652     * to the emulated program, and will not be treated
653     * as filenames to load into the emulator.
654     * The program's name will be in load_names[0], and the
655     * rest of the parameters in load_names[1] and up.
656     */
657     if (m->userland_emul != NULL)
658     break;
659    
660     n_load --;
661     load_names ++;
662     }
663    
664     if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
665     cpu->byte_order = m->byte_order_override;
666    
667     /* Same byte order and entrypoint for all CPUs: */
668     for (i=0; i<m->ncpus; i++)
669     if (i != m->bootstrap_cpu) {
670     m->cpus[i]->byte_order = cpu->byte_order;
671     m->cpus[i]->pc = cpu->pc;
672     }
673    
674     if (m->userland_emul != NULL)
675     useremul_setup(cpu, n_load, load_names);
676    
677     /* Startup the bootstrap CPU: */
678 dpavlin 30 cpu->running = 1;
679 dpavlin 2
680     /* ... or pause all CPUs, if start_paused is set: */
681     if (m->start_paused) {
682     for (i=0; i<m->ncpus; i++)
683     m->cpus[i]->running = 0;
684     }
685    
686 dpavlin 42 /* Parse and add breakpoints: */
687     add_breakpoints(m);
688 dpavlin 2
689     /* TODO: This is MIPS-specific! */
690 dpavlin 22 if (m->machine_type == MACHINE_PMAX &&
691 dpavlin 2 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
692     add_symbol_name(&m->symbol_context,
693 dpavlin 12 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
694 dpavlin 2
695     symbol_recalc_sizes(&m->symbol_context);
696    
697     /* Special hack for ARC/SGI emulation: */
698     if ((m->machine_type == MACHINE_ARC ||
699     m->machine_type == MACHINE_SGI) && m->prom_emulation)
700     add_arc_components(m);
701    
702     debug("starting cpu%i at ", m->bootstrap_cpu);
703     switch (m->arch) {
704 dpavlin 14
705     case ARCH_ARM:
706     /* ARM cpus aren't 64-bit: */
707 dpavlin 38 debug("0x%08"PRIx32, (uint32_t) entrypoint);
708 dpavlin 14 break;
709    
710 dpavlin 2 case ARCH_MIPS:
711 dpavlin 12 if (cpu->is_32bit) {
712 dpavlin 38 debug("0x%08"PRIx32, (uint32_t)
713     m->cpus[m->bootstrap_cpu]->pc);
714 dpavlin 2 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
715 dpavlin 38 debug(" (gp=0x%08"PRIx32")", (uint32_t)
716     m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
717 dpavlin 2 MIPS_GPR_GP]);
718     } else {
719 dpavlin 38 debug("0x%016"PRIx64, (uint64_t)
720     m->cpus[m->bootstrap_cpu]->pc);
721 dpavlin 2 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
722 dpavlin 38 debug(" (gp=0x%016"PRIx64")", (uint64_t)
723 dpavlin 2 cpu->cd.mips.gpr[MIPS_GPR_GP]);
724     }
725     break;
726 dpavlin 14
727 dpavlin 2 case ARCH_PPC:
728     if (cpu->cd.ppc.bits == 32)
729 dpavlin 38 debug("0x%08"PRIx32, (uint32_t) entrypoint);
730 dpavlin 2 else
731 dpavlin 38 debug("0x%016"PRIx64, (uint64_t) entrypoint);
732 dpavlin 2 break;
733 dpavlin 14
734 dpavlin 2 default:
735 dpavlin 22 if (cpu->is_32bit)
736 dpavlin 38 debug("0x%08"PRIx32, (uint32_t) cpu->pc);
737 dpavlin 22 else
738 dpavlin 38 debug("0x%016"PRIx64, (uint64_t) cpu->pc);
739 dpavlin 2 }
740     debug("\n");
741    
742     debug_indentation(-iadd);
743     }
744    
745    
746     /*
747     * emul_dumpinfo():
748     *
749     * Dump info about all machines in an emul.
750     */
751     void emul_dumpinfo(struct emul *e)
752     {
753 dpavlin 22 int j, nm, iadd = DEBUG_INDENTATION;
754 dpavlin 2
755     if (e->net != NULL)
756     net_dumpinfo(e->net);
757    
758     nm = e->n_machines;
759     for (j=0; j<nm; j++) {
760     debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
761     debug_indentation(iadd);
762     machine_dumpinfo(e->machines[j]);
763     debug_indentation(-iadd);
764     }
765     }
766    
767    
768     /*
769     * emul_simple_init():
770     *
771     * For a normal setup:
772     *
773     * o) Initialize a network.
774     * o) Initialize one machine.
775     *
776     * For a userland-only setup:
777     *
778     * o) Initialize a "pseudo"-machine.
779     */
780     void emul_simple_init(struct emul *emul)
781     {
782 dpavlin 22 int iadd = DEBUG_INDENTATION;
783 dpavlin 2 struct machine *m;
784    
785     if (emul->n_machines != 1) {
786     fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
787     exit(1);
788     }
789    
790     m = emul->machines[0];
791    
792     if (m->userland_emul == NULL) {
793     debug("Simple setup...\n");
794     debug_indentation(iadd);
795    
796 dpavlin 10 /* Create a simple network: */
797 dpavlin 2 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
798 dpavlin 32 NET_DEFAULT_IPV4_MASK,
799     NET_DEFAULT_IPV4_LEN,
800     NULL, 0, 0, NULL);
801 dpavlin 2 } else {
802     /* Userland pseudo-machine: */
803     debug("Syscall emulation (userland-only) setup...\n");
804     debug_indentation(iadd);
805     }
806    
807     /* Create the machine: */
808     emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
809    
810     debug_indentation(-iadd);
811     }
812    
813    
814     /*
815     * emul_create_from_configfile():
816     *
817     * Create an emul struct by reading settings from a configuration file.
818     */
819 dpavlin 34 struct emul *emul_create_from_configfile(char *fname, int id)
820 dpavlin 2 {
821 dpavlin 22 int iadd = DEBUG_INDENTATION;
822 dpavlin 34 struct emul *e = emul_new(fname, id);
823 dpavlin 2
824     debug("Creating emulation from configfile \"%s\":\n", fname);
825     debug_indentation(iadd);
826    
827 dpavlin 24 emul_parse_config(e, fname);
828 dpavlin 2
829     debug_indentation(-iadd);
830     return e;
831     }
832    
833    
834     /*
835     * emul_run():
836     *
837     * o) Set up things needed before running emulations.
838     *
839     * o) Run emulations (one or more, in parallel).
840     *
841     * o) De-initialize things.
842     */
843     void emul_run(struct emul **emuls, int n_emuls)
844     {
845     struct emul *e;
846     int i = 0, j, go = 1, n, anything;
847    
848     if (n_emuls < 1) {
849     fprintf(stderr, "emul_run(): no thing to do\n");
850     return;
851     }
852    
853     atexit(fix_console);
854    
855     /* Initialize the interactive debugger: */
856     debugger_init(emuls, n_emuls);
857    
858 dpavlin 22 /* Run any additional debugger commands before starting: */
859     for (i=0; i<n_emuls; i++) {
860     struct emul *emul = emuls[i];
861     if (emul->n_debugger_cmds > 0) {
862     int j;
863     if (i == 0)
864 dpavlin 42 print_separator_line();
865 dpavlin 22 for (j = 0; j < emul->n_debugger_cmds; j ++) {
866     debug("> %s\n", emul->debugger_cmds[j]);
867     debugger_execute_cmd(emul->debugger_cmds[j],
868     strlen(emul->debugger_cmds[j]));
869     }
870     }
871     }
872    
873 dpavlin 42 print_separator_line();
874 dpavlin 22 debug("\n");
875    
876    
877 dpavlin 2 /*
878     * console_init_main() makes sure that the terminal is in a
879     * reasonable state.
880     *
881     * The SIGINT handler is for CTRL-C (enter the interactive debugger).
882     *
883     * The SIGCONT handler is invoked whenever the user presses CTRL-Z
884     * (or sends SIGSTOP) and then continues. It makes sure that the
885     * terminal is in an expected state.
886     */
887     console_init_main(emuls[0]); /* TODO: what is a good argument? */
888     signal(SIGINT, debugger_activate);
889     signal(SIGCONT, console_sigcont);
890    
891     /* Not in verbose mode? Then set quiet_mode. */
892     if (!verbose)
893     quiet_mode = 1;
894    
895     /* Initialize all CPUs in all machines in all emulations: */
896     for (i=0; i<n_emuls; i++) {
897     e = emuls[i];
898     if (e == NULL)
899     continue;
900     for (j=0; j<e->n_machines; j++)
901 dpavlin 12 cpu_run_init(e->machines[j]);
902 dpavlin 2 }
903    
904 dpavlin 12 /* TODO: Generalize: */
905     if (emuls[0]->machines[0]->show_trace_tree)
906     cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
907     emuls[0]->machines[0]->cpus[0]->pc);
908    
909 dpavlin 32 /* Start emulated clocks: */
910     timer_start();
911    
912 dpavlin 2 /*
913     * MAIN LOOP:
914     *
915 dpavlin 42 * Run all emulations in parallel, running instructions from each
916     * cpu in each machine in each emulation.
917 dpavlin 2 */
918     while (go) {
919 dpavlin 42 struct cpu *bootcpu = emuls[0]->machines[0]->cpus[
920     emuls[0]->machines[0]->bootstrap_cpu];
921    
922 dpavlin 2 go = 0;
923    
924 dpavlin 26 /* Flush X11 and serial console output every now and then: */
925 dpavlin 42 if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) {
926 dpavlin 26 x11_check_event(emuls, n_emuls);
927     console_flush();
928 dpavlin 42 bootcpu->ninstrs_flush = bootcpu->ninstrs;
929 dpavlin 26 }
930 dpavlin 2
931 dpavlin 42 if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) {
932     bootcpu->ninstrs_since_gettimeofday +=
933     (bootcpu->ninstrs - bootcpu->ninstrs_show);
934 dpavlin 26 cpu_show_cycles(emuls[0]->machines[0], 0);
935 dpavlin 42 bootcpu->ninstrs_show = bootcpu->ninstrs;
936 dpavlin 26 }
937 dpavlin 2
938 dpavlin 26 if (single_step == ENTER_SINGLE_STEPPING) {
939     /* TODO: Cleanup! */
940     old_instruction_trace =
941     emuls[0]->machines[0]->instruction_trace;
942     old_quiet_mode = quiet_mode;
943     old_show_trace_tree =
944     emuls[0]->machines[0]->show_trace_tree;
945     emuls[0]->machines[0]->instruction_trace = 1;
946     emuls[0]->machines[0]->show_trace_tree = 1;
947     quiet_mode = 0;
948     single_step = SINGLE_STEPPING;
949     }
950 dpavlin 24
951 dpavlin 26 if (single_step == SINGLE_STEPPING)
952     debugger();
953    
954 dpavlin 32 for (i=0; i<n_emuls; i++) {
955     e = emuls[i];
956 dpavlin 26
957 dpavlin 32 for (j=0; j<e->n_machines; j++) {
958     anything = machine_run(e->machines[j]);
959     if (anything)
960     go = 1;
961     }
962 dpavlin 2 }
963     }
964    
965 dpavlin 32 /* Stop any running timers: */
966     timer_stop();
967    
968 dpavlin 2 /* Deinitialize all CPUs in all machines in all emulations: */
969     for (i=0; i<n_emuls; i++) {
970     e = emuls[i];
971     if (e == NULL)
972     continue;
973     for (j=0; j<e->n_machines; j++)
974 dpavlin 12 cpu_run_deinit(e->machines[j]);
975 dpavlin 2 }
976    
977     /* force_debugger_at_exit flag set? Then enter the debugger: */
978     if (force_debugger_at_exit) {
979     quiet_mode = 0;
980     debugger_reset();
981     debugger();
982     }
983    
984 dpavlin 32 /* Any machine using X11? Then wait before exiting: */
985 dpavlin 2 n = 0;
986     for (i=0; i<n_emuls; i++)
987     for (j=0; j<emuls[i]->n_machines; j++)
988 dpavlin 42 if (emuls[i]->machines[j]->x11_md.in_use)
989 dpavlin 2 n++;
990     if (n > 0) {
991     printf("Press enter to quit.\n");
992     while (!console_charavail(MAIN_CONSOLE)) {
993     x11_check_event(emuls, n_emuls);
994 dpavlin 32 usleep(10000);
995 dpavlin 2 }
996     console_readchar(MAIN_CONSOLE);
997     }
998    
999 dpavlin 32 console_deinit_main();
1000 dpavlin 2 }
1001    

  ViewVC Help
Powered by ViewVC 1.1.26