/[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 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 23788 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26