/[gxemul]/upstream/0.3.3.2/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 /upstream/0.3.3.2/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (hide annotations)
Mon Oct 8 16:18:22 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 35130 byte(s)
0.3.3.2
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