/[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 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 37602 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2003-2005 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 dpavlin 10 * $Id: emul.c,v 1.211 2005/06/26 11:36:28 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 "bintrans.h"
43     #include "cpu.h"
44     #include "emul.h"
45     #include "console.h"
46     #include "debugger.h"
47     #include "device.h"
48     #include "diskimage.h"
49 dpavlin 10 #include "exec_elf.h"
50 dpavlin 2 #include "machine.h"
51     #include "memory.h"
52     #include "mips_cpu_types.h"
53     #include "misc.h"
54     #include "net.h"
55     #include "sgi_arcbios.h"
56     #include "x11.h"
57    
58    
59     extern int force_debugger_at_exit;
60    
61     extern int extra_argc;
62     extern char **extra_argv;
63    
64     extern int verbose;
65     extern int quiet_mode;
66    
67     extern struct emul *debugger_emul;
68     extern struct diskimage *diskimages[];
69    
70 dpavlin 6 static char *diskimage_types[] = DISKIMAGE_TYPES;
71 dpavlin 2
72 dpavlin 6
73 dpavlin 2 /*
74     * add_dump_points():
75     *
76     * Take the strings breakpoint_string[] and convert to addresses
77     * (and store them in breakpoint_addr[]).
78     *
79     * TODO: This function should be moved elsewhere.
80     */
81     static void add_dump_points(struct machine *m)
82     {
83     int i;
84     int string_flag;
85     uint64_t dp;
86    
87     for (i=0; i<m->n_breakpoints; i++) {
88     string_flag = 0;
89     dp = strtoull(m->breakpoint_string[i], NULL, 0);
90    
91     /*
92     * If conversion resulted in 0, then perhaps it is a
93     * symbol:
94     */
95     if (dp == 0) {
96     uint64_t addr;
97     int res = get_symbol_addr(&m->symbol_context,
98     m->breakpoint_string[i], &addr);
99     if (!res)
100     fprintf(stderr,
101     "WARNING! Breakpoint '%s' could not be"
102     " parsed\n",
103     m->breakpoint_string[i]);
104     else {
105     dp = addr;
106     string_flag = 1;
107     }
108     }
109    
110     /*
111     * TODO: It would be nice if things like symbolname+0x1234
112     * were automatically converted into the correct address.
113     */
114    
115     if ((dp >> 32) == 0 && ((dp >> 31) & 1))
116     dp |= 0xffffffff00000000ULL;
117     m->breakpoint_addr[i] = dp;
118    
119     debug("breakpoint %i: 0x%016llx", i, (long long)dp);
120     if (string_flag)
121     debug(" (%s)", m->breakpoint_string[i]);
122     debug("\n");
123     }
124     }
125    
126    
127     /*
128     * fix_console():
129     */
130     static void fix_console(void)
131     {
132     console_deinit();
133     }
134    
135    
136     /*
137 dpavlin 6 * iso_load_bootblock():
138     *
139     * Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for
140     * "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra).
141     *
142     * TODO: This function uses too many magic offsets and so on; it should be
143     * cleaned up some day.
144     *
145     * Returns 1 on success, 0 on failure.
146     */
147     static int iso_load_bootblock(struct machine *m, struct cpu *cpu,
148     int disk_id, int disk_type, int iso_type, unsigned char *buf,
149     int *n_loadp, char ***load_namesp)
150     {
151     char str[35];
152     int filenr, i, ofs, dirlen, res = 0, res2, iadd = 4;
153     int found_dir;
154     uint64_t dirofs;
155     uint64_t fileofs, filelen;
156     unsigned char *dirbuf = NULL, *dp;
157     unsigned char *match_entry = NULL;
158     char *p, *filename_orig;
159     char *filename = strdup(cpu->machine->boot_kernel_filename);
160     unsigned char *filebuf = NULL;
161     char *tmpfilename = NULL;
162     char **new_array;
163     int tmpfile_handle;
164    
165     if (filename == NULL) {
166     fatal("out of memory\n");
167     exit(1);
168     }
169     filename_orig = filename;
170    
171     debug("ISO9660 boot:\n");
172     debug_indentation(iadd);
173    
174     /* Volume ID: */
175     ofs = iso_type == 3? 48 : 40;
176     memcpy(str, buf + ofs, sizeof(str));
177     str[32] = '\0'; i = 31;
178     while (i >= 0 && str[i]==' ')
179     str[i--] = '\0';
180     if (str[0])
181     debug("\"%s\"", str);
182     else {
183     /* System ID: */
184     ofs = iso_type == 3? 16 : 8;
185     memcpy(str, buf + ofs, sizeof(str));
186     str[32] = '\0'; i = 31;
187     while (i >= 0 && str[i]==' ')
188     str[i--] = '\0';
189     if (str[0])
190     debug("\"%s\"", str);
191     else
192     debug("(no ID)");
193     }
194    
195     debug(":%s\n", filename);
196    
197    
198     /*
199     * Traverse the directory structure to find the kernel.
200     */
201    
202     dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86];
203     if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89])
204     fatal("WARNING: Root directory length mismatch?\n");
205    
206     dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) +
207     (buf[0x8f] << 24)) * 2048;
208    
209     /* debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs); */
210    
211     dirbuf = malloc(dirlen);
212     if (dirbuf == NULL) {
213     fatal("out of memory in iso_load_bootblock()\n");
214     exit(1);
215     }
216    
217     res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf,
218     dirlen);
219     if (!res2) {
220     fatal("Couldn't read the disk image. Aborting.\n");
221     goto ret;
222     }
223    
224     found_dir = 1; /* Assume root dir */
225     dp = dirbuf; filenr = 1;
226     p = NULL;
227     while (dp < dirbuf + dirlen) {
228     int i, nlen = dp[0];
229     int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) + (dp[5] << 24);
230     int y = dp[6] + (dp[7] << 8);
231     char direntry[65];
232    
233     dp += 8;
234    
235     /*
236     * As long as there is an \ or / in the filename, then we
237     * have not yet found the directory.
238     */
239     p = strchr(filename, '/');
240     if (p == NULL)
241     p = strchr(filename, '\\');
242    
243     /* debug("%i%s: %i, %i, \"", filenr, filenr == found_dir?
244     " [CURRENT]" : "", x, y); */
245     for (i=0; i<nlen && i<sizeof(direntry)-1; i++)
246     if (dp[i]) {
247     direntry[i] = dp[i];
248     /* debug("%c", dp[i]); */
249     } else
250     break;
251     /* debug("\"\n"); */
252     direntry[i] = '\0';
253    
254     /* A directory name match? */
255     if (p != NULL && strncasecmp(filename, direntry, nlen) == 0
256     && nlen == (size_t)p - (size_t)filename && found_dir == y) {
257     found_dir = filenr;
258     filename = p+1;
259     dirofs = 2048 * (int64_t)x;
260     }
261    
262     dp += nlen;
263    
264     /* 16-bit aligned lenght: */
265     if (nlen & 1)
266     dp ++;
267    
268     filenr ++;
269     }
270    
271     p = strchr(filename, '/');
272     if (p == NULL)
273     p = strchr(filename, '\\');
274    
275     if (p != NULL) {
276     char *blah = filename_orig;
277    
278     fatal("could not find '%s' in /", filename);
279    
280     /* Print the first part of the filename: */
281     while (blah != filename)
282     fatal("%c", *blah++);
283    
284     fatal("\n");
285     goto ret;
286     }
287    
288     /* debug("dirofs = 0x%llx\n", (long long)dirofs); */
289    
290     /* Free the old dirbuf, and allocate a new one: */
291     free(dirbuf);
292     dirbuf = malloc(512);
293     if (dirbuf == NULL) {
294     fatal("out of memory in iso_load_bootblock()\n");
295     exit(1);
296     }
297    
298     for (;;) {
299     int len, i;
300    
301     /* Too close to another sector? Then realign. */
302     if ((dirofs & 2047) + 70 > 2047) {
303     dirofs = (dirofs | 2047) + 1;
304     /* debug("realign dirofs = 0x%llx\n", dirofs); */
305     }
306    
307     res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs,
308     dirbuf, 256);
309     if (!res2) {
310     fatal("Couldn't read the disk image. Aborting.\n");
311     goto ret;
312     }
313    
314     dp = dirbuf;
315     len = dp[0];
316     if (len < 2)
317     break;
318    
319     /*
320     * TODO: Actually parse the directory entry!
321     *
322     * Haha, this must be rewritten.
323     */
324     for (i=32; i<len; i++) {
325     if (i < len - strlen(filename))
326     if (strncasecmp(filename, (char *)dp + i,
327     strlen(filename)) == 0) {
328     /* The filename was found somewhere
329     in the directory entry. */
330     if (match_entry != NULL) {
331     fatal("TODO: I'm too lazy to"
332     " implement a correct "
333     "directory parser right "
334     "now... (BUG)\n");
335     exit(1);
336     }
337     match_entry = malloc(512);
338     if (match_entry == NULL) {
339     fatal("out of memory\n");
340     exit(1);
341     }
342     memcpy(match_entry, dp, 512);
343     break;
344     }
345     }
346    
347     dirofs += len;
348     }
349    
350     if (match_entry == NULL) {
351     char *blah = filename_orig;
352    
353     fatal("could not find '%s' in /", filename);
354    
355     /* Print the first part of the filename: */
356     while (blah != filename)
357     fatal("%c", *blah++);
358    
359     fatal("\n");
360     goto ret;
361     }
362    
363     fileofs = match_entry[2] + (match_entry[3] << 8) +
364     (match_entry[4] << 16) + (match_entry[5] << 24);
365     filelen = match_entry[10] + (match_entry[11] << 8) +
366     (match_entry[12] << 16) + (match_entry[13] << 24);
367     fileofs *= 2048;
368    
369     /* debug("filelen=%llx fileofs=%llx\n", (long long)filelen,
370     (long long)fileofs); */
371    
372     filebuf = malloc(filelen);
373     if (filebuf == NULL) {
374     fatal("could not allocate %lli bytes to read the file"
375     " from the disk image!\n", (long long)filelen);
376     goto ret;
377     }
378    
379     tmpfilename = strdup("/tmp/gxemul.XXXXXXXXXXXX");
380    
381     debug("extracting %lli bytes into %s\n",
382     (long long)filelen, tmpfilename);
383    
384     res2 = diskimage_access(m, disk_id, disk_type, 0, fileofs, filebuf,
385     filelen);
386     if (!res2) {
387     fatal("could not read the file from the disk image!\n");
388     goto ret;
389     }
390    
391     tmpfile_handle = mkstemp(tmpfilename);
392     if (tmpfile_handle < 0) {
393     fatal("could not create %s\n", tmpfilename);
394     exit(1);
395     }
396     write(tmpfile_handle, filebuf, filelen);
397     close(tmpfile_handle);
398    
399     /* Add the temporary filename to the load_namesp array: */
400     (*n_loadp)++;
401     new_array = malloc(sizeof(char *) * (*n_loadp));
402     if (new_array == NULL) {
403     fatal("out of memory\n");
404     exit(1);
405     }
406     memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));
407     *load_namesp = new_array;
408    
409     /* This adds a Backspace char in front of the filename; this
410     is a special hack which causes the file to be removed once
411     it has been loaded. */
412     tmpfilename = realloc(tmpfilename, strlen(tmpfilename) + 2);
413     memmove(tmpfilename + 1, tmpfilename, strlen(tmpfilename) + 1);
414     tmpfilename[0] = 8;
415    
416     (*load_namesp)[*n_loadp - 1] = tmpfilename;
417    
418     res = 1;
419    
420     ret:
421     if (dirbuf != NULL)
422     free(dirbuf);
423    
424     if (filebuf != NULL)
425     free(filebuf);
426    
427     if (match_entry != NULL)
428     free(match_entry);
429    
430     free(filename_orig);
431    
432     debug_indentation(-iadd);
433     return res;
434     }
435    
436    
437     /*
438 dpavlin 2 * load_bootblock():
439     *
440     * For some emulation modes, it is possible to boot from a harddisk image by
441     * loading a bootblock from a specific disk offset into memory, and executing
442     * that, instead of requiring a separate kernel file. It is then up to the
443     * bootblock to load a kernel.
444 dpavlin 6 *
445     * Returns 1 on success, 0 on failure.
446 dpavlin 2 */
447 dpavlin 6 static int load_bootblock(struct machine *m, struct cpu *cpu,
448     int *n_loadp, char ***load_namesp)
449 dpavlin 2 {
450 dpavlin 6 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
451     iso_type, retval = 0;
452 dpavlin 2 unsigned char minibuf[0x20];
453     unsigned char *bootblock_buf;
454     uint64_t bootblock_offset;
455     uint64_t bootblock_loadaddr, bootblock_pc;
456    
457 dpavlin 6 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
458 dpavlin 2 if (boot_disk_id < 0)
459 dpavlin 6 return 0;
460 dpavlin 2
461     switch (m->machine_type) {
462     case MACHINE_DEC:
463     /*
464     * The first few bytes of a disk contains information about
465     * where the bootblock(s) are located. (These are all 32-bit
466     * little-endian words.)
467     *
468     * Offset 0x10 = load address
469     * 0x14 = initial PC value
470     * 0x18 = nr of 512-byte blocks to read
471     * 0x1c = offset on disk to where the bootblocks
472     * are (in 512-byte units)
473     * 0x20 = nr of blocks to read...
474     * 0x24 = offset...
475     *
476     * nr of blocks to read and offset are repeated until nr of
477     * blocks to read is zero.
478     */
479 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
480 dpavlin 2 minibuf, sizeof(minibuf));
481    
482     bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
483     + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);
484    
485     /* Convert loadaddr to uncached: */
486     if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
487     (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)
488     fatal("\nWARNING! Weird load address 0x%08x.\n\n",
489     (int)bootblock_loadaddr);
490     bootblock_loadaddr &= 0x0fffffffULL;
491     bootblock_loadaddr |= 0xffffffffa0000000ULL;
492    
493     bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
494     + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);
495    
496     bootblock_pc &= 0x0fffffffULL;
497     bootblock_pc |= 0xffffffffa0000000ULL;
498     cpu->pc = bootblock_pc;
499    
500     debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",
501     (int)bootblock_loadaddr, (int)bootblock_pc);
502    
503     readofs = 0x18;
504    
505     for (;;) {
506 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type,
507     0, readofs, minibuf, sizeof(minibuf));
508 dpavlin 2 if (!res) {
509 dpavlin 6 fatal("Couldn't read the disk image. "
510     "Aborting.\n");
511     return 0;
512 dpavlin 2 }
513    
514     n_blocks = minibuf[0] + (minibuf[1] << 8)
515     + (minibuf[2] << 16) + (minibuf[3] << 24);
516    
517     bootblock_offset = (minibuf[4] + (minibuf[5] << 8)
518     + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;
519    
520     if (n_blocks < 1)
521     break;
522    
523     debug(readofs == 0x18? ": %i" : " + %i", n_blocks);
524    
525     if (n_blocks * 512 > 65536)
526     fatal("\nWARNING! Unusually large bootblock "
527     "(%i bytes)\n\n", n_blocks * 512);
528    
529     bootblock_buf = malloc(n_blocks * 512);
530     if (bootblock_buf == NULL) {
531     fprintf(stderr, "out of memory in "
532     "load_bootblock()\n");
533     exit(1);
534     }
535    
536 dpavlin 6 res = diskimage_access(m, boot_disk_id, boot_disk_type,
537     0, bootblock_offset, bootblock_buf, n_blocks * 512);
538 dpavlin 2 if (!res) {
539     fatal("WARNING: could not load bootblocks from"
540     " disk offset 0x%llx\n",
541     (long long)bootblock_offset);
542     }
543    
544     store_buf(cpu, bootblock_loadaddr,
545     (char *)bootblock_buf, n_blocks * 512);
546    
547     bootblock_loadaddr += 512*n_blocks;
548     free(bootblock_buf);
549     readofs += 8;
550     }
551    
552     debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
553 dpavlin 6 return 1;
554 dpavlin 4
555     case MACHINE_X86:
556 dpavlin 6 /* TODO: "El Torito" etc? */
557     if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
558     boot_disk_type))
559     break;
560 dpavlin 4
561     bootblock_buf = malloc(512);
562     if (bootblock_buf == NULL) {
563     fprintf(stderr, "Out of memory.\n");
564     exit(1);
565     }
566    
567 dpavlin 6 debug("loading PC bootsector from %s id %i\n",
568     diskimage_types[boot_disk_type], boot_disk_id);
569    
570     res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
571 dpavlin 4 bootblock_buf, 512);
572     if (!res) {
573 dpavlin 6 fatal("Couldn't read the disk image. Aborting.\n");
574     return 0;
575 dpavlin 4 }
576    
577     if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)
578     debug("WARNING! The 0x55,0xAA marker is missing! "
579     "Booting anyway.\n");
580     store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);
581     free(bootblock_buf);
582    
583 dpavlin 6 return 1;
584     }
585    
586    
587     /*
588     * Try reading a kernel manually from the disk. The code here
589     * does not rely on machine-dependant boot blocks etc.
590     */
591     /* ISO9660: (0x800 bytes at 0x8000) */
592     bootblock_buf = malloc(0x800);
593     if (bootblock_buf == NULL) {
594     fprintf(stderr, "Out of memory.\n");
595 dpavlin 2 exit(1);
596     }
597 dpavlin 6
598     res = diskimage_access(m, boot_disk_id, boot_disk_type,
599     0, 0x8000, bootblock_buf, 0x800);
600     if (!res) {
601     fatal("Couldn't read the disk image. Aborting.\n");
602     return 0;
603     }
604    
605     iso_type = 0;
606     if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)
607     iso_type = 1;
608     if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)
609     iso_type = 2;
610     if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)
611     iso_type = 3;
612    
613     if (iso_type != 0) {
614     /* We can't load a kernel if the name
615     isn't specified. */
616     if (cpu->machine->boot_kernel_filename == NULL ||
617     cpu->machine->boot_kernel_filename[0] == '\0')
618     fatal("\nISO9660 filesystem, but no kernel "
619     "specified? (Use the -j option.)\n");
620     else
621     retval = iso_load_bootblock(m, cpu, boot_disk_id,
622     boot_disk_type, iso_type, bootblock_buf,
623     n_loadp, load_namesp);
624     }
625    
626     free(bootblock_buf);
627     return retval;
628 dpavlin 2 }
629    
630    
631     /*
632     * emul_new():
633     *
634     * Returns a reasonably initialized struct emul.
635     */
636     struct emul *emul_new(char *name)
637     {
638     struct emul *e;
639     e = malloc(sizeof(struct emul));
640     if (e == NULL) {
641     fprintf(stderr, "out of memory in emul_new()\n");
642     exit(1);
643     }
644    
645     memset(e, 0, sizeof(struct emul));
646    
647     /* Sane default values: */
648     e->n_machines = 0;
649 dpavlin 10 e->next_serial_nr = 1;
650 dpavlin 2
651     if (name != NULL) {
652     e->name = strdup(name);
653     if (e->name == NULL) {
654     fprintf(stderr, "out of memory in emul_new()\n");
655     exit(1);
656     }
657     }
658    
659     return e;
660     }
661    
662    
663     /*
664     * emul_add_machine():
665     *
666     * Calls machine_new(), adds the new machine into the emul struct, and
667     * returns a pointer to the new machine.
668     *
669     * This function should be used instead of manually calling machine_new().
670     */
671     struct machine *emul_add_machine(struct emul *e, char *name)
672     {
673     struct machine *m;
674    
675     m = machine_new(name, e);
676     m->serial_nr = (e->next_serial_nr ++);
677    
678     e->n_machines ++;
679     e->machines = realloc(e->machines,
680     sizeof(struct machine *) * e->n_machines);
681     if (e->machines == NULL) {
682     fprintf(stderr, "emul_add_machine(): out of memory\n");
683     exit(1);
684     }
685    
686     e->machines[e->n_machines - 1] = m;
687     return m;
688     }
689    
690    
691     /*
692     * add_arc_components():
693     *
694     * This function adds ARCBIOS memory descriptors for the loaded program,
695     * and ARCBIOS components for SCSI devices.
696     */
697     static void add_arc_components(struct machine *m)
698     {
699     struct cpu *cpu = m->cpus[m->bootstrap_cpu];
700     uint64_t start = cpu->pc & 0x1fffffff;
701     uint64_t len = 0xc00000 - start;
702     struct diskimage *d;
703     uint64_t scsicontroller, scsidevice, scsidisk;
704    
705     if ((cpu->pc >> 60) != 0xf) {
706     start = cpu->pc & 0xffffffffffULL;
707     len = 0xc00000 - start;
708     }
709    
710     len += 1048576 * m->memory_offset_in_mb;
711    
712     /* NOTE/TODO: magic 12MB end of load program area */
713     arcbios_add_memory_descriptor(cpu,
714     0x60000 + m->memory_offset_in_mb * 1048576,
715     start-0x60000 - m->memory_offset_in_mb * 1048576,
716     ARCBIOS_MEM_FreeMemory);
717     arcbios_add_memory_descriptor(cpu,
718     start, len, ARCBIOS_MEM_LoadedProgram);
719    
720 dpavlin 6 scsicontroller = arcbios_get_scsicontroller(m);
721 dpavlin 2 if (scsicontroller == 0)
722     return;
723    
724     /* TODO: The device 'name' should defined be somewhere else. */
725    
726     d = m->first_diskimage;
727     while (d != NULL) {
728     if (d->type == DISKIMAGE_SCSI) {
729     int a, b, flags = COMPONENT_FLAG_Input;
730     char component_string[100];
731     char *name = "DEC RZ58 (C) DEC2000";
732    
733     /* Read-write, or read-only? */
734     if (d->writable)
735     flags |= COMPONENT_FLAG_Output;
736     else
737     flags |= COMPONENT_FLAG_ReadOnly;
738    
739     a = COMPONENT_TYPE_DiskController;
740     b = COMPONENT_TYPE_DiskPeripheral;
741    
742     if (d->is_a_cdrom) {
743     flags |= COMPONENT_FLAG_Removable;
744     a = COMPONENT_TYPE_CDROMController;
745     b = COMPONENT_TYPE_FloppyDiskPeripheral;
746     name = "NEC CD-ROM CDR-210P 1.0 ";
747     }
748    
749     scsidevice = arcbios_addchild_manual(cpu,
750     COMPONENT_CLASS_ControllerClass,
751     a, flags, 1, 2, d->id, 0xffffffff,
752     name, scsicontroller, NULL, 0);
753    
754     scsidisk = arcbios_addchild_manual(cpu,
755     COMPONENT_CLASS_PeripheralClass,
756     b, flags, 1, 2, 0, 0xffffffff, NULL,
757     scsidevice, NULL, 0);
758    
759     /*
760     * Add device string to component address mappings:
761     * "scsi(0)disk(0)rdisk(0)partition(0)"
762     */
763    
764     if (d->is_a_cdrom) {
765     snprintf(component_string,
766     sizeof(component_string),
767     "scsi(0)cdrom(%i)", d->id);
768 dpavlin 6 arcbios_add_string_to_component(m,
769 dpavlin 2 component_string, scsidevice);
770    
771     snprintf(component_string,
772     sizeof(component_string),
773     "scsi(0)cdrom(%i)fdisk(0)", d->id);
774 dpavlin 6 arcbios_add_string_to_component(m,
775 dpavlin 2 component_string, scsidisk);
776     } else {
777     snprintf(component_string,
778     sizeof(component_string),
779     "scsi(0)disk(%i)", d->id);
780 dpavlin 6 arcbios_add_string_to_component(m,
781 dpavlin 2 component_string, scsidevice);
782    
783     snprintf(component_string,
784     sizeof(component_string),
785     "scsi(0)disk(%i)rdisk(0)", d->id);
786 dpavlin 6 arcbios_add_string_to_component(m,
787 dpavlin 2 component_string, scsidisk);
788     }
789     }
790    
791     d = d->next;
792     }
793     }
794    
795    
796     /*
797     * emul_machine_setup():
798     *
799     * o) Initialize the hardware (RAM, devices, CPUs, ...) which
800     * will be emulated in this machine.
801     *
802     * o) Load ROM code and/or other programs into emulated memory.
803     *
804     * o) Special hacks needed after programs have been loaded.
805     */
806     void emul_machine_setup(struct machine *m, int n_load, char **load_names,
807     int n_devices, char **device_names)
808     {
809     struct emul *emul;
810     struct cpu *cpu;
811     int i, iadd=4;
812 dpavlin 6 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
813 dpavlin 2 int byte_order;
814    
815     emul = m->emul;
816    
817     debug("machine \"%s\":\n", m->name);
818     debug_indentation(iadd);
819    
820     /* For userland-only, this decides which ARCH/cpu_name to use: */
821     if (m->machine_type == MACHINE_USERLAND && m->userland_emul != NULL) {
822     useremul_name_to_useremul(NULL, m->userland_emul,
823     &m->arch, &m->machine_name, &m->cpu_name);
824     if (m->arch == ARCH_NOARCH) {
825     printf("Unsupported userland emulation mode.\n");
826     exit(1);
827     }
828     }
829    
830     if (m->machine_type == MACHINE_NONE) {
831     fatal("No machine type specified?\n");
832     exit(1);
833     }
834    
835     m->cpu_family = cpu_family_ptr_by_number(m->arch);
836    
837 dpavlin 10 if (m->arch != ARCH_MIPS)
838     m->bintrans_enable = 0;
839    
840 dpavlin 2 machine_memsize_fix(m);
841    
842     /*
843     * Create the system's memory:
844     *
845     * (Don't print the amount for userland-only emulation; the
846     * size doesn't matter.)
847     */
848     if (m->machine_type != MACHINE_USERLAND)
849     debug("memory: %i MB", m->physical_ram_in_mb);
850     memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576;
851     if (m->memory_offset_in_mb > 0) {
852     /*
853     * A special hack is used for some SGI models,
854     * where memory is offset by 128MB to leave room for
855     * EISA space and other things.
856     */
857     debug(" (offset by %iMB)", m->memory_offset_in_mb);
858     memory_amount += 1048576 * m->memory_offset_in_mb;
859     }
860     m->memory = memory_new(memory_amount);
861     if (m->machine_type != MACHINE_USERLAND)
862     debug("\n");
863    
864     /* Create CPUs: */
865     if (m->cpu_name == NULL)
866     machine_default_cputype(m);
867     if (m->ncpus == 0) {
868     /* TODO: This should be moved elsewhere... */
869     if (m->machine_type == MACHINE_BEBOX)
870     m->ncpus = 2;
871     else if (m->machine_type == MACHINE_ARC &&
872     m->machine_subtype == MACHINE_ARC_NEC_R96)
873     m->ncpus = 2;
874     else if (m->machine_type == MACHINE_ARC &&
875     m->machine_subtype == MACHINE_ARC_NEC_R98)
876     m->ncpus = 4;
877     else
878     m->ncpus = 1;
879     }
880     m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);
881     if (m->cpus == NULL) {
882     fprintf(stderr, "out of memory\n");
883     exit(1);
884     }
885     memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
886    
887     /* Initialize dynamic binary translation, if available: */
888     if (m->bintrans_enable)
889     bintrans_init(m, m->memory);
890    
891     debug("cpu0");
892     if (m->ncpus > 1)
893     debug(" .. cpu%i", m->ncpus - 1);
894     debug(": ");
895     for (i=0; i<m->ncpus; i++) {
896     m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
897     if (m->bintrans_enable)
898     bintrans_init_cpu(m->cpus[i]);
899     }
900     debug("\n");
901    
902 dpavlin 10 #if 0
903     /* Special case: The Playstation Portable has an additional CPU: */
904     if (m->machine_type == MACHINE_PSP) {
905     debug("cpu%i: ", m->ncpus);
906     m->cpus[m->ncpus] = cpu_new(m->memory, m,
907     0 /* use 0 here to show info with debug() */,
908     "Allegrex" /* TODO */);
909     if (m->bintrans_enable)
910     bintrans_init_cpu(m->cpus[m->ncpus]);
911     debug("\n");
912     m->ncpus ++;
913     }
914     #endif
915    
916 dpavlin 2 if (m->use_random_bootstrap_cpu)
917     m->bootstrap_cpu = random() % m->ncpus;
918     else
919     m->bootstrap_cpu = 0;
920    
921     cpu = m->cpus[m->bootstrap_cpu];
922    
923     /* Set cpu->useremul_syscall, and use userland_memory_rw: */
924     if (m->userland_emul != NULL) {
925     useremul_name_to_useremul(cpu,
926     m->userland_emul, NULL, NULL, NULL);
927     cpu->memory_rw = userland_memory_rw;
928     }
929    
930     if (m->use_x11)
931     x11_init(m);
932    
933     /* Fill memory with random bytes: */
934     if (m->random_mem_contents) {
935     for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
936     unsigned char data[256];
937     unsigned int j;
938     for (j=0; j<sizeof(data); j++)
939     data[j] = random() & 255;
940 dpavlin 6 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
941     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
942 dpavlin 2 }
943     }
944    
945     if (m->userland_emul != NULL) {
946     /*
947     * For userland-only emulation, no machine emulation
948     * is needed.
949     */
950     } else {
951     for (i=0; i<n_devices; i++)
952     device_add(m, device_names[i]);
953    
954     machine_setup(m);
955     }
956    
957     diskimage_dump_info(m);
958    
959     /* Load files (ROM code, boot code, ...) into memory: */
960     if (n_load == 0) {
961 dpavlin 6 if (m->first_diskimage != NULL) {
962     if (!load_bootblock(m, cpu, &n_load, &load_names)) {
963     fprintf(stderr, "\nNo executable files were"
964     " specified, and booting directly from disk"
965     " failed.\n");
966     exit(1);
967     }
968     } else {
969 dpavlin 2 fprintf(stderr, "No executable file(s) loaded, and "
970     "we are not booting directly from a disk image."
971     "\nAborting.\n");
972     exit(1);
973     }
974     }
975    
976     while (n_load > 0) {
977 dpavlin 6 FILE *tmp_f;
978     char *name_to_load = *load_names;
979     int remove_after_load = 0;
980    
981     /* Special hack for removing temporary files: */
982     if (name_to_load[0] == 8) {
983     name_to_load ++;
984     remove_after_load = 1;
985     }
986    
987     /*
988 dpavlin 10 * gzipped files are automagically gunzipped:
989     * NOTE/TODO: This isn't secure. system() is used.
990 dpavlin 6 */
991     tmp_f = fopen(name_to_load, "r");
992     if (tmp_f != NULL) {
993     unsigned char buf[2]; /* gzip header */
994     memset(buf, 0, sizeof(buf));
995     fread(buf, 1, sizeof(buf), tmp_f);
996     if (buf[0]==0x1f && buf[1]==0x8b) {
997 dpavlin 10 size_t zzlen = strlen(name_to_load)*2 + 100;
998     char *zz = malloc(zzlen);
999 dpavlin 6 debug("gunziping %s\n", name_to_load);
1000 dpavlin 10 /*
1001     * gzip header found. If this was a file
1002     * extracted from, say, a CDROM image, then it
1003     * already has a temporary name. Otherwise we
1004     * have to gunzip into a temporary file.
1005     */
1006     if (remove_after_load) {
1007     snprintf(zz, zzlen, "mv %s %s.gz",
1008     name_to_load, name_to_load);
1009     system(zz);
1010     snprintf(zz, zzlen, "gunzip %s.gz",
1011     name_to_load);
1012     system(zz);
1013     } else {
1014     /* gunzip into new temp file: */
1015     int tmpfile_handle;
1016     char *new_temp_name =
1017     strdup("/tmp/gxemul.XXXXXXXXXXXX");
1018     tmpfile_handle = mkstemp(new_temp_name);
1019     close(tmpfile_handle);
1020     snprintf(zz, zzlen, "gunzip -c '%s' > "
1021     "%s", name_to_load, new_temp_name);
1022     system(zz);
1023     name_to_load = new_temp_name;
1024     remove_after_load = 1;
1025     }
1026 dpavlin 6 free(zz);
1027     }
1028     fclose(tmp_f);
1029     }
1030    
1031 dpavlin 10 /*
1032     * Ugly (but usable) hack for Playstation Portable: If the
1033     * filename ends with ".pbp" and the file contains an ELF
1034     * header, then extract the ELF file into a temporary file.
1035     */
1036     if (strlen(name_to_load) > 4 && strcasecmp(name_to_load +
1037     strlen(name_to_load) - 4, ".pbp") == 0 &&
1038     (tmp_f = fopen(name_to_load, "r")) != NULL) {
1039     off_t filesize, j, found=0;
1040     unsigned char *buf;
1041     fseek(tmp_f, 0, SEEK_END);
1042     filesize = ftello(tmp_f);
1043     fseek(tmp_f, 0, SEEK_SET);
1044     buf = malloc(filesize);
1045     if (buf == NULL) {
1046     fprintf(stderr, "out of memory while trying"
1047     " to read %s\n", name_to_load);
1048     exit(1);
1049     }
1050     fread(buf, 1, filesize, tmp_f);
1051     fclose(tmp_f);
1052     /* Search for the ELF header, from offset 1 (!): */
1053     for (j=1; j<filesize - 4; j++)
1054     if (memcmp(buf + j, ELFMAG, SELFMAG) == 0) {
1055     found = j;
1056     break;
1057     }
1058     if (found != 0) {
1059     int tmpfile_handle;
1060     char *new_temp_name =
1061     strdup("/tmp/gxemul.XXXXXXXXXXXX");
1062     debug("extracting ELF from %s (offset 0x%x)\n",
1063     name_to_load, (int)found);
1064     tmpfile_handle = mkstemp(new_temp_name);
1065     write(tmpfile_handle, buf + found,
1066     filesize - found);
1067     close(tmpfile_handle);
1068     name_to_load = new_temp_name;
1069     remove_after_load = 1;
1070     }
1071     }
1072    
1073 dpavlin 6 /* Special things required _before_ loading the file: */
1074     switch (m->arch) {
1075     case ARCH_X86:
1076     /*
1077     * X86 machines normally don't need to load any files,
1078     * they can boot from disk directly. Therefore, an x86
1079     * machine usually boots up in 16-bit real mode. When
1080     * loading a 32-bit (or even 64-bit) ELF, that's not
1081     * very nice, hence this special case.
1082     */
1083     pc_bios_simple_pmode_setup(cpu);
1084     break;
1085     }
1086    
1087 dpavlin 2 byte_order = NO_BYTE_ORDER_OVERRIDE;
1088    
1089 dpavlin 6 /*
1090     * Load the file: :-)
1091     */
1092     file_load(m, m->memory, name_to_load, &entrypoint,
1093 dpavlin 2 m->arch, &gp, &byte_order, &toc);
1094    
1095 dpavlin 6 if (remove_after_load) {
1096     debug("removing %s\n", name_to_load);
1097     unlink(name_to_load);
1098     }
1099    
1100 dpavlin 2 if (byte_order != NO_BYTE_ORDER_OVERRIDE)
1101     cpu->byte_order = byte_order;
1102    
1103     cpu->pc = entrypoint;
1104    
1105     switch (m->arch) {
1106     case ARCH_MIPS:
1107     if ((cpu->pc >> 32) == 0
1108     && (cpu->pc & 0x80000000ULL))
1109     cpu->pc |= 0xffffffff00000000ULL;
1110    
1111     cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
1112    
1113     if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 &&
1114     (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL))
1115     cpu->cd.mips.gpr[MIPS_GPR_GP] |=
1116     0xffffffff00000000ULL;
1117     break;
1118 dpavlin 4
1119 dpavlin 2 case ARCH_PPC:
1120 dpavlin 6 /* See http://www.linuxbase.org/spec/ELF/ppc64/
1121     spec/x458.html for more info. */
1122 dpavlin 2 cpu->cd.ppc.gpr[2] = toc;
1123 dpavlin 6 /* TODO */
1124 dpavlin 2 break;
1125 dpavlin 4
1126     case ARCH_ALPHA:
1127     case ARCH_HPPA:
1128 dpavlin 2 case ARCH_SPARC:
1129     case ARCH_URISC:
1130     break;
1131 dpavlin 4
1132 dpavlin 6 case ARCH_ARM:
1133 dpavlin 10 cpu->pc &= 0xfffffffc;
1134     cpu->cd.arm.r[ARM_PC] = cpu->pc;
1135 dpavlin 6 break;
1136    
1137 dpavlin 4 case ARCH_X86:
1138     /*
1139 dpavlin 6 * NOTE: The toc field is used to indicate an ELF32
1140     * or ELF64 load.
1141 dpavlin 4 */
1142 dpavlin 6 switch (toc) {
1143     case 0: /* 16-bit? TODO */
1144 dpavlin 4 cpu->pc &= 0xffffffffULL;
1145 dpavlin 6 break;
1146     case 1: /* 32-bit. */
1147     cpu->pc &= 0xffffffffULL;
1148     break;
1149     case 2: /* 64-bit: TODO */
1150     fatal("64-bit x86 load. TODO\n");
1151     exit(1);
1152     }
1153 dpavlin 2 break;
1154 dpavlin 4
1155 dpavlin 2 default:
1156     fatal("emul_machine_setup(): Internal error: "
1157     "Unimplemented arch %i\n", m->arch);
1158     exit(1);
1159     }
1160    
1161     /*
1162     * For userland emulation, the remaining items
1163     * on the command line will be passed as parameters
1164     * to the emulated program, and will not be treated
1165     * as filenames to load into the emulator.
1166     * The program's name will be in load_names[0], and the
1167     * rest of the parameters in load_names[1] and up.
1168     */
1169     if (m->userland_emul != NULL)
1170     break;
1171    
1172     n_load --;
1173     load_names ++;
1174     }
1175    
1176     if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE)
1177     cpu->byte_order = m->byte_order_override;
1178    
1179     /* Same byte order and entrypoint for all CPUs: */
1180     for (i=0; i<m->ncpus; i++)
1181     if (i != m->bootstrap_cpu) {
1182     m->cpus[i]->byte_order = cpu->byte_order;
1183     m->cpus[i]->pc = cpu->pc;
1184     }
1185    
1186     if (m->userland_emul != NULL)
1187     useremul_setup(cpu, n_load, load_names);
1188    
1189     /* Startup the bootstrap CPU: */
1190     cpu->bootstrap_cpu_flag = 1;
1191     cpu->running = 1;
1192    
1193     /* ... or pause all CPUs, if start_paused is set: */
1194     if (m->start_paused) {
1195     for (i=0; i<m->ncpus; i++)
1196     m->cpus[i]->running = 0;
1197     }
1198    
1199     /* Add PC dump points: */
1200     add_dump_points(m);
1201    
1202     /* TODO: This is MIPS-specific! */
1203     if (m->machine_type == MACHINE_DEC &&
1204     cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1205     add_symbol_name(&m->symbol_context,
1206     0x9fff0000, 0x10000, "r2k3k_cache", 0);
1207    
1208     symbol_recalc_sizes(&m->symbol_context);
1209    
1210     if (m->max_random_cycles_per_chunk > 0)
1211     debug("using random cycle chunks (1 to %i cycles)\n",
1212     m->max_random_cycles_per_chunk);
1213    
1214     /* Special hack for ARC/SGI emulation: */
1215     if ((m->machine_type == MACHINE_ARC ||
1216     m->machine_type == MACHINE_SGI) && m->prom_emulation)
1217     add_arc_components(m);
1218    
1219     debug("starting cpu%i at ", m->bootstrap_cpu);
1220     switch (m->arch) {
1221     case ARCH_MIPS:
1222     if (cpu->cd.mips.cpu_type.isa_level < 3 ||
1223     cpu->cd.mips.cpu_type.isa_level == 32) {
1224     debug("0x%08x", (int)m->cpus[
1225     m->bootstrap_cpu]->pc);
1226     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1227     debug(" (gp=0x%08x)", (int)m->cpus[
1228     m->bootstrap_cpu]->cd.mips.gpr[
1229     MIPS_GPR_GP]);
1230     } else {
1231     debug("0x%016llx", (long long)m->cpus[
1232     m->bootstrap_cpu]->pc);
1233     if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
1234     debug(" (gp=0x%016llx)", (long long)
1235     cpu->cd.mips.gpr[MIPS_GPR_GP]);
1236     }
1237     break;
1238     case ARCH_PPC:
1239     if (cpu->cd.ppc.bits == 32)
1240     debug("0x%08x", (int)entrypoint);
1241     else
1242     debug("0x%016llx", (long long)entrypoint);
1243     break;
1244 dpavlin 6 case ARCH_ARM:
1245     /* ARM cpus aren't 64-bit: */
1246     debug("0x%08x", (int)entrypoint);
1247     break;
1248 dpavlin 2 case ARCH_URISC:
1249     {
1250     char tmps[100];
1251     unsigned char buf[sizeof(uint64_t)];
1252    
1253     cpu->memory_rw(cpu, m->memory, 0, buf, sizeof(buf),
1254     MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
1255    
1256     entrypoint = 0;
1257     for (i=0; i<cpu->cd.urisc.wordlen/8; i++) {
1258     entrypoint <<= 8;
1259     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1260     entrypoint += buf[i];
1261     else
1262     entrypoint += buf[cpu->
1263     cd.urisc.wordlen/8 - 1 - i];
1264     }
1265    
1266 dpavlin 10 snprintf(tmps, sizeof(tmps), "0x%%0%illx",
1267     cpu->cd.urisc.wordlen / 4);
1268 dpavlin 2 debug(tmps, (long long)entrypoint);
1269     cpu->pc = entrypoint;
1270     }
1271     break;
1272 dpavlin 4 case ARCH_X86:
1273 dpavlin 6 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1274     (long long)cpu->pc);
1275 dpavlin 4 break;
1276 dpavlin 2 default:
1277 dpavlin 4 debug("0x%016llx", (long long)cpu->pc);
1278 dpavlin 2 }
1279     debug("\n");
1280    
1281     debug_indentation(-iadd);
1282     }
1283    
1284    
1285     /*
1286     * emul_dumpinfo():
1287     *
1288     * Dump info about all machines in an emul.
1289     */
1290     void emul_dumpinfo(struct emul *e)
1291     {
1292     int j, nm, iadd = 4;
1293    
1294     if (e->net != NULL)
1295     net_dumpinfo(e->net);
1296    
1297     nm = e->n_machines;
1298     for (j=0; j<nm; j++) {
1299     debug("machine %i: \"%s\"\n", j, e->machines[j]->name);
1300     debug_indentation(iadd);
1301     machine_dumpinfo(e->machines[j]);
1302     debug_indentation(-iadd);
1303     }
1304     }
1305    
1306    
1307     /*
1308     * emul_simple_init():
1309     *
1310     * For a normal setup:
1311     *
1312     * o) Initialize a network.
1313     * o) Initialize one machine.
1314     *
1315     * For a userland-only setup:
1316     *
1317     * o) Initialize a "pseudo"-machine.
1318     */
1319     void emul_simple_init(struct emul *emul)
1320     {
1321     int iadd=4;
1322     struct machine *m;
1323    
1324     if (emul->n_machines != 1) {
1325     fprintf(stderr, "emul_simple_init(): n_machines != 1\n");
1326     exit(1);
1327     }
1328    
1329     m = emul->machines[0];
1330    
1331     if (m->userland_emul == NULL) {
1332     debug("Simple setup...\n");
1333     debug_indentation(iadd);
1334    
1335 dpavlin 10 /* Create a simple network: */
1336 dpavlin 2 emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1337 dpavlin 10 "10.0.0.0", 8, NULL, 0, 0);
1338 dpavlin 2 } else {
1339     /* Userland pseudo-machine: */
1340     debug("Syscall emulation (userland-only) setup...\n");
1341     debug_indentation(iadd);
1342     }
1343    
1344     /* Create the machine: */
1345     emul_machine_setup(m, extra_argc, extra_argv, 0, NULL);
1346    
1347     debug_indentation(-iadd);
1348     }
1349    
1350    
1351     /*
1352     * emul_create_from_configfile():
1353     *
1354     * Create an emul struct by reading settings from a configuration file.
1355     */
1356     struct emul *emul_create_from_configfile(char *fname)
1357     {
1358     int iadd = 4;
1359     struct emul *e = emul_new(fname);
1360     FILE *f;
1361     char buf[128];
1362     size_t len;
1363    
1364     debug("Creating emulation from configfile \"%s\":\n", fname);
1365     debug_indentation(iadd);
1366    
1367     f = fopen(fname, "r");
1368     if (f == NULL) {
1369     perror(fname);
1370     exit(1);
1371     }
1372    
1373     /* Read header: (must be !!gxemul) */
1374     len = fread(buf, 1, 8, f);
1375     if (len != 8 || strncmp(buf, "!!gxemul", 8) != 0) {
1376     fprintf(stderr, "%s: must start with '!!gxemul'\n", fname);
1377     exit(1);
1378     }
1379    
1380     /* Restart from beginning: */
1381     rewind(f);
1382    
1383     emul_parse_config(e, f);
1384    
1385     fclose(f);
1386     debug_indentation(-iadd);
1387     return e;
1388     }
1389    
1390    
1391     /*
1392     * emul_run():
1393     *
1394     * o) Set up things needed before running emulations.
1395     *
1396     * o) Run emulations (one or more, in parallel).
1397     *
1398     * o) De-initialize things.
1399     */
1400     void emul_run(struct emul **emuls, int n_emuls)
1401     {
1402     struct emul *e;
1403     int i = 0, j, go = 1, n, anything;
1404    
1405     if (n_emuls < 1) {
1406     fprintf(stderr, "emul_run(): no thing to do\n");
1407     return;
1408     }
1409    
1410     atexit(fix_console);
1411    
1412     i = 79;
1413     while (i-- > 0)
1414     debug("-");
1415     debug("\n\n");
1416    
1417     /* Initialize the interactive debugger: */
1418     debugger_init(emuls, n_emuls);
1419    
1420     /*
1421     * console_init_main() makes sure that the terminal is in a
1422     * reasonable state.
1423     *
1424     * The SIGINT handler is for CTRL-C (enter the interactive debugger).
1425     *
1426     * The SIGCONT handler is invoked whenever the user presses CTRL-Z
1427     * (or sends SIGSTOP) and then continues. It makes sure that the
1428     * terminal is in an expected state.
1429     */
1430     console_init_main(emuls[0]); /* TODO: what is a good argument? */
1431     signal(SIGINT, debugger_activate);
1432     signal(SIGCONT, console_sigcont);
1433    
1434     /* Not in verbose mode? Then set quiet_mode. */
1435     if (!verbose)
1436     quiet_mode = 1;
1437    
1438     /* Initialize all CPUs in all machines in all emulations: */
1439     for (i=0; i<n_emuls; i++) {
1440     e = emuls[i];
1441     if (e == NULL)
1442     continue;
1443     for (j=0; j<e->n_machines; j++)
1444     cpu_run_init(e, e->machines[j]);
1445     }
1446    
1447     /*
1448     * MAIN LOOP:
1449     *
1450     * Run all emulations in parallel, running each machine in
1451     * each emulation.
1452     */
1453     while (go) {
1454     go = 0;
1455    
1456     x11_check_event(emuls, n_emuls);
1457    
1458     for (i=0; i<n_emuls; i++) {
1459     e = emuls[i];
1460     if (e == NULL)
1461     continue;
1462    
1463     for (j=0; j<e->n_machines; j++) {
1464     /* TODO: cpu_run() is a strange name, since
1465     there can be multiple cpus in a machine */
1466     anything = cpu_run(e, e->machines[j]);
1467     if (anything)
1468     go = 1;
1469     }
1470     }
1471     }
1472    
1473     /* Deinitialize all CPUs in all machines in all emulations: */
1474     for (i=0; i<n_emuls; i++) {
1475     e = emuls[i];
1476     if (e == NULL)
1477     continue;
1478     for (j=0; j<e->n_machines; j++)
1479     cpu_run_deinit(e, e->machines[j]);
1480     }
1481    
1482     /* force_debugger_at_exit flag set? Then enter the debugger: */
1483     if (force_debugger_at_exit) {
1484     quiet_mode = 0;
1485     debugger_reset();
1486     debugger();
1487     }
1488    
1489     /* Any machine using X11? Then we should wait before exiting: */
1490     n = 0;
1491     for (i=0; i<n_emuls; i++)
1492     for (j=0; j<emuls[i]->n_machines; j++)
1493     if (emuls[i]->machines[j]->use_x11)
1494     n++;
1495     if (n > 0) {
1496     printf("Press enter to quit.\n");
1497     while (!console_charavail(MAIN_CONSOLE)) {
1498     x11_check_event(emuls, n_emuls);
1499     usleep(1);
1500     }
1501     console_readchar(MAIN_CONSOLE);
1502     }
1503    
1504     console_deinit();
1505     }
1506    

  ViewVC Help
Powered by ViewVC 1.1.26