/[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 38 - (show annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 26841 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1515 2007/04/14 05:39:46 debug Exp $
20070324	Adding a "--debug" option to the configure script, to disable
		optimizations in unstable development builds.
		Moving out SCSI-specific stuff from diskimage.c into a new
		diskimage_scsicmd.c.
		Applying Hĺvard Eidnes' patch for SCSICDROM_READ_DISKINFO and
		SCSICDROM_READ_TRACKINFO. (Not really tested yet.)
		Implementing disk image "overlays" (to allow simple roll-back
		to previous disk state). Adding a 'V' disk flag for this, and
		updating the man page and misc.html.
20070325	Stability fix to cpu_dyntrans.c, when multiple physical pages
		share the same initial table entry. (The ppp == NULL check
		should be physpage_ofs == 0.) Bug found by analysing GXemul
		against a version patched for Godson.
		Fixing a second occurance of the same problem (also in
		cpu_dyntrans.c).
		Fixing a MAJOR physical page leak in cpu_dyntrans.c; pages
		weren't _added_ to the set of translated pages, they _replaced_
		all previous pages. It's amazing that this bug has been able
		to live for this long. (Triggered when emulating >128MB RAM.)
20070326	Removing the GDB debugging stub support; it was too hackish
		and ugly.
20070328	Moving around some native code generation skeleton code.
20070329	The -lm check in the configure script now also checks for sin()
		in addition to sqrt(). (Thanks to Nigel Horne for noticing that
		sqrt was not enough on Fedora Core 6.) (Not verified yet.)
20070330	Fixing an indexing bug in dev_sh4.c, found by using gcc version
		4.3.0 20070323.
20070331	Some more experimentation with native code generation.
20070404	Attempting to fix some more SH4 SCIF interrupt bugs; rewriting
		the SH interrupt assertion/deassertion code somewhat.
20070410	Splitting src/file.c into separate files in src/file/.
		Cleanup: Removing the dummy TS7200, Walnut, PB1000, and
		Meshcube emulation modes, and dev_epcom and dev_au1x00.
		Removing the experimental CHIP8/RCA180x code; it wasn't really
		working much lately, anyway. It was fun while it lasted.
		Also removing the experimental Transputer CPU support.
20070412	Moving the section about how the dynamic translation system
		works from intro.html to a separate translation.html file.
		Minor SH fixes; attempting to get OpenBSD/landisk to run
		without randomly bugging out, but no success yet.
20070413	SH SCI (serial bit interface) should now work together with a
		(new) RS5C313 clock device (for Landisk emulation).
20070414	Moving Redhat/MIPS down from supported to experimental, in
		guestoses.html.
		Preparing for a new release; doing some regression testing etc.

==============  RELEASE 0.4.5  ==============


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.282 2007/04/11 15:15:31 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_M68K:
700 break;
701
702 case ARCH_MIPS:
703 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
704 cpu->pc |= 0xffffffff00000000ULL;
705
706 cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
707
708 if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
709 (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
710 cpu->cd.mips.gpr[MIPS_GPR_GP] |=
711 0xffffffff00000000ULL;
712 break;
713
714 case ARCH_PPC:
715 /* See http://www.linuxbase.org/spec/ELF/ppc64/
716 spec/x458.html for more info. */
717 cpu->cd.ppc.gpr[2] = toc;
718 /* TODO */
719 if (cpu->cd.ppc.bits == 32)
720 cpu->pc &= 0xffffffffULL;
721 break;
722
723 case ARCH_SH:
724 if (cpu->cd.sh.cpu_type.bits == 32)
725 cpu->pc &= 0xffffffffULL;
726 cpu->pc &= ~1;
727 break;
728
729 case ARCH_SPARC:
730 break;
731
732 default:
733 fatal("emul_machine_setup(): Internal error: "
734 "Unimplemented arch %i\n", m->arch);
735 exit(1);
736 }
737
738 /*
739 * For userland emulation, the remaining items
740 * on the command line will be passed as parameters
741 * to the emulated program, and will not be treated
742 * as filenames to load into the emulator.
743 * The program's name will be in load_names[0], and the
744 * rest of the parameters in load_names[1] and up.
745 */
746 if (m->userland_emul != NULL)
747 break;
748
749 n_load --;
750 load_names ++;
751 }
752
753 if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
754 cpu->byte_order = m->byte_order_override;
755
756 /* Same byte order and entrypoint for all CPUs: */
757 for (i=0; i<m->ncpus; i++)
758 if (i != m->bootstrap_cpu) {
759 m->cpus[i]->byte_order = cpu->byte_order;
760 m->cpus[i]->pc = cpu->pc;
761 }
762
763 if (m->userland_emul != NULL)
764 useremul_setup(cpu, n_load, load_names);
765
766 /* Startup the bootstrap CPU: */
767 cpu->running = 1;
768
769 /* ... or pause all CPUs, if start_paused is set: */
770 if (m->start_paused) {
771 for (i=0; i<m->ncpus; i++)
772 m->cpus[i]->running = 0;
773 }
774
775 /* Add PC dump points: */
776 add_dump_points(m);
777
778 /* TODO: This is MIPS-specific! */
779 if (m->machine_type == MACHINE_PMAX &&
780 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
781 add_symbol_name(&m->symbol_context,
782 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
783
784 symbol_recalc_sizes(&m->symbol_context);
785
786 /* Special hack for ARC/SGI emulation: */
787 if ((m->machine_type == MACHINE_ARC ||
788 m->machine_type == MACHINE_SGI) && m->prom_emulation)
789 add_arc_components(m);
790
791 debug("starting cpu%i at ", m->bootstrap_cpu);
792 switch (m->arch) {
793
794 case ARCH_ARM:
795 /* ARM cpus aren't 64-bit: */
796 debug("0x%08"PRIx32, (uint32_t) entrypoint);
797 break;
798
799 case ARCH_AVR:
800 /* Atmel AVR uses a 16-bit or 22-bit program counter: */
801 debug("0x%04x", (int) entrypoint);
802 break;
803
804 case ARCH_MIPS:
805 if (cpu->is_32bit) {
806 debug("0x%08"PRIx32, (uint32_t)
807 m->cpus[m->bootstrap_cpu]->pc);
808 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
809 debug(" (gp=0x%08"PRIx32")", (uint32_t)
810 m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
811 MIPS_GPR_GP]);
812 } else {
813 debug("0x%016"PRIx64, (uint64_t)
814 m->cpus[m->bootstrap_cpu]->pc);
815 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
816 debug(" (gp=0x%016"PRIx64")", (uint64_t)
817 cpu->cd.mips.gpr[MIPS_GPR_GP]);
818 }
819 break;
820
821 case ARCH_PPC:
822 if (cpu->cd.ppc.bits == 32)
823 debug("0x%08"PRIx32, (uint32_t) entrypoint);
824 else
825 debug("0x%016"PRIx64, (uint64_t) entrypoint);
826 break;
827
828 default:
829 if (cpu->is_32bit)
830 debug("0x%08"PRIx32, (uint32_t) cpu->pc);
831 else
832 debug("0x%016"PRIx64, (uint64_t) cpu->pc);
833 }
834 debug("\n");
835
836 debug_indentation(-iadd);
837 }
838
839
840 /*
841 * emul_dumpinfo():
842 *
843 * Dump info about all machines in an emul.
844 */
845 void emul_dumpinfo(struct emul *e)
846 {
847 int j, nm, iadd = DEBUG_INDENTATION;
848
849 if (e->net != NULL)
850 net_dumpinfo(e->net);
851
852 nm = e->n_machines;
853 for (j=0; j<nm; j++) {
854 debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
855 debug_indentation(iadd);
856 machine_dumpinfo(e->machines[j]);
857 debug_indentation(-iadd);
858 }
859 }
860
861
862 /*
863 * emul_simple_init():
864 *
865 * For a normal setup:
866 *
867 * o) Initialize a network.
868 * o) Initialize one machine.
869 *
870 * For a userland-only setup:
871 *
872 * o) Initialize a "pseudo"-machine.
873 */
874 void emul_simple_init(struct emul *emul)
875 {
876 int iadd = DEBUG_INDENTATION;
877 struct machine *m;
878
879 if (emul->n_machines != 1) {
880 fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
881 exit(1);
882 }
883
884 m = emul->machines[0];
885
886 if (m->userland_emul == NULL) {
887 debug("Simple setup...\n");
888 debug_indentation(iadd);
889
890 /* Create a simple network: */
891 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
892 NET_DEFAULT_IPV4_MASK,
893 NET_DEFAULT_IPV4_LEN,
894 NULL, 0, 0, NULL);
895 } else {
896 /* Userland pseudo-machine: */
897 debug("Syscall emulation (userland-only) setup...\n");
898 debug_indentation(iadd);
899 }
900
901 /* Create the machine: */
902 emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
903
904 debug_indentation(-iadd);
905 }
906
907
908 /*
909 * emul_create_from_configfile():
910 *
911 * Create an emul struct by reading settings from a configuration file.
912 */
913 struct emul *emul_create_from_configfile(char *fname, int id)
914 {
915 int iadd = DEBUG_INDENTATION;
916 struct emul *e = emul_new(fname, id);
917
918 debug("Creating emulation from configfile \"%s\":\n", fname);
919 debug_indentation(iadd);
920
921 emul_parse_config(e, fname);
922
923 debug_indentation(-iadd);
924 return e;
925 }
926
927
928 /*
929 * emul_run():
930 *
931 * o) Set up things needed before running emulations.
932 *
933 * o) Run emulations (one or more, in parallel).
934 *
935 * o) De-initialize things.
936 */
937 void emul_run(struct emul **emuls, int n_emuls)
938 {
939 struct emul *e;
940 int i = 0, j, go = 1, n, anything;
941
942 if (n_emuls < 1) {
943 fprintf(stderr, "emul_run(): no thing to do\n");
944 return;
945 }
946
947 atexit(fix_console);
948
949 /* Initialize the interactive debugger: */
950 debugger_init(emuls, n_emuls);
951
952 /* Run any additional debugger commands before starting: */
953 for (i=0; i<n_emuls; i++) {
954 struct emul *emul = emuls[i];
955 if (emul->n_debugger_cmds > 0) {
956 int j;
957 if (i == 0)
958 print_separator();
959 for (j = 0; j < emul->n_debugger_cmds; j ++) {
960 debug("> %s\n", emul->debugger_cmds[j]);
961 debugger_execute_cmd(emul->debugger_cmds[j],
962 strlen(emul->debugger_cmds[j]));
963 }
964 }
965 }
966
967 print_separator();
968 debug("\n");
969
970
971 /*
972 * console_init_main() makes sure that the terminal is in a
973 * reasonable state.
974 *
975 * The SIGINT handler is for CTRL-C (enter the interactive debugger).
976 *
977 * The SIGCONT handler is invoked whenever the user presses CTRL-Z
978 * (or sends SIGSTOP) and then continues. It makes sure that the
979 * terminal is in an expected state.
980 */
981 console_init_main(emuls[0]); /* TODO: what is a good argument? */
982 signal(SIGINT, debugger_activate);
983 signal(SIGCONT, console_sigcont);
984
985 /* Not in verbose mode? Then set quiet_mode. */
986 if (!verbose)
987 quiet_mode = 1;
988
989 /* Initialize all CPUs in all machines in all emulations: */
990 for (i=0; i<n_emuls; i++) {
991 e = emuls[i];
992 if (e == NULL)
993 continue;
994 for (j=0; j<e->n_machines; j++)
995 cpu_run_init(e->machines[j]);
996 }
997
998 /* TODO: Generalize: */
999 if (emuls[0]->machines[0]->show_trace_tree)
1000 cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1001 emuls[0]->machines[0]->cpus[0]->pc);
1002
1003 /* Start emulated clocks: */
1004 timer_start();
1005
1006 /*
1007 * MAIN LOOP:
1008 *
1009 * Run all emulations in parallel, running each machine in
1010 * each emulation.
1011 */
1012 while (go) {
1013 go = 0;
1014
1015 /* Flush X11 and serial console output every now and then: */
1016 if (emuls[0]->machines[0]->ninstrs >
1017 emuls[0]->machines[0]->ninstrs_flush + (1<<19)) {
1018 x11_check_event(emuls, n_emuls);
1019 console_flush();
1020 emuls[0]->machines[0]->ninstrs_flush =
1021 emuls[0]->machines[0]->ninstrs;
1022 }
1023
1024 if (emuls[0]->machines[0]->ninstrs >
1025 emuls[0]->machines[0]->ninstrs_show + (1<<25)) {
1026 emuls[0]->machines[0]->ninstrs_since_gettimeofday +=
1027 (emuls[0]->machines[0]->ninstrs -
1028 emuls[0]->machines[0]->ninstrs_show);
1029 cpu_show_cycles(emuls[0]->machines[0], 0);
1030 emuls[0]->machines[0]->ninstrs_show =
1031 emuls[0]->machines[0]->ninstrs;
1032 }
1033
1034 if (single_step == ENTER_SINGLE_STEPPING) {
1035 /* TODO: Cleanup! */
1036 old_instruction_trace =
1037 emuls[0]->machines[0]->instruction_trace;
1038 old_quiet_mode = quiet_mode;
1039 old_show_trace_tree =
1040 emuls[0]->machines[0]->show_trace_tree;
1041 emuls[0]->machines[0]->instruction_trace = 1;
1042 emuls[0]->machines[0]->show_trace_tree = 1;
1043 quiet_mode = 0;
1044 single_step = SINGLE_STEPPING;
1045 }
1046
1047 if (single_step == SINGLE_STEPPING)
1048 debugger();
1049
1050 for (i=0; i<n_emuls; i++) {
1051 e = emuls[i];
1052
1053 for (j=0; j<e->n_machines; j++) {
1054 anything = machine_run(e->machines[j]);
1055 if (anything)
1056 go = 1;
1057 }
1058 }
1059 }
1060
1061 /* Stop any running timers: */
1062 timer_stop();
1063
1064 /* Deinitialize all CPUs in all machines in all emulations: */
1065 for (i=0; i<n_emuls; i++) {
1066 e = emuls[i];
1067 if (e == NULL)
1068 continue;
1069 for (j=0; j<e->n_machines; j++)
1070 cpu_run_deinit(e->machines[j]);
1071 }
1072
1073 /* force_debugger_at_exit flag set? Then enter the debugger: */
1074 if (force_debugger_at_exit) {
1075 quiet_mode = 0;
1076 debugger_reset();
1077 debugger();
1078 }
1079
1080 /* Any machine using X11? Then wait before exiting: */
1081 n = 0;
1082 for (i=0; i<n_emuls; i++)
1083 for (j=0; j<emuls[i]->n_machines; j++)
1084 if (emuls[i]->machines[j]->use_x11)
1085 n++;
1086 if (n > 0) {
1087 printf("Press enter to quit.\n");
1088 while (!console_charavail(MAIN_CONSOLE)) {
1089 x11_check_event(emuls, n_emuls);
1090 usleep(10000);
1091 }
1092 console_readchar(MAIN_CONSOLE);
1093 }
1094
1095 console_deinit_main();
1096 }
1097

  ViewVC Help
Powered by ViewVC 1.1.26