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

Contents of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (11 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 41811 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26