/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 41264 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26