/[gxemul]/upstream/0.4.6/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 /upstream/0.4.6/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26