/[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

Annotation of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 dpavlin 2 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 44 * $Id: emul.c,v 1.302 2007/08/29 20:36:49 debug Exp $
29 dpavlin 2 *
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 dpavlin 10 #include "exec_elf.h"
49 dpavlin 2 #include "machine.h"
50     #include "memory.h"
51     #include "mips_cpu_types.h"
52     #include "misc.h"
53     #include "net.h"
54 dpavlin 32 #include "settings.h"
55     #include "timer.h"
56 dpavlin 42 #include "useremul.h"
57 dpavlin 2 #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 dpavlin 26 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 dpavlin 2
72    
73     /*
74 dpavlin 42 * add_breakpoints():
75 dpavlin 2 *
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 dpavlin 42 static void add_breakpoints(struct machine *m)
82 dpavlin 2 {
83     int i;
84     int string_flag;
85     uint64_t dp;
86    
87 dpavlin 42 for (i=0; i<m->breakpoints.n; i++) {
88 dpavlin 2 string_flag = 0;
89 dpavlin 42 dp = strtoull(m->breakpoints.string[i], NULL, 0);
90 dpavlin 2
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 dpavlin 42 m->breakpoints.string[i], &addr);
99 dpavlin 24 if (!res) {
100 dpavlin 2 fprintf(stderr,
101 dpavlin 24 "ERROR! Breakpoint '%s' could not be"
102 dpavlin 2 " parsed\n",
103 dpavlin 42 m->breakpoints.string[i]);
104     exit(1);
105 dpavlin 24 } else {
106 dpavlin 2 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 dpavlin 20 if (m->arch == ARCH_MIPS) {
117     if ((dp >> 32) == 0 && ((dp >> 31) & 1))
118     dp |= 0xffffffff00000000ULL;
119     }
120    
121 dpavlin 42 m->breakpoints.addr[i] = dp;
122 dpavlin 2
123 dpavlin 44 debug("breakpoint %i: 0x%"PRIx64, i, dp);
124 dpavlin 2 if (string_flag)
125 dpavlin 42 debug(" (%s)", m->breakpoints.string[i]);
126 dpavlin 2 debug("\n");
127     }
128     }
129    
130    
131     /*
132     * fix_console():
133     */
134     static void fix_console(void)
135     {
136 dpavlin 32 console_deinit_main();
137 dpavlin 2 }
138    
139    
140     /*
141     * emul_new():
142     *
143     * Returns a reasonably initialized struct emul.
144     */
145 dpavlin 44 struct emul *emul_new(char *name)
146 dpavlin 2 {
147     struct emul *e;
148    
149 dpavlin 42 CHECK_ALLOCATION(e = malloc(sizeof(struct emul)));
150 dpavlin 2 memset(e, 0, sizeof(struct emul));
151    
152 dpavlin 32 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 dpavlin 2 /* Sane default values: */
161     e->n_machines = 0;
162 dpavlin 10 e->next_serial_nr = 1;
163 dpavlin 2
164     if (name != NULL) {
165 dpavlin 42 CHECK_ALLOCATION(e->name = strdup(name));
166 dpavlin 32 settings_add(e->settings, "name", 0,
167     SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
168     (void *) &e->name);
169 dpavlin 2 }
170    
171     return e;
172     }
173    
174    
175     /*
176 dpavlin 32 * 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 dpavlin 2 * 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 dpavlin 32 char tmpstr[20];
215     int i;
216 dpavlin 2
217 dpavlin 34 m = machine_new(name, e, e->n_machines);
218 dpavlin 2 m->serial_nr = (e->next_serial_nr ++);
219    
220 dpavlin 42 i = e->n_machines ++;
221 dpavlin 32
222 dpavlin 42 CHECK_ALLOCATION(e->machines = realloc(e->machines,
223     sizeof(struct machine *) * e->n_machines));
224 dpavlin 2
225 dpavlin 32 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 dpavlin 2 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 dpavlin 12 /*
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 dpavlin 2 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 dpavlin 12 #endif
267 dpavlin 2 arcbios_add_memory_descriptor(cpu,
268     start, len, ARCBIOS_MEM_LoadedProgram);
269    
270 dpavlin 6 scsicontroller = arcbios_get_scsicontroller(m);
271 dpavlin 2 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 dpavlin 6 arcbios_add_string_to_component(m,
319 dpavlin 2 component_string, scsidevice);
320    
321     snprintf(component_string,
322     sizeof(component_string),
323     "scsi(0)cdrom(%i)fdisk(0)", d->id);
324 dpavlin 6 arcbios_add_string_to_component(m,
325 dpavlin 2 component_string, scsidisk);
326     } else {
327     snprintf(component_string,
328     sizeof(component_string),
329     "scsi(0)disk(%i)", d->id);
330 dpavlin 6 arcbios_add_string_to_component(m,
331 dpavlin 2 component_string, scsidevice);
332    
333     snprintf(component_string,
334     sizeof(component_string),
335     "scsi(0)disk(%i)rdisk(0)", d->id);
336 dpavlin 6 arcbios_add_string_to_component(m,
337 dpavlin 2 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 dpavlin 22 int i, iadd = DEBUG_INDENTATION;
361 dpavlin 6 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
362 dpavlin 2 int byte_order;
363    
364 dpavlin 44 if (m->name != NULL)
365     debug("machine \"%s\":\n", m->name);
366     else
367     debug("machine:\n");
368    
369 dpavlin 2 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 dpavlin 12 if (m->arch == ARCH_ALPHA)
389     m->arch_pagesize = 8192;
390    
391 dpavlin 2 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 dpavlin 12 m->memory = memory_new(memory_amount, m->arch);
412 dpavlin 2 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 dpavlin 42
426     CHECK_ALLOCATION(m->cpus = malloc(sizeof(struct cpu *) * m->ncpus));
427 dpavlin 2 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 dpavlin 24 if (m->cpus[i] == NULL) {
436     fprintf(stderr, "Unable to create CPU object. "
437     "Aborting.");
438     exit(1);
439     }
440 dpavlin 2 }
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 dpavlin 12
455     switch (m->arch) {
456 dpavlin 42
457 dpavlin 12 case ARCH_ALPHA:
458     cpu->memory_rw = alpha_userland_memory_rw;
459     break;
460 dpavlin 42
461     default:
462     cpu->memory_rw = userland_memory_rw;
463 dpavlin 12 }
464 dpavlin 2 }
465    
466 dpavlin 42 if (m->x11_md.in_use)
467 dpavlin 2 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 dpavlin 6 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
477     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
478 dpavlin 2 }
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 dpavlin 22 console_debug_dump(m);
495 dpavlin 2
496     /* Load files (ROM code, boot code, ...) into memory: */
497     if (n_load == 0) {
498 dpavlin 6 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 dpavlin 2 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 dpavlin 6 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 dpavlin 10 * gzipped files are automagically gunzipped:
526     * NOTE/TODO: This isn't secure. system() is used.
527 dpavlin 6 */
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 dpavlin 10 size_t zzlen = strlen(name_to_load)*2 + 100;
535 dpavlin 42 char *zz;
536    
537     CHECK_ALLOCATION(zz = malloc(zzlen));
538 dpavlin 6 debug("gunziping %s\n", name_to_load);
539 dpavlin 42
540 dpavlin 10 /*
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 dpavlin 42 char *new_temp_name;
557 dpavlin 44 char *tmpdir = getenv("TMPDIR");
558    
559     if (tmpdir == NULL)
560     tmpdir = DEFAULT_TMP_DIR;
561    
562 dpavlin 42 CHECK_ALLOCATION(new_temp_name =
563 dpavlin 44 malloc(300));
564     snprintf(new_temp_name, 300,
565     "%s/gxemul.XXXXXXXXXXXX", tmpdir);
566    
567 dpavlin 10 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 dpavlin 6 free(zz);
576     }
577     fclose(tmp_f);
578     }
579    
580 dpavlin 2 byte_order = NO_BYTE_ORDER_OVERRIDE;
581    
582 dpavlin 6 /*
583     * Load the file: :-)
584     */
585     file_load(m, m->memory, name_to_load, &entrypoint,
586 dpavlin 2 m->arch, &gp, &byte_order, &toc);
587    
588 dpavlin 6 if (remove_after_load) {
589     debug("removing %s\n", name_to_load);
590     unlink(name_to_load);
591     }
592    
593 dpavlin 2 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
594     cpu->byte_order = byte_order;
595    
596     cpu->pc = entrypoint;
597    
598     switch (m->arch) {
599 dpavlin 14
600     case ARCH_ALPHA:
601 dpavlin 18 /* For position-independent code: */
602 dpavlin 14 cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
603     break;
604    
605     case ARCH_ARM:
606 dpavlin 20 if (cpu->pc & 3) {
607     fatal("ARM: lowest bits of pc set: TODO\n");
608     exit(1);
609     }
610 dpavlin 14 cpu->pc &= 0xfffffffc;
611     break;
612    
613 dpavlin 44 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 dpavlin 42 case ARCH_M88K:
622     if (cpu->pc & 3) {
623     fatal("M88K: lowest bits of pc set: TODO\n");
624 dpavlin 14 exit(1);
625     }
626 dpavlin 42 cpu->pc &= 0xfffffffc;
627 dpavlin 14 break;
628    
629 dpavlin 2 case ARCH_MIPS:
630 dpavlin 20 if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
631 dpavlin 2 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 dpavlin 4
641 dpavlin 2 case ARCH_PPC:
642 dpavlin 6 /* See http://www.linuxbase.org/spec/ELF/ppc64/
643     spec/x458.html for more info. */
644 dpavlin 2 cpu->cd.ppc.gpr[2] = toc;
645 dpavlin 6 /* TODO */
646 dpavlin 14 if (cpu->cd.ppc.bits == 32)
647     cpu->pc &= 0xffffffffULL;
648 dpavlin 2 break;
649 dpavlin 4
650 dpavlin 14 case ARCH_SH:
651 dpavlin 30 if (cpu->cd.sh.cpu_type.bits == 32)
652 dpavlin 14 cpu->pc &= 0xffffffffULL;
653     cpu->pc &= ~1;
654 dpavlin 12 break;
655    
656 dpavlin 2 case ARCH_SPARC:
657     break;
658 dpavlin 4
659 dpavlin 2 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 dpavlin 30 cpu->running = 1;
695 dpavlin 2
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 dpavlin 42 /* Parse and add breakpoints: */
703     add_breakpoints(m);
704 dpavlin 2
705     /* TODO: This is MIPS-specific! */
706 dpavlin 22 if (m->machine_type == MACHINE_PMAX &&
707 dpavlin 2 cpu->cd.mips.cpu_type.mmu_model == MMU3K)
708     add_symbol_name(&m->symbol_context,
709 dpavlin 12 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
710 dpavlin 2
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 dpavlin 44 debug("cpu%i: starting at ", m->bootstrap_cpu);
719    
720 dpavlin 2 switch (m->arch) {
721 dpavlin 14
722 dpavlin 2 case ARCH_MIPS:
723 dpavlin 12 if (cpu->is_32bit) {
724 dpavlin 38 debug("0x%08"PRIx32, (uint32_t)
725     m->cpus[m->bootstrap_cpu]->pc);
726 dpavlin 2 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
727 dpavlin 38 debug(" (gp=0x%08"PRIx32")", (uint32_t)
728     m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
729 dpavlin 2 MIPS_GPR_GP]);
730     } else {
731 dpavlin 38 debug("0x%016"PRIx64, (uint64_t)
732     m->cpus[m->bootstrap_cpu]->pc);
733 dpavlin 2 if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
734 dpavlin 38 debug(" (gp=0x%016"PRIx64")", (uint64_t)
735 dpavlin 2 cpu->cd.mips.gpr[MIPS_GPR_GP]);
736     }
737     break;
738 dpavlin 14
739 dpavlin 2 default:
740 dpavlin 22 if (cpu->is_32bit)
741 dpavlin 38 debug("0x%08"PRIx32, (uint32_t) cpu->pc);
742 dpavlin 22 else
743 dpavlin 38 debug("0x%016"PRIx64, (uint64_t) cpu->pc);
744 dpavlin 2 }
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 dpavlin 44 int i;
759 dpavlin 2
760     if (e->net != NULL)
761     net_dumpinfo(e->net);
762    
763 dpavlin 44 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 dpavlin 2 }
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 dpavlin 22 int iadd = DEBUG_INDENTATION;
793 dpavlin 2 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 dpavlin 10 /* Create a simple network: */
807 dpavlin 2 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
808 dpavlin 32 NET_DEFAULT_IPV4_MASK,
809     NET_DEFAULT_IPV4_LEN,
810     NULL, 0, 0, NULL);
811 dpavlin 2 } 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 dpavlin 44 struct emul *emul_create_from_configfile(char *fname)
830 dpavlin 2 {
831 dpavlin 22 int iadd = DEBUG_INDENTATION;
832 dpavlin 44 struct emul *e = emul_new(fname);
833 dpavlin 2
834     debug("Creating emulation from configfile \"%s\":\n", fname);
835     debug_indentation(iadd);
836    
837 dpavlin 24 emul_parse_config(e, fname);
838 dpavlin 2
839     debug_indentation(-iadd);
840     return e;
841     }
842    
843    
844     /*
845     * emul_run():
846     *
847 dpavlin 44 * o) Set up things needed before running an emulation.
848 dpavlin 2 *
849 dpavlin 44 * o) Run instructions in all machines.
850 dpavlin 2 *
851     * o) De-initialize things.
852     */
853 dpavlin 44 void emul_run(struct emul *emul)
854 dpavlin 2 {
855     int i = 0, j, go = 1, n, anything;
856    
857     atexit(fix_console);
858    
859     /* Initialize the interactive debugger: */
860 dpavlin 44 debugger_init(emul);
861 dpavlin 2
862 dpavlin 22 /* Run any additional debugger commands before starting: */
863 dpavlin 44 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 dpavlin 22 }
872     }
873    
874 dpavlin 42 print_separator_line();
875 dpavlin 22 debug("\n");
876    
877    
878 dpavlin 2 /*
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 dpavlin 44 console_init_main(emul);
889    
890 dpavlin 2 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 dpavlin 44 /* Initialize all CPUs in all machines: */
899     for (j=0; j<emul->n_machines; j++)
900     cpu_run_init(emul->machines[j]);
901    
902 dpavlin 12 /* TODO: Generalize: */
903 dpavlin 44 if (emul->machines[0]->show_trace_tree)
904     cpu_functioncall_trace(emul->machines[0]->cpus[0],
905     emul->machines[0]->cpus[0]->pc);
906 dpavlin 12
907 dpavlin 32 /* Start emulated clocks: */
908     timer_start();
909    
910 dpavlin 44
911 dpavlin 2 /*
912     * MAIN LOOP:
913     *
914 dpavlin 42 * Run all emulations in parallel, running instructions from each
915 dpavlin 44 * cpu in each machine.
916 dpavlin 2 */
917     while (go) {
918 dpavlin 44 struct cpu *bootcpu = emul->machines[0]->cpus[
919     emul->machines[0]->bootstrap_cpu];
920 dpavlin 42
921 dpavlin 2 go = 0;
922    
923 dpavlin 26 /* Flush X11 and serial console output every now and then: */
924 dpavlin 42 if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) {
925 dpavlin 44 x11_check_event(emul);
926 dpavlin 26 console_flush();
927 dpavlin 42 bootcpu->ninstrs_flush = bootcpu->ninstrs;
928 dpavlin 26 }
929 dpavlin 2
930 dpavlin 42 if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) {
931     bootcpu->ninstrs_since_gettimeofday +=
932     (bootcpu->ninstrs - bootcpu->ninstrs_show);
933 dpavlin 44 cpu_show_cycles(emul->machines[0], 0);
934 dpavlin 42 bootcpu->ninstrs_show = bootcpu->ninstrs;
935 dpavlin 26 }
936 dpavlin 2
937 dpavlin 26 if (single_step == ENTER_SINGLE_STEPPING) {
938     /* TODO: Cleanup! */
939     old_instruction_trace =
940 dpavlin 44 emul->machines[0]->instruction_trace;
941 dpavlin 26 old_quiet_mode = quiet_mode;
942     old_show_trace_tree =
943 dpavlin 44 emul->machines[0]->show_trace_tree;
944     emul->machines[0]->instruction_trace = 1;
945     emul->machines[0]->show_trace_tree = 1;
946 dpavlin 26 quiet_mode = 0;
947     single_step = SINGLE_STEPPING;
948     }
949 dpavlin 24
950 dpavlin 26 if (single_step == SINGLE_STEPPING)
951     debugger();
952    
953 dpavlin 44 for (j=0; j<emul->n_machines; j++) {
954     anything = machine_run(emul->machines[j]);
955     if (anything)
956     go = 1;
957 dpavlin 2 }
958     }
959    
960 dpavlin 32 /* Stop any running timers: */
961     timer_stop();
962    
963 dpavlin 44 /* Deinitialize all CPUs in all machines: */
964     for (j=0; j<emul->n_machines; j++)
965     cpu_run_deinit(emul->machines[j]);
966 dpavlin 2
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 dpavlin 32 /* Any machine using X11? Then wait before exiting: */
975 dpavlin 2 n = 0;
976 dpavlin 44 for (j=0; j<emul->n_machines; j++)
977     if (emul->machines[j]->x11_md.in_use)
978     n++;
979    
980 dpavlin 2 if (n > 0) {
981     printf("Press enter to quit.\n");
982     while (!console_charavail(MAIN_CONSOLE)) {
983 dpavlin 44 x11_check_event(emul);
984 dpavlin 32 usleep(10000);
985 dpavlin 2 }
986     console_readchar(MAIN_CONSOLE);
987     }
988    
989 dpavlin 32 console_deinit_main();
990 dpavlin 2 }
991    

  ViewVC Help
Powered by ViewVC 1.1.26