/[gxemul]/trunk/src/emul.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 5 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 /*
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 * $Id: emul.c,v 1.184 2005/04/20 04:43:52 debug Exp $
29 *
30 * Emulation startup and misc. routines.
31 */
32
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "arcbios.h"
42 #include "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
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 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
633 case ARCH_PPC:
634 cpu->cd.ppc.gpr[2] = toc;
635 break;
636
637 case ARCH_ALPHA:
638 case ARCH_HPPA:
639 case ARCH_SPARC:
640 case ARCH_URISC:
641 break;
642
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 break;
653
654 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 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 default:
776 debug("0x%016llx", (long long)cpu->pc);
777 }
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