/[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 36 - (show annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 26990 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


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.279 2007/03/16 14:45:30 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 "sgi_arcbios.h"
56 #include "timer.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 extern struct emul *debugger_emul;
73 extern struct diskimage *diskimages[];
74
75
76 static void print_separator(void)
77 {
78 int i = 79;
79 while (i-- > 0)
80 debug("-");
81 debug("\n");
82 }
83
84
85 /*
86 * add_dump_points():
87 *
88 * Take the strings breakpoint_string[] and convert to addresses
89 * (and store them in breakpoint_addr[]).
90 *
91 * TODO: This function should be moved elsewhere.
92 */
93 static void add_dump_points(struct machine *m)
94 {
95 int i;
96 int string_flag;
97 uint64_t dp;
98
99 for (i=0; i<m->n_breakpoints; i++) {
100 string_flag = 0;
101 dp = strtoull(m->breakpoint_string[i], NULL, 0);
102
103 /*
104 * If conversion resulted in 0, then perhaps it is a
105 * symbol:
106 */
107 if (dp == 0) {
108 uint64_t addr;
109 int res = get_symbol_addr(&m->symbol_context,
110 m->breakpoint_string[i], &addr);
111 if (!res) {
112 fprintf(stderr,
113 "ERROR! Breakpoint '%s' could not be"
114 " parsed\n",
115 m->breakpoint_string[i]);
116 } else {
117 dp = addr;
118 string_flag = 1;
119 }
120 }
121
122 /*
123 * TODO: It would be nice if things like symbolname+0x1234
124 * were automatically converted into the correct address.
125 */
126
127 if (m->arch == ARCH_MIPS) {
128 if ((dp >> 32) == 0 && ((dp >> 31) & 1))
129 dp |= 0xffffffff00000000ULL;
130 }
131
132 m->breakpoint_addr[i] = dp;
133
134 debug("breakpoint %i: 0x%llx", i, (long long)dp);
135 if (string_flag)
136 debug(" (%s)", m->breakpoint_string[i]);
137 debug("\n");
138 }
139 }
140
141
142 /*
143 * fix_console():
144 */
145 static void fix_console(void)
146 {
147 console_deinit_main();
148 }
149
150
151 /*
152 * emul_new():
153 *
154 * Returns a reasonably initialized struct emul.
155 */
156 struct emul *emul_new(char *name, int id)
157 {
158 struct emul *e;
159 e = malloc(sizeof(struct emul));
160 if (e == NULL) {
161 fprintf(stderr, "out of memory in emul_new()\n");
162 exit(1);
163 }
164
165 memset(e, 0, sizeof(struct emul));
166
167 e->path = malloc(15);
168 if (e->path == NULL) {
169 fprintf(stderr, "out of memory\n");
170 exit(1);
171 }
172 snprintf(e->path, 15, "emul[%i]", id);
173
174 e->settings = settings_new();
175
176 settings_add(e->settings, "n_machines", 0,
177 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
178 (void *) &e->n_machines);
179
180 /* TODO: More settings? */
181
182 /* Sane default values: */
183 e->n_machines = 0;
184 e->next_serial_nr = 1;
185
186 if (name != NULL) {
187 e->name = strdup(name);
188 if (e->name == NULL) {
189 fprintf(stderr, "out of memory in emul_new()\n");
190 exit(1);
191 }
192
193 settings_add(e->settings, "name", 0,
194 SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
195 (void *) &e->name);
196 }
197
198 return e;
199 }
200
201
202 /*
203 * emul_destroy():
204 *
205 * Destroys a previously created emul object.
206 */
207 void emul_destroy(struct emul *emul)
208 {
209 int i;
210
211 if (emul->name != NULL) {
212 settings_remove(emul->settings, "name");
213 free(emul->name);
214 }
215
216 for (i=0; i<emul->n_machines; i++)
217 machine_destroy(emul->machines[i]);
218
219 if (emul->machines != NULL)
220 free(emul->machines);
221
222 /* Remove any remaining level-1 settings: */
223 settings_remove_all(emul->settings);
224 settings_destroy(emul->settings);
225
226 free(emul);
227 }
228
229
230 /*
231 * emul_add_machine():
232 *
233 * Calls machine_new(), adds the new machine into the emul struct, and
234 * returns a pointer to the new machine.
235 *
236 * This function should be used instead of manually calling machine_new().
237 */
238 struct machine *emul_add_machine(struct emul *e, char *name)
239 {
240 struct machine *m;
241 char tmpstr[20];
242 int i;
243
244 m = machine_new(name, e, e->n_machines);
245 m->serial_nr = (e->next_serial_nr ++);
246
247 i = e->n_machines;
248
249 e->n_machines ++;
250 e->machines = realloc(e->machines,
251 sizeof(struct machine *) * e->n_machines);
252 if (e->machines == NULL) {
253 fprintf(stderr, "emul_add_machine(): out of memory\n");
254 exit(1);
255 }
256
257 e->machines[i] = m;
258
259 snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
260 settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
261 e->machines[i]->settings);
262
263 return m;
264 }
265
266
267 /*
268 * add_arc_components():
269 *
270 * This function adds ARCBIOS memory descriptors for the loaded program,
271 * and ARCBIOS components for SCSI devices.
272 */
273 static void add_arc_components(struct machine *m)
274 {
275 struct cpu *cpu = m->cpus[m->bootstrap_cpu];
276 uint64_t start = cpu->pc & 0x1fffffff;
277 uint64_t len = 0xc00000 - start;
278 struct diskimage *d;
279 uint64_t scsicontroller, scsidevice, scsidisk;
280
281 if ((cpu->pc >> 60) != 0xf) {
282 start = cpu->pc & 0xffffffffffULL;
283 len = 0xc00000 - start;
284 }
285
286 len += 1048576 * m->memory_offset_in_mb;
287
288 /*
289 * NOTE/TODO: magic 12MB end of load program area
290 *
291 * Hm. This breaks the old FreeBSD/MIPS snapshots...
292 */
293 #if 0
294 arcbios_add_memory_descriptor(cpu,
295 0x60000 + m->memory_offset_in_mb * 1048576,
296 start-0x60000 - m->memory_offset_in_mb * 1048576,
297 ARCBIOS_MEM_FreeMemory);
298 #endif
299 arcbios_add_memory_descriptor(cpu,
300 start, len, ARCBIOS_MEM_LoadedProgram);
301
302 scsicontroller = arcbios_get_scsicontroller(m);
303 if (scsicontroller == 0)
304 return;
305
306 /* TODO: The device 'name' should defined be somewhere else. */
307
308 d = m->first_diskimage;
309 while (d != NULL) {
310 if (d->type == DISKIMAGE_SCSI) {
311 int a, b, flags = COMPONENT_FLAG_Input;
312 char component_string[100];
313 char *name = "DEC RZ58 (C) DEC2000";
314
315 /* Read-write, or read-only? */
316 if (d->writable)
317 flags |= COMPONENT_FLAG_Output;
318 else
319 flags |= COMPONENT_FLAG_ReadOnly;
320
321 a = COMPONENT_TYPE_DiskController;
322 b = COMPONENT_TYPE_DiskPeripheral;
323
324 if (d->is_a_cdrom) {
325 flags |= COMPONENT_FLAG_Removable;
326 a = COMPONENT_TYPE_CDROMController;
327 b = COMPONENT_TYPE_FloppyDiskPeripheral;
328 name = "NEC CD-ROM CDR-210P 1.0 ";
329 }
330
331 scsidevice = arcbios_addchild_manual(cpu,
332 COMPONENT_CLASS_ControllerClass,
333 a, flags, 1, 2, d->id, 0xffffffff,
334 name, scsicontroller, NULL, 0);
335
336 scsidisk = arcbios_addchild_manual(cpu,
337 COMPONENT_CLASS_PeripheralClass,
338 b, flags, 1, 2, 0, 0xffffffff, NULL,
339 scsidevice, NULL, 0);
340
341 /*
342 * Add device string to component address mappings:
343 * "scsi(0)disk(0)rdisk(0)partition(0)"
344 */
345
346 if (d->is_a_cdrom) {
347 snprintf(component_string,
348 sizeof(component_string),
349 "scsi(0)cdrom(%i)", d->id);
350 arcbios_add_string_to_component(m,
351 component_string, scsidevice);
352
353 snprintf(component_string,
354 sizeof(component_string),
355 "scsi(0)cdrom(%i)fdisk(0)", d->id);
356 arcbios_add_string_to_component(m,
357 component_string, scsidisk);
358 } else {
359 snprintf(component_string,
360 sizeof(component_string),
361 "scsi(0)disk(%i)", d->id);
362 arcbios_add_string_to_component(m,
363 component_string, scsidevice);
364
365 snprintf(component_string,
366 sizeof(component_string),
367 "scsi(0)disk(%i)rdisk(0)", d->id);
368 arcbios_add_string_to_component(m,
369 component_string, scsidisk);
370 }
371 }
372
373 d = d->next;
374 }
375 }
376
377
378 /*
379 * emul_machine_setup():
380 *
381 * o) Initialize the hardware (RAM, devices, CPUs, ...) which
382 * will be emulated in this machine.
383 *
384 * o) Load ROM code and/or other programs into emulated memory.
385 *
386 * o) Special hacks needed after programs have been loaded.
387 */
388 void emul_machine_setup(struct machine *m, int n_load, char **load_names,
389 int n_devices, char **device_names)
390 {
391 struct cpu *cpu;
392 int i, iadd = DEBUG_INDENTATION;
393 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
394 int byte_order;
395
396 debug("machine \"%s\":\n", m->name);
397 debug_indentation(iadd);
398
399 /* For userland-only, this decides which ARCH/cpu_name to use: */
400 if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
401 useremul_name_to_useremul(NULL, m->userland_emul,
402 &m->arch, &m->machine_name, &m->cpu_name);
403 if (m->arch == ARCH_NOARCH) {
404 printf("Unsupported userland emulation mode.\n");
405 exit(1);
406 }
407 }
408
409 if (m->machine_type == MACHINE_NONE) {
410 fatal("No machine type specified?\n");
411 exit(1);
412 }
413
414 m->cpu_family = cpu_family_ptr_by_number(m->arch);
415
416 if (m->arch == ARCH_ALPHA)
417 m->arch_pagesize = 8192;
418
419 machine_memsize_fix(m);
420
421 /*
422 * Create the system's memory:
423 *
424 * (Don't print the amount for userland-only emulation; the
425 * size doesn't matter.)
426 */
427 if (m->machine_type != MACHINE_USERLAND)
428 debug("memory: %i MB", m->physical_ram_in_mb);
429 memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
430 if (m->memory_offset_in_mb > 0) {
431 /*
432 * A special hack is used for some SGI models,
433 * where memory is offset by 128MB to leave room for
434 * EISA space and other things.
435 */
436 debug(" (offset by %iMB)", m->memory_offset_in_mb);
437 memory_amount += 1048576 * m->memory_offset_in_mb;
438 }
439 m->memory = memory_new(memory_amount, m->arch);
440 if (m->machine_type != MACHINE_USERLAND)
441 debug("\n");
442
443 /* Create CPUs: */
444 if (m->cpu_name == NULL)
445 machine_default_cputype(m);
446 if (m->ncpus == 0) {
447 /* TODO: This should be moved elsewhere... */
448 if (m->machine_type == MACHINE_BEBOX)
449 m->ncpus = 2;
450 else if (m->machine_type == MACHINE_ARC &&
451 m->machine_subtype == MACHINE_ARC_NEC_R96)
452 m->ncpus = 2;
453 else if (m->machine_type == MACHINE_ARC &&
454 m->machine_subtype == MACHINE_ARC_NEC_R98)
455 m->ncpus = 4;
456 else
457 m->ncpus = 1;
458 }
459 m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);
460 if (m->cpus == NULL) {
461 fprintf(stderr, "out of memory\n");
462 exit(1);
463 }
464 memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
465
466 debug("cpu0");
467 if (m->ncpus > 1)
468 debug(" .. cpu%i", m->ncpus - 1);
469 debug(": ");
470 for (i=0; i<m->ncpus; i++) {
471 m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
472 if (m->cpus[i] == NULL) {
473 fprintf(stderr, "Unable to create CPU object. "
474 "Aborting.");
475 exit(1);
476 }
477 }
478 debug("\n");
479
480 #if 0
481 /* Special case: The Playstation Portable has an additional CPU: */
482 if (m->machine_type == MACHINE_PSP) {
483 debug("cpu%i: ", m->ncpus);
484 m->cpus[m->ncpus] = cpu_new(m->memory, m,
485 0 /* use 0 here to show info with debug() */,
486 "Allegrex" /* TODO */);
487 debug("\n");
488 m->ncpus ++;
489 }
490 #endif
491
492 if (m->use_random_bootstrap_cpu)
493 m->bootstrap_cpu = random() % m->ncpus;
494 else
495 m->bootstrap_cpu = 0;
496
497 cpu = m->cpus[m->bootstrap_cpu];
498
499 /* Set cpu->useremul_syscall, and use userland_memory_rw: */
500 if (m->userland_emul != NULL) {
501 useremul_name_to_useremul(cpu,
502 m->userland_emul, NULL, NULL, NULL);
503
504 switch (m->arch) {
505 #ifdef ENABLE_ALPHA
506 case ARCH_ALPHA:
507 cpu->memory_rw = alpha_userland_memory_rw;
508 break;
509 #endif
510 default:cpu->memory_rw = userland_memory_rw;
511 }
512 }
513
514 if (m->use_x11)
515 x11_init(m);
516
517 /* Fill memory with random bytes: */
518 if (m->random_mem_contents) {
519 for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
520 unsigned char data[256];
521 unsigned int j;
522 for (j=0; j<sizeof(data); j++)
523 data[j] = random() & 255;
524 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
525 MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
526 }
527 }
528
529 if (m->userland_emul != NULL) {
530 /*
531 * For userland-only emulation, no machine emulation
532 * is needed.
533 */
534 } else {
535 for (i=0; i<n_devices; i++)
536 device_add(m, device_names[i]);
537
538 machine_setup(m);
539 }
540
541 diskimage_dump_info(m);
542 console_debug_dump(m);
543
544 /* Load files (ROM code, boot code, ...) into memory: */
545 if (n_load == 0) {
546 if (m->first_diskimage != NULL) {
547 if (!load_bootblock(m, cpu, &n_load, &load_names)) {
548 fprintf(stderr, "\nNo executable files were"
549 " specified, and booting directly from disk"
550 " failed.\n");
551 exit(1);
552 }
553 } else {
554 fprintf(stderr, "No executable file(s) loaded, and "
555 "we are not booting directly from a disk image."
556 "\nAborting.\n");
557 exit(1);
558 }
559 }
560
561 while (n_load > 0) {
562 FILE *tmp_f;
563 char *name_to_load = *load_names;
564 int remove_after_load = 0;
565
566 /* Special hack for removing temporary files: */
567 if (name_to_load[0] == 8) {
568 name_to_load ++;
569 remove_after_load = 1;
570 }
571
572 /*
573 * gzipped files are automagically gunzipped:
574 * NOTE/TODO: This isn't secure. system() is used.
575 */
576 tmp_f = fopen(name_to_load, "r");
577 if (tmp_f != NULL) {
578 unsigned char buf[2]; /* gzip header */
579 memset(buf, 0, sizeof(buf));
580 fread(buf, 1, sizeof(buf), tmp_f);
581 if (buf[0]==0x1f && buf[1]==0x8b) {
582 size_t zzlen = strlen(name_to_load)*2 + 100;
583 char *zz = malloc(zzlen);
584 debug("gunziping %s\n", name_to_load);
585 /*
586 * gzip header found. If this was a file
587 * extracted from, say, a CDROM image, then it
588 * already has a temporary name. Otherwise we
589 * have to gunzip into a temporary file.
590 */
591 if (remove_after_load) {
592 snprintf(zz, zzlen, "mv %s %s.gz",
593 name_to_load, name_to_load);
594 system(zz);
595 snprintf(zz, zzlen, "gunzip %s.gz",
596 name_to_load);
597 system(zz);
598 } else {
599 /* gunzip into new temp file: */
600 int tmpfile_handle;
601 char *new_temp_name =
602 strdup("/tmp/gxemul.XXXXXXXXXXXX");
603 tmpfile_handle = mkstemp(new_temp_name);
604 close(tmpfile_handle);
605 snprintf(zz, zzlen, "gunzip -c '%s' > "
606 "%s", name_to_load, new_temp_name);
607 system(zz);
608 name_to_load = new_temp_name;
609 remove_after_load = 1;
610 }
611 free(zz);
612 }
613 fclose(tmp_f);
614 }
615
616 /*
617 * Ugly (but usable) hack for Playstation Portable: If the
618 * filename ends with ".pbp" and the file contains an ELF
619 * header, then extract the ELF file into a temporary file.
620 */
621 if (strlen(name_to_load) > 4 && strcasecmp(name_to_load +
622 strlen(name_to_load) - 4, ".pbp") == 0 &&
623 (tmp_f = fopen(name_to_load, "r")) != NULL) {
624 off_t filesize, j, found=0;
625 unsigned char *buf;
626 fseek(tmp_f, 0, SEEK_END);
627 filesize = ftello(tmp_f);
628 fseek(tmp_f, 0, SEEK_SET);
629 buf = malloc(filesize);
630 if (buf == NULL) {
631 fprintf(stderr, "out of memory while trying"
632 " to read %s\n", name_to_load);
633 exit(1);
634 }
635 fread(buf, 1, filesize, tmp_f);
636 fclose(tmp_f);
637 /* Search for the ELF header, from offset 1 (!): */
638 for (j=1; j<filesize - 4; j++)
639 if (memcmp(buf + j, ELFMAG, SELFMAG) == 0) {
640 found = j;
641 break;
642 }
643 if (found != 0) {
644 int tmpfile_handle;
645 char *new_temp_name =
646 strdup("/tmp/gxemul.XXXXXXXXXXXX");
647 debug("extracting ELF from %s (offset 0x%x)\n",
648 name_to_load, (int)found);
649 tmpfile_handle = mkstemp(new_temp_name);
650 write(tmpfile_handle, buf + found,
651 filesize - found);
652 close(tmpfile_handle);
653 name_to_load = new_temp_name;
654 remove_after_load = 1;
655 }
656 }
657
658 byte_order = NO_BYTE_ORDER_OVERRIDE;
659
660 /*
661 * Load the file: :-)
662 */
663 file_load(m, m->memory, name_to_load, &entrypoint,
664 m->arch, &gp, &byte_order, &toc);
665
666 if (remove_after_load) {
667 debug("removing %s\n", name_to_load);
668 unlink(name_to_load);
669 }
670
671 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
672 cpu->byte_order = byte_order;
673
674 cpu->pc = entrypoint;
675
676 switch (m->arch) {
677
678 case ARCH_ALPHA:
679 /* For position-independent code: */
680 cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
681 break;
682
683 case ARCH_ARM:
684 if (cpu->pc & 3) {
685 fatal("ARM: lowest bits of pc set: TODO\n");
686 exit(1);
687 }
688 cpu->pc &= 0xfffffffc;
689 break;
690
691 case ARCH_AVR:
692 cpu->pc &= 0xfffff;
693 if (cpu->pc & 1) {
694 fatal("AVR: lowest bit of pc set: TODO\n");
695 exit(1);
696 }
697 break;
698
699 case ARCH_RCA180X:
700 cpu->pc &= 0xffff;
701 break;
702
703 case ARCH_M68K:
704 break;
705
706 case ARCH_MIPS:
707 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
708 cpu->pc |= 0xffffffff00000000ULL;
709
710 cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
711
712 if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
713 (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
714 cpu->cd.mips.gpr[MIPS_GPR_GP] |=
715 0xffffffff00000000ULL;
716 break;
717
718 case ARCH_PPC:
719 /* See http://www.linuxbase.org/spec/ELF/ppc64/
720 spec/x458.html for more info. */
721 cpu->cd.ppc.gpr[2] = toc;
722 /* TODO */
723 if (cpu->cd.ppc.bits == 32)
724 cpu->pc &= 0xffffffffULL;
725 break;
726
727 case ARCH_SH:
728 if (cpu->cd.sh.cpu_type.bits == 32)
729 cpu->pc &= 0xffffffffULL;
730 cpu->pc &= ~1;
731 break;
732
733 case ARCH_SPARC:
734 break;
735
736 case ARCH_TRANSPUTER:
737 cpu->pc &= 0xffffffffULL;
738 break;
739
740 default:
741 fatal("emul_machine_setup(): Internal error: "
742 "Unimplemented arch %i\n", m->arch);
743 exit(1);
744 }
745
746 /*
747 * For userland emulation, the remaining items
748 * on the command line will be passed as parameters
749 * to the emulated program, and will not be treated
750 * as filenames to load into the emulator.
751 * The program's name will be in load_names[0], and the
752 * rest of the parameters in load_names[1] and up.
753 */
754 if (m->userland_emul != NULL)
755 break;
756
757 n_load --;
758 load_names ++;
759 }
760
761 if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
762 cpu->byte_order = m->byte_order_override;
763
764 /* Same byte order and entrypoint for all CPUs: */
765 for (i=0; i<m->ncpus; i++)
766 if (i != m->bootstrap_cpu) {
767 m->cpus[i]->byte_order = cpu->byte_order;
768 m->cpus[i]->pc = cpu->pc;
769 }
770
771 if (m->userland_emul != NULL)
772 useremul_setup(cpu, n_load, load_names);
773
774 /* Startup the bootstrap CPU: */
775 cpu->running = 1;
776
777 /* ... or pause all CPUs, if start_paused is set: */
778 if (m->start_paused) {
779 for (i=0; i<m->ncpus; i++)
780 m->cpus[i]->running = 0;
781 }
782
783 /* Add PC dump points: */
784 add_dump_points(m);
785
786 /* TODO: This is MIPS-specific! */
787 if (m->machine_type == MACHINE_PMAX &&
788 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
789 add_symbol_name(&m->symbol_context,
790 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
791
792 symbol_recalc_sizes(&m->symbol_context);
793
794 /* Special hack for ARC/SGI emulation: */
795 if ((m->machine_type == MACHINE_ARC ||
796 m->machine_type == MACHINE_SGI) && m->prom_emulation)
797 add_arc_components(m);
798
799 debug("starting cpu%i at ", m->bootstrap_cpu);
800 switch (m->arch) {
801
802 case ARCH_ARM:
803 /* ARM cpus aren't 64-bit: */
804 debug("0x%08x", (int)entrypoint);
805 break;
806
807 case ARCH_AVR:
808 /* Atmel AVR uses a 16-bit or 22-bit program counter: */
809 debug("0x%04x", (int)entrypoint);
810 break;
811
812 case ARCH_MIPS:
813 if (cpu->is_32bit) {
814 debug("0x%08x", (int)m->cpus[
815 m->bootstrap_cpu]->pc);
816 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
817 debug(" (gp=0x%08x)", (int)m->cpus[
818 m->bootstrap_cpu]->cd.mips.gpr[
819 MIPS_GPR_GP]);
820 } else {
821 debug("0x%016llx", (long long)m->cpus[
822 m->bootstrap_cpu]->pc);
823 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
824 debug(" (gp=0x%016llx)", (long long)
825 cpu->cd.mips.gpr[MIPS_GPR_GP]);
826 }
827 break;
828
829 case ARCH_PPC:
830 if (cpu->cd.ppc.bits == 32)
831 debug("0x%08x", (int)entrypoint);
832 else
833 debug("0x%016llx", (long long)entrypoint);
834 break;
835
836 default:
837 if (cpu->is_32bit)
838 debug("0x%08x", (int)cpu->pc);
839 else
840 debug("0x%016llx", (long long)cpu->pc);
841 }
842 debug("\n");
843
844 debug_indentation(-iadd);
845 }
846
847
848 /*
849 * emul_dumpinfo():
850 *
851 * Dump info about all machines in an emul.
852 */
853 void emul_dumpinfo(struct emul *e)
854 {
855 int j, nm, iadd = DEBUG_INDENTATION;
856
857 if (e->net != NULL)
858 net_dumpinfo(e->net);
859
860 nm = e->n_machines;
861 for (j=0; j<nm; j++) {
862 debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
863 debug_indentation(iadd);
864 machine_dumpinfo(e->machines[j]);
865 debug_indentation(-iadd);
866 }
867 }
868
869
870 /*
871 * emul_simple_init():
872 *
873 * For a normal setup:
874 *
875 * o) Initialize a network.
876 * o) Initialize one machine.
877 *
878 * For a userland-only setup:
879 *
880 * o) Initialize a "pseudo"-machine.
881 */
882 void emul_simple_init(struct emul *emul)
883 {
884 int iadd = DEBUG_INDENTATION;
885 struct machine *m;
886
887 if (emul->n_machines != 1) {
888 fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
889 exit(1);
890 }
891
892 m = emul->machines[0];
893
894 if (m->userland_emul == NULL) {
895 debug("Simple setup...\n");
896 debug_indentation(iadd);
897
898 /* Create a simple network: */
899 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
900 NET_DEFAULT_IPV4_MASK,
901 NET_DEFAULT_IPV4_LEN,
902 NULL, 0, 0, NULL);
903 } else {
904 /* Userland pseudo-machine: */
905 debug("Syscall emulation (userland-only) setup...\n");
906 debug_indentation(iadd);
907 }
908
909 /* Create the machine: */
910 emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
911
912 debug_indentation(-iadd);
913 }
914
915
916 /*
917 * emul_create_from_configfile():
918 *
919 * Create an emul struct by reading settings from a configuration file.
920 */
921 struct emul *emul_create_from_configfile(char *fname, int id)
922 {
923 int iadd = DEBUG_INDENTATION;
924 struct emul *e = emul_new(fname, id);
925
926 debug("Creating emulation from configfile \"%s\":\n", fname);
927 debug_indentation(iadd);
928
929 emul_parse_config(e, fname);
930
931 debug_indentation(-iadd);
932 return e;
933 }
934
935
936 /*
937 * emul_run():
938 *
939 * o) Set up things needed before running emulations.
940 *
941 * o) Run emulations (one or more, in parallel).
942 *
943 * o) De-initialize things.
944 */
945 void emul_run(struct emul **emuls, int n_emuls)
946 {
947 struct emul *e;
948 int i = 0, j, go = 1, n, anything;
949
950 if (n_emuls < 1) {
951 fprintf(stderr, "emul_run(): no thing to do\n");
952 return;
953 }
954
955 atexit(fix_console);
956
957 /* Initialize the interactive debugger: */
958 debugger_init(emuls, n_emuls);
959
960 /* Run any additional debugger commands before starting: */
961 for (i=0; i<n_emuls; i++) {
962 struct emul *emul = emuls[i];
963 if (emul->n_debugger_cmds > 0) {
964 int j;
965 if (i == 0)
966 print_separator();
967 for (j = 0; j < emul->n_debugger_cmds; j ++) {
968 debug("> %s\n", emul->debugger_cmds[j]);
969 debugger_execute_cmd(emul->debugger_cmds[j],
970 strlen(emul->debugger_cmds[j]));
971 }
972 }
973 }
974
975 print_separator();
976 debug("\n");
977
978
979 /*
980 * console_init_main() makes sure that the terminal is in a
981 * reasonable state.
982 *
983 * The SIGINT handler is for CTRL-C (enter the interactive debugger).
984 *
985 * The SIGCONT handler is invoked whenever the user presses CTRL-Z
986 * (or sends SIGSTOP) and then continues. It makes sure that the
987 * terminal is in an expected state.
988 */
989 console_init_main(emuls[0]); /* TODO: what is a good argument? */
990 signal(SIGINT, debugger_activate);
991 signal(SIGCONT, console_sigcont);
992
993 /* Not in verbose mode? Then set quiet_mode. */
994 if (!verbose)
995 quiet_mode = 1;
996
997 /* Initialize all CPUs in all machines in all emulations: */
998 for (i=0; i<n_emuls; i++) {
999 e = emuls[i];
1000 if (e == NULL)
1001 continue;
1002 for (j=0; j<e->n_machines; j++)
1003 cpu_run_init(e->machines[j]);
1004 }
1005
1006 /* TODO: Generalize: */
1007 if (emuls[0]->machines[0]->show_trace_tree)
1008 cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1009 emuls[0]->machines[0]->cpus[0]->pc);
1010
1011 /* Start emulated clocks: */
1012 timer_start();
1013
1014 /*
1015 * MAIN LOOP:
1016 *
1017 * Run all emulations in parallel, running each machine in
1018 * each emulation.
1019 */
1020 while (go) {
1021 go = 0;
1022
1023 /* Flush X11 and serial console output every now and then: */
1024 if (emuls[0]->machines[0]->ninstrs >
1025 emuls[0]->machines[0]->ninstrs_flush + (1<<19)) {
1026 x11_check_event(emuls, n_emuls);
1027 console_flush();
1028 emuls[0]->machines[0]->ninstrs_flush =
1029 emuls[0]->machines[0]->ninstrs;
1030 }
1031
1032 if (emuls[0]->machines[0]->ninstrs >
1033 emuls[0]->machines[0]->ninstrs_show + (1<<25)) {
1034 emuls[0]->machines[0]->ninstrs_since_gettimeofday +=
1035 (emuls[0]->machines[0]->ninstrs -
1036 emuls[0]->machines[0]->ninstrs_show);
1037 cpu_show_cycles(emuls[0]->machines[0], 0);
1038 emuls[0]->machines[0]->ninstrs_show =
1039 emuls[0]->machines[0]->ninstrs;
1040 }
1041
1042 if (single_step == ENTER_SINGLE_STEPPING) {
1043 /* TODO: Cleanup! */
1044 old_instruction_trace =
1045 emuls[0]->machines[0]->instruction_trace;
1046 old_quiet_mode = quiet_mode;
1047 old_show_trace_tree =
1048 emuls[0]->machines[0]->show_trace_tree;
1049 emuls[0]->machines[0]->instruction_trace = 1;
1050 emuls[0]->machines[0]->show_trace_tree = 1;
1051 quiet_mode = 0;
1052 single_step = SINGLE_STEPPING;
1053 }
1054
1055 if (single_step == SINGLE_STEPPING)
1056 debugger();
1057
1058 for (i=0; i<n_emuls; i++) {
1059 e = emuls[i];
1060
1061 for (j=0; j<e->n_machines; j++) {
1062 if (e->machines[j]->gdb.port > 0)
1063 debugger_gdb_check_incoming(
1064 e->machines[j]);
1065
1066 anything = machine_run(e->machines[j]);
1067 if (anything)
1068 go = 1;
1069 }
1070 }
1071 }
1072
1073 /* Stop any running timers: */
1074 timer_stop();
1075
1076 /* Deinitialize all CPUs in all machines in all emulations: */
1077 for (i=0; i<n_emuls; i++) {
1078 e = emuls[i];
1079 if (e == NULL)
1080 continue;
1081 for (j=0; j<e->n_machines; j++)
1082 cpu_run_deinit(e->machines[j]);
1083 }
1084
1085 /* force_debugger_at_exit flag set? Then enter the debugger: */
1086 if (force_debugger_at_exit) {
1087 quiet_mode = 0;
1088 debugger_reset();
1089 debugger();
1090 }
1091
1092 /* Any machine using X11? Then wait before exiting: */
1093 n = 0;
1094 for (i=0; i<n_emuls; i++)
1095 for (j=0; j<emuls[i]->n_machines; j++)
1096 if (emuls[i]->machines[j]->use_x11)
1097 n++;
1098 if (n > 0) {
1099 printf("Press enter to quit.\n");
1100 while (!console_charavail(MAIN_CONSOLE)) {
1101 x11_check_event(emuls, n_emuls);
1102 usleep(10000);
1103 }
1104 console_readchar(MAIN_CONSOLE);
1105 }
1106
1107 console_deinit_main();
1108 }
1109

  ViewVC Help
Powered by ViewVC 1.1.26