/[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 6 - (hide annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 35130 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26