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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 45 - (show annotations)
Mon Oct 8 16:23:07 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 23788 byte(s)
20070918
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