/[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 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24856 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 4 * $Id: emul.c,v 1.184 2005/04/20 04:43:52 debug Exp $
29 dpavlin 2 *
30     * Emulation startup and misc. routines.
31     */
32    
33     #include <signal.h>
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <limits.h>
37     #include <stdarg.h>
38     #include <string.h>
39     #include <unistd.h>
40    
41     #include "arcbios.h"
42     #include "bintrans.h"
43     #include "cpu.h"
44     #include "emul.h"
45     #include "console.h"
46     #include "debugger.h"
47     #include "device.h"
48     #include "diskimage.h"
49     #include "machine.h"
50     #include "memory.h"
51     #include "mips_cpu_types.h"
52     #include "misc.h"
53     #include "net.h"
54     #include "sgi_arcbios.h"
55     #include "x11.h"
56    
57    
58     extern int force_debugger_at_exit;
59    
60     extern int extra_argc;
61     extern char **extra_argv;
62    
63     extern int verbose;
64     extern int quiet_mode;
65    
66     extern struct emul *debugger_emul;
67     extern struct diskimage *diskimages[];
68    
69    
70     /*
71     * add_dump_points():
72     *
73     * Take the strings breakpoint_string[] and convert to addresses
74     * (and store them in breakpoint_addr[]).
75     *
76     * TODO: This function should be moved elsewhere.
77     */
78     static void add_dump_points(struct machine *m)
79     {
80     int i;
81     int string_flag;
82     uint64_t dp;
83    
84     for (i=0; i<m->n_breakpoints; i++) {
85     string_flag = 0;
86     dp = strtoull(m->breakpoint_string[i], NULL, 0);
87    
88     /*
89     * If conversion resulted in 0, then perhaps it is a
90     * symbol:
91     */
92     if (dp == 0) {
93     uint64_t addr;
94     int res = get_symbol_addr(&m->symbol_context,
95     m->breakpoint_string[i], &addr);
96     if (!res)
97     fprintf(stderr,
98     "WARNING! Breakpoint '%s' could not be"
99     " parsed\n",
100     m->breakpoint_string[i]);
101     else {
102     dp = addr;
103     string_flag = 1;
104     }
105     }
106    
107     /*
108     * TODO: It would be nice if things like symbolname+0x1234
109     * were automatically converted into the correct address.
110     */
111    
112     if ((dp >> 32) == 0 && ((dp >> 31) & 1))
113     dp |= 0xffffffff00000000ULL;
114     m->breakpoint_addr[i] = dp;
115    
116     debug("breakpoint %i: 0x%016llx", i, (long long)dp);
117     if (string_flag)
118     debug(" (%s)", m->breakpoint_string[i]);
119     debug("\n");
120     }
121     }
122    
123    
124     /*
125     * fix_console():
126     */
127     static void fix_console(void)
128     {
129     console_deinit();
130     }
131    
132    
133     /*
134     * load_bootblock():
135     *
136     * For some emulation modes, it is possible to boot from a harddisk image by
137     * loading a bootblock from a specific disk offset into memory, and executing
138     * that, instead of requiring a separate kernel file. It is then up to the
139     * bootblock to load a kernel.
140     */
141     static void load_bootblock(struct machine *m, struct cpu *cpu)
142     {
143     int boot_disk_id;
144     unsigned char minibuf[0x20];
145     unsigned char *bootblock_buf;
146     uint64_t bootblock_offset;
147     uint64_t bootblock_loadaddr, bootblock_pc;
148     int n_blocks, res, readofs;
149    
150     boot_disk_id = diskimage_bootdev(m);
151     if (boot_disk_id < 0)
152     return;
153    
154     switch (m->machine_type) {
155     case MACHINE_DEC:
156     /*
157     * The first few bytes of a disk contains information about
158     * where the bootblock(s) are located. (These are all 32-bit
159     * little-endian words.)
160     *
161     * Offset 0x10 = load address
162     * 0x14 = initial PC value
163     * 0x18 = nr of 512-byte blocks to read
164     * 0x1c = offset on disk to where the bootblocks
165     * are (in 512-byte units)
166     * 0x20 = nr of blocks to read...
167     * 0x24 = offset...
168     *
169     * nr of blocks to read and offset are repeated until nr of
170     * blocks to read is zero.
171     */
172     res = diskimage_access(m, boot_disk_id, 0, 0,
173     minibuf, sizeof(minibuf));
174    
175     bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
176     + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);
177    
178     /* Convert loadaddr to uncached: */
179     if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
180     (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)
181     fatal("\nWARNING! Weird load address 0x%08x.\n\n",
182     (int)bootblock_loadaddr);
183     bootblock_loadaddr &= 0x0fffffffULL;
184     bootblock_loadaddr |= 0xffffffffa0000000ULL;
185    
186     bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
187     + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);
188    
189     bootblock_pc &= 0x0fffffffULL;
190     bootblock_pc |= 0xffffffffa0000000ULL;
191     cpu->pc = bootblock_pc;
192    
193     debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",
194     (int)bootblock_loadaddr, (int)bootblock_pc);
195    
196     readofs = 0x18;
197    
198     for (;;) {
199     res = diskimage_access(m, boot_disk_id, 0, readofs,
200     minibuf, sizeof(minibuf));
201     if (!res) {
202     printf("couldn't read disk?\n");
203     exit(1);
204     }
205    
206     n_blocks = minibuf[0] + (minibuf[1] << 8)
207     + (minibuf[2] << 16) + (minibuf[3] << 24);
208    
209     bootblock_offset = (minibuf[4] + (minibuf[5] << 8)
210     + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;
211    
212     if (n_blocks < 1)
213     break;
214    
215     debug(readofs == 0x18? ": %i" : " + %i", n_blocks);
216    
217     if (n_blocks * 512 > 65536)
218     fatal("\nWARNING! Unusually large bootblock "
219     "(%i bytes)\n\n", n_blocks * 512);
220    
221     bootblock_buf = malloc(n_blocks * 512);
222     if (bootblock_buf == NULL) {
223     fprintf(stderr, "out of memory in "
224     "load_bootblock()\n");
225     exit(1);
226     }
227    
228     res = diskimage_access(m, boot_disk_id, 0,
229     bootblock_offset, bootblock_buf, n_blocks * 512);
230     if (!res) {
231     fatal("WARNING: could not load bootblocks from"
232     " disk offset 0x%llx\n",
233     (long long)bootblock_offset);
234     }
235    
236     store_buf(cpu, bootblock_loadaddr,
237     (char *)bootblock_buf, n_blocks * 512);
238    
239     bootblock_loadaddr += 512*n_blocks;
240     free(bootblock_buf);
241     readofs += 8;
242     }
243    
244     debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
245     break;
246 dpavlin 4
247     case MACHINE_X86:
248     cpu->cd.x86.mode = 16;
249     cpu->pc = 0x7c00;
250    
251     bootblock_buf = malloc(512);
252     if (bootblock_buf == NULL) {
253     fprintf(stderr, "Out of memory.\n");
254     exit(1);
255     }
256    
257     res = diskimage_access(m, boot_disk_id, 0, 0,
258     bootblock_buf, 512);
259     if (!res) {
260     printf("Couldn't read the disk image. Aborting.\n");
261     exit(1);
262     }
263    
264     debug("loading PC bootsector from disk %i\n", boot_disk_id);
265     if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)
266     debug("WARNING! The 0x55,0xAA marker is missing! "
267     "Booting anyway.\n");
268     store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);
269     free(bootblock_buf);
270     break;
271    
272 dpavlin 2 default:
273     fatal("Booting from disk without a separate kernel "
274     "doesn't work in this emulation mode.\n");
275     exit(1);
276     }
277     }
278    
279    
280     /*
281     * emul_new():
282     *
283     * Returns a reasonably initialized struct emul.
284     */
285     struct emul *emul_new(char *name)
286     {
287     struct emul *e;
288     e = malloc(sizeof(struct emul));
289     if (e == NULL) {
290     fprintf(stderr, "out of memory in emul_new()\n");
291     exit(1);
292     }
293    
294     memset(e, 0, sizeof(struct emul));
295    
296     /* Sane default values: */
297     e->n_machines = 0;
298    
299     if (name != NULL) {
300     e->name = strdup(name);
301     if (e->name == NULL) {
302     fprintf(stderr, "out of memory in emul_new()\n");
303     exit(1);
304     }
305     }
306    
307     return e;
308     }
309    
310    
311     /*
312     * emul_add_machine():
313     *
314     * Calls machine_new(), adds the new machine into the emul struct, and
315     * returns a pointer to the new machine.
316     *
317     * This function should be used instead of manually calling machine_new().
318     */
319     struct machine *emul_add_machine(struct emul *e, char *name)
320     {
321     struct machine *m;
322    
323     m = machine_new(name, e);
324     m->serial_nr = (e->next_serial_nr ++);
325    
326     e->n_machines ++;
327     e->machines = realloc(e->machines,
328     sizeof(struct machine *) * e->n_machines);
329     if (e->machines == NULL) {
330     fprintf(stderr, "emul_add_machine(): out of memory\n");
331     exit(1);
332     }
333    
334     e->machines[e->n_machines - 1] = m;
335     return m;
336     }
337    
338    
339     /*
340     * add_arc_components():
341     *
342     * This function adds ARCBIOS memory descriptors for the loaded program,
343     * and ARCBIOS components for SCSI devices.
344     */
345     static void add_arc_components(struct machine *m)
346     {
347     struct cpu *cpu = m->cpus[m->bootstrap_cpu];
348     uint64_t start = cpu->pc & 0x1fffffff;
349     uint64_t len = 0xc00000 - start;
350     struct diskimage *d;
351     uint64_t scsicontroller, scsidevice, scsidisk;
352    
353     if ((cpu->pc >> 60) != 0xf) {
354     start = cpu->pc & 0xffffffffffULL;
355     len = 0xc00000 - start;
356     }
357    
358     len += 1048576 * m->memory_offset_in_mb;
359    
360     /* NOTE/TODO: magic 12MB end of load program area */
361     arcbios_add_memory_descriptor(cpu,
362     0x60000 + m->memory_offset_in_mb * 1048576,
363     start-0x60000 - m->memory_offset_in_mb * 1048576,
364     ARCBIOS_MEM_FreeMemory);
365     arcbios_add_memory_descriptor(cpu,
366     start, len, ARCBIOS_MEM_LoadedProgram);
367    
368     scsicontroller = arcbios_get_scsicontroller();
369     if (scsicontroller == 0)
370     return;
371    
372     /* TODO: The device 'name' should defined be somewhere else. */
373    
374     d = m->first_diskimage;
375     while (d != NULL) {
376     if (d->type == DISKIMAGE_SCSI) {
377     int a, b, flags = COMPONENT_FLAG_Input;
378     char component_string[100];
379     char *name = "DEC RZ58 (C) DEC2000";
380    
381     /* Read-write, or read-only? */
382     if (d->writable)
383     flags |= COMPONENT_FLAG_Output;
384     else
385     flags |= COMPONENT_FLAG_ReadOnly;
386    
387     a = COMPONENT_TYPE_DiskController;
388     b = COMPONENT_TYPE_DiskPeripheral;
389    
390     if (d->is_a_cdrom) {
391     flags |= COMPONENT_FLAG_Removable;
392     a = COMPONENT_TYPE_CDROMController;
393     b = COMPONENT_TYPE_FloppyDiskPeripheral;
394     name = "NEC CD-ROM CDR-210P 1.0 ";
395     }
396    
397     scsidevice = arcbios_addchild_manual(cpu,
398     COMPONENT_CLASS_ControllerClass,
399     a, flags, 1, 2, d->id, 0xffffffff,
400     name, scsicontroller, NULL, 0);
401    
402     scsidisk = arcbios_addchild_manual(cpu,
403     COMPONENT_CLASS_PeripheralClass,
404     b, flags, 1, 2, 0, 0xffffffff, NULL,
405     scsidevice, NULL, 0);
406    
407     /*
408     * Add device string to component address mappings:
409     * "scsi(0)disk(0)rdisk(0)partition(0)"
410     */
411    
412     if (d->is_a_cdrom) {
413     snprintf(component_string,
414     sizeof(component_string),
415     "scsi(0)cdrom(%i)", d->id);
416     arcbios_add_string_to_component(
417     component_string, scsidevice);
418    
419     snprintf(component_string,
420     sizeof(component_string),
421     "scsi(0)cdrom(%i)fdisk(0)", d->id);
422     arcbios_add_string_to_component(
423     component_string, scsidisk);
424     } else {
425     snprintf(component_string,
426     sizeof(component_string),
427     "scsi(0)disk(%i)", d->id);
428     arcbios_add_string_to_component(
429     component_string, scsidevice);
430    
431     snprintf(component_string,
432     sizeof(component_string),
433     "scsi(0)disk(%i)rdisk(0)", d->id);
434     arcbios_add_string_to_component(
435     component_string, scsidisk);
436     }
437     }
438    
439     d = d->next;
440     }
441     }
442    
443    
444     /*
445     * emul_machine_setup():
446     *
447     * o) Initialize the hardware (RAM, devices, CPUs, ...) which
448     * will be emulated in this machine.
449     *
450     * o) Load ROM code and/or other programs into emulated memory.
451     *
452     * o) Special hacks needed after programs have been loaded.
453     */
454     void emul_machine_setup(struct machine *m, int n_load, char **load_names,
455     int n_devices, char **device_names)
456     {
457     struct emul *emul;
458     struct cpu *cpu;
459     int i, iadd=4;
460     uint64_t addr, memory_amount, entrypoint = 0, gp = 0, toc = 0;
461     int byte_order;
462    
463     emul = m->emul;
464    
465     debug("machine \"%s\":\n", m->name);
466     debug_indentation(iadd);
467    
468     /* For userland-only, this decides which ARCH/cpu_name to use: */
469     if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
470     useremul_name_to_useremul(NULL, m->userland_emul,
471     &m->arch, &m->machine_name, &m->cpu_name);
472     if (m->arch == ARCH_NOARCH) {
473     printf("Unsupported userland emulation mode.\n");
474     exit(1);
475     }
476     }
477    
478     if (m->machine_type == MACHINE_NONE) {
479     fatal("No machine type specified?\n");
480     exit(1);
481     }
482    
483     m->cpu_family = cpu_family_ptr_by_number(m->arch);
484    
485     machine_memsize_fix(m);
486    
487     /*
488     * Create the system's memory:
489     *
490     * (Don't print the amount for userland-only emulation; the
491     * size doesn't matter.)
492     */
493     if (m->machine_type != MACHINE_USERLAND)
494     debug("memory: %i MB", m->physical_ram_in_mb);
495     memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
496     if (m->memory_offset_in_mb > 0) {
497     /*
498     * A special hack is used for some SGI models,
499     * where memory is offset by 128MB to leave room for
500     * EISA space and other things.
501     */
502     debug(" (offset by %iMB)", m->memory_offset_in_mb);
503     memory_amount += 1048576 * m->memory_offset_in_mb;
504     }
505     m->memory = memory_new(memory_amount);
506     if (m->machine_type != MACHINE_USERLAND)
507     debug("\n");
508    
509     /* Create CPUs: */
510     if (m->cpu_name == NULL)
511     machine_default_cputype(m);
512     if (m->ncpus == 0) {
513     /* TODO: This should be moved elsewhere... */
514     if (m->machine_type == MACHINE_BEBOX)
515     m->ncpus = 2;
516     else if (m->machine_type == MACHINE_ARC &&
517     m->machine_subtype == MACHINE_ARC_NEC_R96)
518     m->ncpus = 2;
519     else if (m->machine_type == MACHINE_ARC &&
520     m->machine_subtype == MACHINE_ARC_NEC_R98)
521     m->ncpus = 4;
522     else
523     m->ncpus = 1;
524     }
525     m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);
526     if (m->cpus == NULL) {
527     fprintf(stderr, "out of memory\n");
528     exit(1);
529     }
530     memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
531    
532     /* Initialize dynamic binary translation, if available: */
533     if (m->bintrans_enable)
534     bintrans_init(m, m->memory);
535    
536     debug("cpu0");
537     if (m->ncpus > 1)
538     debug(" .. cpu%i", m->ncpus - 1);
539     debug(": ");
540     for (i=0; i<m->ncpus; i++) {
541     m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
542     if (m->bintrans_enable)
543     bintrans_init_cpu(m->cpus[i]);
544     }
545     debug("\n");
546    
547     if (m->use_random_bootstrap_cpu)
548     m->bootstrap_cpu = random() % m->ncpus;
549     else
550     m->bootstrap_cpu = 0;
551    
552     cpu = m->cpus[m->bootstrap_cpu];
553    
554     /* Set cpu->useremul_syscall, and use userland_memory_rw: */
555     if (m->userland_emul != NULL) {
556     useremul_name_to_useremul(cpu,
557     m->userland_emul, NULL, NULL, NULL);
558     cpu->memory_rw = userland_memory_rw;
559     }
560    
561     if (m->use_x11)
562     x11_init(m);
563    
564     /* Fill memory with random bytes: */
565     /* TODO: This is MIPS-specific! */
566     if (m->random_mem_contents) {
567     for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
568     unsigned char data[256];
569     unsigned int j;
570     for (j=0; j<sizeof(data); j++)
571     data[j] = random() & 255;
572     addr = 0xffffffff80000000ULL + i;
573     cpu->memory_rw(cpu, m->memory, addr, data, sizeof(data),
574     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
575     }
576     }
577    
578     if ((m->machine_type == MACHINE_ARC ||
579     m->machine_type == MACHINE_SGI) && m->prom_emulation)
580     arcbios_init();
581    
582     if (m->userland_emul != NULL) {
583     /*
584     * For userland-only emulation, no machine emulation
585     * is needed.
586     */
587     } else {
588     for (i=0; i<n_devices; i++)
589     device_add(m, device_names[i]);
590    
591     machine_setup(m);
592     }
593    
594     diskimage_dump_info(m);
595    
596     /* Load files (ROM code, boot code, ...) into memory: */
597     if (n_load == 0) {
598     if (m->first_diskimage != NULL)
599     load_bootblock(m, cpu);
600     else {
601     fprintf(stderr, "No executable file(s) loaded, and "
602     "we are not booting directly from a disk image."
603     "\nAborting.\n");
604     exit(1);
605     }
606     }
607    
608     while (n_load > 0) {
609     byte_order = NO_BYTE_ORDER_OVERRIDE;
610    
611     file_load(m, m->memory, *load_names, &entrypoint,
612     m->arch, &gp, &byte_order, &toc);
613    
614     if (byte_order != NO_BYTE_ORDER_OVERRIDE)
615     cpu->byte_order = byte_order;
616    
617     cpu->pc = entrypoint;
618    
619     switch (m->arch) {
620     case ARCH_MIPS:
621     if ((cpu->pc >> 32) == 0
622     && (cpu->pc & 0x80000000ULL))
623     cpu->pc |= 0xffffffff00000000ULL;
624    
625     cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
626    
627     if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
628     (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
629     cpu->cd.mips.gpr[MIPS_GPR_GP] |=
630     0xffffffff00000000ULL;
631     break;
632 dpavlin 4
633 dpavlin 2 case ARCH_PPC:
634     cpu->cd.ppc.gpr[2] = toc;
635     break;
636 dpavlin 4
637     case ARCH_ALPHA:
638     case ARCH_HPPA:
639 dpavlin 2 case ARCH_SPARC:
640     case ARCH_URISC:
641     break;
642 dpavlin 4
643     case ARCH_X86:
644     /*
645     * NOTE: The toc field is used to indicate an ELF64
646     * load, on AMD64!
647     */
648     if (toc != 0) {
649     cpu->cd.x86.mode = 64;
650     } else
651     cpu->pc &= 0xffffffffULL;
652 dpavlin 2 break;
653 dpavlin 4
654 dpavlin 2 default:
655     fatal("emul_machine_setup(): Internal error: "
656     "Unimplemented arch %i\n", m->arch);
657     exit(1);
658     }
659    
660     /*
661     * For userland emulation, the remaining items
662     * on the command line will be passed as parameters
663     * to the emulated program, and will not be treated
664     * as filenames to load into the emulator.
665     * The program's name will be in load_names[0], and the
666     * rest of the parameters in load_names[1] and up.
667     */
668     if (m->userland_emul != NULL)
669     break;
670    
671     n_load --;
672     load_names ++;
673     }
674    
675     if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
676     cpu->byte_order = m->byte_order_override;
677    
678     /* Same byte order and entrypoint for all CPUs: */
679     for (i=0; i<m->ncpus; i++)
680     if (i != m->bootstrap_cpu) {
681     m->cpus[i]->byte_order = cpu->byte_order;
682     m->cpus[i]->pc = cpu->pc;
683     }
684    
685     if (m->userland_emul != NULL)
686     useremul_setup(cpu, n_load, load_names);
687    
688     /* Startup the bootstrap CPU: */
689     cpu->bootstrap_cpu_flag = 1;
690     cpu->running = 1;
691    
692     /* ... or pause all CPUs, if start_paused is set: */
693     if (m->start_paused) {
694     for (i=0; i<m->ncpus; i++)
695     m->cpus[i]->running = 0;
696     }
697    
698     /* Add PC dump points: */
699     add_dump_points(m);
700    
701     /* TODO: This is MIPS-specific! */
702     if (m->machine_type == MACHINE_DEC &&
703     cpu->cd.mips.cpu_type.mmu_model == MMU3K)
704     add_symbol_name(&m->symbol_context,
705     0x9fff0000, 0x10000, "r2k3k_cache", 0);
706    
707     symbol_recalc_sizes(&m->symbol_context);
708    
709     if (m->max_random_cycles_per_chunk > 0)
710     debug("using random cycle chunks (1 to %i cycles)\n",
711     m->max_random_cycles_per_chunk);
712    
713     /* Special hack for ARC/SGI emulation: */
714     if ((m->machine_type == MACHINE_ARC ||
715     m->machine_type == MACHINE_SGI) && m->prom_emulation)
716     add_arc_components(m);
717    
718     debug("starting cpu%i at ", m->bootstrap_cpu);
719     switch (m->arch) {
720     case ARCH_MIPS:
721     if (cpu->cd.mips.cpu_type.isa_level < 3 ||
722     cpu->cd.mips.cpu_type.isa_level == 32) {
723     debug("0x%08x", (int)m->cpus[
724     m->bootstrap_cpu]->pc);
725     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
726     debug(" (gp=0x%08x)", (int)m->cpus[
727     m->bootstrap_cpu]->cd.mips.gpr[
728     MIPS_GPR_GP]);
729     } else {
730     debug("0x%016llx", (long long)m->cpus[
731     m->bootstrap_cpu]->pc);
732     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
733     debug(" (gp=0x%016llx)", (long long)
734     cpu->cd.mips.gpr[MIPS_GPR_GP]);
735     }
736     break;
737     case ARCH_PPC:
738     if (cpu->cd.ppc.bits == 32)
739     debug("0x%08x", (int)entrypoint);
740     else
741     debug("0x%016llx", (long long)entrypoint);
742     break;
743     case ARCH_URISC:
744     {
745     char tmps[100];
746     unsigned char buf[sizeof(uint64_t)];
747    
748     cpu->memory_rw(cpu, m->memory, 0, buf, sizeof(buf),
749     MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
750    
751     entrypoint = 0;
752     for (i=0; i<cpu->cd.urisc.wordlen/8; i++) {
753     entrypoint <<= 8;
754     if (cpu->byte_order == EMUL_BIG_ENDIAN)
755     entrypoint += buf[i];
756     else
757     entrypoint += buf[cpu->
758     cd.urisc.wordlen/8 - 1 - i];
759     }
760    
761     sprintf(tmps, "0x%%0%illx", cpu->cd.urisc.wordlen / 4);
762     debug(tmps, (long long)entrypoint);
763     cpu->pc = entrypoint;
764     }
765     break;
766 dpavlin 4 case ARCH_X86:
767     if (cpu->cd.x86.mode == 16)
768     debug("0x%04x:0x%04x", cpu->cd.x86.s[X86_S_CS],
769     (int)cpu->pc);
770     else if (cpu->cd.x86.mode == 32)
771     debug("0x%08x", (int)cpu->pc);
772     else
773     debug("0x%016llx", (long long)cpu->pc);
774     break;
775 dpavlin 2 default:
776 dpavlin 4 debug("0x%016llx", (long long)cpu->pc);
777 dpavlin 2 }
778     debug("\n");
779    
780     debug_indentation(-iadd);
781     }
782    
783    
784     /*
785     * emul_dumpinfo():
786     *
787     * Dump info about all machines in an emul.
788     */
789     void emul_dumpinfo(struct emul *e)
790     {
791     int j, nm, iadd = 4;
792    
793     if (e->net != NULL)
794     net_dumpinfo(e->net);
795    
796     nm = e->n_machines;
797     for (j=0; j<nm; j++) {
798     debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
799     debug_indentation(iadd);
800     machine_dumpinfo(e->machines[j]);
801     debug_indentation(-iadd);
802     }
803     }
804    
805    
806     /*
807     * emul_simple_init():
808     *
809     * For a normal setup:
810     *
811     * o) Initialize a network.
812     * o) Initialize one machine.
813     *
814     * For a userland-only setup:
815     *
816     * o) Initialize a "pseudo"-machine.
817     */
818     void emul_simple_init(struct emul *emul)
819     {
820     int iadd=4;
821     struct machine *m;
822    
823     if (emul->n_machines != 1) {
824     fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
825     exit(1);
826     }
827    
828     m = emul->machines[0];
829    
830     if (m->userland_emul == NULL) {
831     debug("Simple setup...\n");
832     debug_indentation(iadd);
833    
834     /* Create a network: */
835     emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
836     "10.0.0.0", 8);
837     } else {
838     /* Userland pseudo-machine: */
839     debug("Syscall emulation (userland-only) setup...\n");
840     debug_indentation(iadd);
841     }
842    
843     /* Create the machine: */
844     emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
845    
846     debug_indentation(-iadd);
847     }
848    
849    
850     /*
851     * emul_create_from_configfile():
852     *
853     * Create an emul struct by reading settings from a configuration file.
854     */
855     struct emul *emul_create_from_configfile(char *fname)
856     {
857     int iadd = 4;
858     struct emul *e = emul_new(fname);
859     FILE *f;
860     char buf[128];
861     size_t len;
862    
863     debug("Creating emulation from configfile \"%s\":\n", fname);
864     debug_indentation(iadd);
865    
866     f = fopen(fname, "r");
867     if (f == NULL) {
868     perror(fname);
869     exit(1);
870     }
871    
872     /* Read header: (must be !!gxemul) */
873     len = fread(buf, 1, 8, f);
874     if (len != 8 || strncmp(buf, "!!gxemul", 8) != 0) {
875     fprintf(stderr, "%s: must start with '!!gxemul'\n", fname);
876     exit(1);
877     }
878    
879     /* Restart from beginning: */
880     rewind(f);
881    
882     emul_parse_config(e, f);
883    
884     fclose(f);
885     debug_indentation(-iadd);
886     return e;
887     }
888    
889    
890     /*
891     * emul_run():
892     *
893     * o) Set up things needed before running emulations.
894     *
895     * o) Run emulations (one or more, in parallel).
896     *
897     * o) De-initialize things.
898     */
899     void emul_run(struct emul **emuls, int n_emuls)
900     {
901     struct emul *e;
902     int i = 0, j, go = 1, n, anything;
903    
904     if (n_emuls < 1) {
905     fprintf(stderr, "emul_run(): no thing to do\n");
906     return;
907     }
908    
909     atexit(fix_console);
910    
911     i = 79;
912     while (i-- > 0)
913     debug("-");
914     debug("\n\n");
915    
916     /* Initialize the interactive debugger: */
917     debugger_init(emuls, n_emuls);
918    
919     /*
920     * console_init_main() makes sure that the terminal is in a
921     * reasonable state.
922     *
923     * The SIGINT handler is for CTRL-C (enter the interactive debugger).
924     *
925     * The SIGCONT handler is invoked whenever the user presses CTRL-Z
926     * (or sends SIGSTOP) and then continues. It makes sure that the
927     * terminal is in an expected state.
928     */
929     console_init_main(emuls[0]); /* TODO: what is a good argument? */
930     signal(SIGINT, debugger_activate);
931     signal(SIGCONT, console_sigcont);
932    
933     /* Not in verbose mode? Then set quiet_mode. */
934     if (!verbose)
935     quiet_mode = 1;
936    
937     /* Initialize all CPUs in all machines in all emulations: */
938     for (i=0; i<n_emuls; i++) {
939     e = emuls[i];
940     if (e == NULL)
941     continue;
942     for (j=0; j<e->n_machines; j++)
943     cpu_run_init(e, e->machines[j]);
944     }
945    
946     /*
947     * MAIN LOOP:
948     *
949     * Run all emulations in parallel, running each machine in
950     * each emulation.
951     */
952     while (go) {
953     go = 0;
954    
955     x11_check_event(emuls, n_emuls);
956    
957     for (i=0; i<n_emuls; i++) {
958     e = emuls[i];
959     if (e == NULL)
960     continue;
961    
962     for (j=0; j<e->n_machines; j++) {
963     /* TODO: cpu_run() is a strange name, since
964     there can be multiple cpus in a machine */
965     anything = cpu_run(e, e->machines[j]);
966     if (anything)
967     go = 1;
968     }
969     }
970     }
971    
972     /* Deinitialize all CPUs in all machines in all emulations: */
973     for (i=0; i<n_emuls; i++) {
974     e = emuls[i];
975     if (e == NULL)
976     continue;
977     for (j=0; j<e->n_machines; j++)
978     cpu_run_deinit(e, e->machines[j]);
979     }
980    
981     /* force_debugger_at_exit flag set? Then enter the debugger: */
982     if (force_debugger_at_exit) {
983     quiet_mode = 0;
984     debugger_reset();
985     debugger();
986     }
987    
988     /* Any machine using X11? Then we should wait before exiting: */
989     n = 0;
990     for (i=0; i<n_emuls; i++)
991     for (j=0; j<emuls[i]->n_machines; j++)
992     if (emuls[i]->machines[j]->use_x11)
993     n++;
994     if (n > 0) {
995     printf("Press enter to quit.\n");
996     while (!console_charavail(MAIN_CONSOLE)) {
997     x11_check_event(emuls, n_emuls);
998     usleep(1);
999     }
1000     console_readchar(MAIN_CONSOLE);
1001     }
1002    
1003     console_deinit();
1004     }
1005    

  ViewVC Help
Powered by ViewVC 1.1.26