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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show 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 /*
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.203 2005/06/03 07:39:27 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 "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 static char *diskimage_types[] = DISKIMAGE_TYPES;
70
71
72 /*
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 * 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 * 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 *
444 * Returns 1 on success, 0 on failure.
445 */
446 static int load_bootblock(struct machine *m, struct cpu *cpu,
447 int *n_loadp, char ***load_namesp)
448 {
449 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
450 iso_type, retval = 0;
451 unsigned char minibuf[0x20];
452 unsigned char *bootblock_buf;
453 uint64_t bootblock_offset;
454 uint64_t bootblock_loadaddr, bootblock_pc;
455
456 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
457 if (boot_disk_id < 0)
458 return 0;
459
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 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
479 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 res = diskimage_access(m, boot_disk_id, boot_disk_type,
506 0, readofs, minibuf, sizeof(minibuf));
507 if (!res) {
508 fatal("Couldn't read the disk image. "
509 "Aborting.\n");
510 return 0;
511 }
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 res = diskimage_access(m, boot_disk_id, boot_disk_type,
536 0, bootblock_offset, bootblock_buf, n_blocks * 512);
537 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 return 1;
553
554 case MACHINE_X86:
555 /* TODO: "El Torito" etc? */
556 if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
557 boot_disk_type))
558 break;
559
560 bootblock_buf = malloc(512);
561 if (bootblock_buf == NULL) {
562 fprintf(stderr, "Out of memory.\n");
563 exit(1);
564 }
565
566 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 bootblock_buf, 512);
571 if (!res) {
572 fatal("Couldn't read the disk image. Aborting.\n");
573 return 0;
574 }
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 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 exit(1);
595 }
596
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 }
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 scsicontroller = arcbios_get_scsicontroller(m);
719 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 arcbios_add_string_to_component(m,
767 component_string, scsidevice);
768
769 snprintf(component_string,
770 sizeof(component_string),
771 "scsi(0)cdrom(%i)fdisk(0)", d->id);
772 arcbios_add_string_to_component(m,
773 component_string, scsidisk);
774 } else {
775 snprintf(component_string,
776 sizeof(component_string),
777 "scsi(0)disk(%i)", d->id);
778 arcbios_add_string_to_component(m,
779 component_string, scsidevice);
780
781 snprintf(component_string,
782 sizeof(component_string),
783 "scsi(0)disk(%i)rdisk(0)", d->id);
784 arcbios_add_string_to_component(m,
785 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 uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
811 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 cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
922 MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
923 }
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 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 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 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 byte_order = NO_BYTE_ORDER_OVERRIDE;
1006
1007 /*
1008 * Load the file: :-)
1009 */
1010 file_load(m, m->memory, name_to_load, &entrypoint,
1011 m->arch, &gp, &byte_order, &toc);
1012
1013 if (remove_after_load) {
1014 debug("removing %s\n", name_to_load);
1015 unlink(name_to_load);
1016 }
1017
1018 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
1037 case ARCH_PPC:
1038 /* See http://www.linuxbase.org/spec/ELF/ppc64/
1039 spec/x458.html for more info. */
1040 cpu->cd.ppc.gpr[2] = toc;
1041 /* TODO */
1042 break;
1043
1044 case ARCH_ALPHA:
1045 case ARCH_HPPA:
1046 case ARCH_SPARC:
1047 case ARCH_URISC:
1048 break;
1049
1050 case ARCH_ARM:
1051 cpu->pc &= 0xffffffff;
1052 break;
1053
1054 case ARCH_X86:
1055 /*
1056 * NOTE: The toc field is used to indicate an ELF32
1057 * or ELF64 load.
1058 */
1059 switch (toc) {
1060 case 0: /* 16-bit? TODO */
1061 cpu->pc &= 0xffffffffULL;
1062 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 break;
1071
1072 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 case ARCH_ARM:
1162 /* ARM cpus aren't 64-bit: */
1163 debug("0x%08x", (int)entrypoint);
1164 break;
1165 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 case ARCH_X86:
1189 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],
1190 (long long)cpu->pc);
1191 break;
1192 default:
1193 debug("0x%016llx", (long long)cpu->pc);
1194 }
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