/[gxemul]/upstream/0.3.4/src/emul.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.4/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26