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

Diff of /trunk/src/emul.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4 by dpavlin, Mon Oct 8 16:18:00 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: emul.c,v 1.184 2005/04/20 04:43:52 debug Exp $   *  $Id: emul.c,v 1.278 2007/02/10 14:37:38 debug Exp $
29   *   *
30   *  Emulation startup and misc. routines.   *  Emulation startup and misc. routines.
31   */   */
# Line 39  Line 39 
39  #include <unistd.h>  #include <unistd.h>
40    
41  #include "arcbios.h"  #include "arcbios.h"
 #include "bintrans.h"  
42  #include "cpu.h"  #include "cpu.h"
43  #include "emul.h"  #include "emul.h"
44  #include "console.h"  #include "console.h"
45  #include "debugger.h"  #include "debugger.h"
46  #include "device.h"  #include "device.h"
47  #include "diskimage.h"  #include "diskimage.h"
48    #include "exec_elf.h"
49  #include "machine.h"  #include "machine.h"
50  #include "memory.h"  #include "memory.h"
51  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
52  #include "misc.h"  #include "misc.h"
53  #include "net.h"  #include "net.h"
54    #include "settings.h"
55  #include "sgi_arcbios.h"  #include "sgi_arcbios.h"
56    #include "timer.h"
57  #include "x11.h"  #include "x11.h"
58    
59    
60  extern int force_debugger_at_exit;  /*  #define ISO_DEBUG  */
61    
62    
63  extern int extra_argc;  extern int extra_argc;
64  extern char **extra_argv;  extern char **extra_argv;
65    
66  extern int verbose;  extern int verbose;
67  extern int quiet_mode;  extern int quiet_mode;
68    extern int force_debugger_at_exit;
69    extern int single_step;
70    extern int old_show_trace_tree;
71    extern int old_instruction_trace;
72    extern int old_quiet_mode;
73    extern int quiet_mode;
74    
75  extern struct emul *debugger_emul;  extern struct emul *debugger_emul;
76  extern struct diskimage *diskimages[];  extern struct diskimage *diskimages[];
77    
78    static char *diskimage_types[] = DISKIMAGE_TYPES;
79    
80    
81    static void print_separator(void)
82    {
83            int i = 79;
84            while (i-- > 0)
85                    debug("-");
86            debug("\n");
87    }
88    
89    
90  /*  /*
91   *  add_dump_points():   *  add_dump_points():
# Line 93  static void add_dump_points(struct machi Line 113  static void add_dump_points(struct machi
113                          uint64_t addr;                          uint64_t addr;
114                          int res = get_symbol_addr(&m->symbol_context,                          int res = get_symbol_addr(&m->symbol_context,
115                              m->breakpoint_string[i], &addr);                              m->breakpoint_string[i], &addr);
116                          if (!res)                          if (!res) {
117                                  fprintf(stderr,                                  fprintf(stderr,
118                                      "WARNING! Breakpoint '%s' could not be"                                      "ERROR! Breakpoint '%s' could not be"
119                                          " parsed\n",                                          " parsed\n",
120                                      m->breakpoint_string[i]);                                      m->breakpoint_string[i]);
121                          else {                          } else {
122                                  dp = addr;                                  dp = addr;
123                                  string_flag = 1;                                  string_flag = 1;
124                          }                          }
# Line 109  static void add_dump_points(struct machi Line 129  static void add_dump_points(struct machi
129                   *  were automatically converted into the correct address.                   *  were automatically converted into the correct address.
130                   */                   */
131    
132                  if ((dp >> 32) == 0 && ((dp >> 31) & 1))                  if (m->arch == ARCH_MIPS) {
133                          dp |= 0xffffffff00000000ULL;                          if ((dp >> 32) == 0 && ((dp >> 31) & 1))
134                                    dp |= 0xffffffff00000000ULL;
135                    }
136    
137                  m->breakpoint_addr[i] = dp;                  m->breakpoint_addr[i] = dp;
138    
139                  debug("breakpoint %i: 0x%016llx", i, (long long)dp);                  debug("breakpoint %i: 0x%llx", i, (long long)dp);
140                  if (string_flag)                  if (string_flag)
141                          debug(" (%s)", m->breakpoint_string[i]);                          debug(" (%s)", m->breakpoint_string[i]);
142                  debug("\n");                  debug("\n");
# Line 126  static void add_dump_points(struct machi Line 149  static void add_dump_points(struct machi
149   */   */
150  static void fix_console(void)  static void fix_console(void)
151  {  {
152          console_deinit();          console_deinit_main();
153    }
154    
155    
156    /*
157     *  iso_load_bootblock():
158     *
159     *  Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for
160     *  "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra).
161     *
162     *  TODO: This function uses too many magic offsets and so on; it should be
163     *  cleaned up some day.
164     *
165     *  Returns 1 on success, 0 on failure.
166     */
167    static int iso_load_bootblock(struct machine *m, struct cpu *cpu,
168            int disk_id, int disk_type, int iso_type, unsigned char *buf,
169            int *n_loadp, char ***load_namesp)
170    {
171            char str[35];
172            int filenr, i, ofs, dirlen, res = 0, res2, iadd = DEBUG_INDENTATION;
173            int found_dir;
174            uint64_t dirofs;
175            uint64_t fileofs, filelen;
176            unsigned char *dirbuf = NULL, *dp;
177            unsigned char *match_entry = NULL;
178            char *p, *filename_orig;
179            char *filename = strdup(cpu->machine->boot_kernel_filename);
180            unsigned char *filebuf = NULL;
181            char *tmpfname = NULL;
182            char **new_array;
183            int tmpfile_handle;
184    
185            if (filename == NULL) {
186                    fatal("out of memory\n");
187                    exit(1);
188            }
189            filename_orig = filename;
190    
191            debug("ISO9660 boot:\n");
192            debug_indentation(iadd);
193    
194            /*  Volume ID:  */
195            ofs = iso_type == 3? 48 : 40;
196            memcpy(str, buf + ofs, sizeof(str));
197            str[32] = '\0';  i = 31;
198            while (i >= 0 && str[i]==' ')
199                    str[i--] = '\0';
200            if (str[0])
201                    debug("\"%s\"", str);
202            else {
203                    /*  System ID:  */
204                    ofs = iso_type == 3? 16 : 8;
205                    memcpy(str, buf + ofs, sizeof(str));
206                    str[32] = '\0';  i = 31;
207                    while (i >= 0 && str[i]==' ')
208                            str[i--] = '\0';
209                    if (str[0])
210                            debug("\"%s\"", str);
211                    else
212                            debug("(no ID)");
213            }
214    
215            debug(":%s\n", filename);
216    
217    
218            /*
219             *  Traverse the directory structure to find the kernel.
220             */
221    
222            dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86];
223            if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89])
224                    fatal("WARNING: Root directory length mismatch?\n");
225    
226            dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) +
227                ((uint64_t)buf[0x8f] << 24)) * 2048;
228    
229    #ifdef ISO_DEBUG
230            debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs);
231    #endif
232    
233            dirbuf = malloc(dirlen);
234            if (dirbuf == NULL) {
235                    fatal("out of memory in iso_load_bootblock()\n");
236                    exit(1);
237            }
238    
239            res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf,
240                dirlen);
241            if (!res2) {
242                    fatal("Couldn't read the disk image. Aborting.\n");
243                    goto ret;
244            }
245    
246            found_dir = 1;  /*  Assume root dir  */
247            dp = dirbuf; filenr = 1;
248            p = NULL;
249            while (dp < dirbuf + dirlen) {
250                    size_t i, nlen = dp[0];
251                    int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) +
252                        ((uint64_t)dp[5] << 24);
253                    int y = dp[6] + (dp[7] << 8);
254                    char direntry[65];
255    
256                    dp += 8;
257    
258                    /*
259                     *  As long as there is an \ or / in the filename, then we
260                     *  have not yet found the directory.
261                     */
262                    p = strchr(filename, '/');
263                    if (p == NULL)
264                            p = strchr(filename, '\\');
265    
266    #ifdef ISO_DEBUG
267                    debug("%i%s: %i, %i, \"", filenr, filenr == found_dir?
268                        " [CURRENT]" : "", x, y);
269    #endif
270                    for (i=0; i<nlen && i<sizeof(direntry)-1; i++)
271                            if (dp[i]) {
272                                    direntry[i] = dp[i];
273    #ifdef ISO_DEBUG
274                                    debug("%c", dp[i]);
275    #endif
276                            } else
277                                    break;
278    #ifdef ISO_DEBUG
279                    debug("\"\n");
280    #endif
281                    direntry[i] = '\0';
282    
283                    /*  A directory name match?  */
284                    if ((p != NULL && strncasecmp(filename, direntry, nlen) == 0
285                        && nlen == (size_t)p - (size_t)filename && found_dir == y)
286                        || (p == NULL && direntry[0] == '\0') ) {
287                            found_dir = filenr;
288                            if (p != NULL)
289                                    filename = p+1;
290                            dirofs = 2048 * (int64_t)x;
291                    }
292    
293                    dp += nlen;
294    
295                    /*  16-bit aligned lenght:  */
296                    if (nlen & 1)
297                            dp ++;
298    
299                    filenr ++;
300            }
301    
302            p = strchr(filename, '/');
303            if (p == NULL)
304                    p = strchr(filename, '\\');
305    
306            if (p != NULL) {
307                    char *blah = filename_orig;
308    
309                    fatal("could not find '%s' in /", filename);
310    
311                    /*  Print the first part of the filename:  */
312                    while (blah != filename)
313                            fatal("%c", *blah++);
314                    
315                    fatal("\n");
316                    goto ret;
317            }
318    
319            /*  debug("dirofs = 0x%llx\n", (long long)dirofs);  */
320    
321            /*  Free the old dirbuf, and allocate a new one:  */
322            free(dirbuf);
323            dirbuf = malloc(512);
324            if (dirbuf == NULL) {
325                    fatal("out of memory in iso_load_bootblock()\n");
326                    exit(1);
327            }
328    
329            for (;;) {
330                    size_t len, i;
331    
332                    /*  Too close to another sector? Then realign.  */
333                    if ((dirofs & 2047) + 70 > 2047) {
334                            dirofs = (dirofs | 2047) + 1;
335                            /*  debug("realign dirofs = 0x%llx\n", dirofs);  */
336                    }
337    
338                    res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs,
339                        dirbuf, 256);
340                    if (!res2) {
341                            fatal("Couldn't read the disk image. Aborting.\n");
342                            goto ret;
343                    }
344    
345                    dp = dirbuf;
346                    len = dp[0];
347                    if (len < 2)
348                            break;
349    
350                    /*
351                     *  TODO: Actually parse the directory entry!
352                     *
353                     *  Haha, this must be rewritten.
354                     */
355                    for (i=32; i<len; i++) {
356                            if (i < len - strlen(filename))
357                                    if (strncasecmp(filename, (char *)dp + i,
358                                        strlen(filename)) == 0) {
359                                            /*  The filename was found somewhere
360                                                in the directory entry.  */
361                                            if (match_entry != NULL) {
362                                                    fatal("TODO: I'm too lazy to"
363                                                        " implement a correct "
364                                                        "directory parser right "
365                                                        "now... (BUG)\n");
366                                                    exit(1);
367                                            }
368                                            match_entry = malloc(512);
369                                            if (match_entry == NULL) {
370                                                    fatal("out of memory\n");
371                                                    exit(1);
372                                            }
373                                            memcpy(match_entry, dp, 512);
374                                            break;
375                                    }
376                    }
377    
378                    dirofs += len;
379            }
380    
381            if (match_entry == NULL) {
382                    char *blah = filename_orig;
383    
384                    fatal("could not find '%s' in /", filename);
385    
386                    /*  Print the first part of the filename:  */
387                    while (blah != filename)
388                            fatal("%c", *blah++);
389                    
390                    fatal("\n");
391                    goto ret;
392            }
393    
394            fileofs = match_entry[2] + (match_entry[3] << 8) +
395                (match_entry[4] << 16) + ((uint64_t)match_entry[5] << 24);
396            filelen = match_entry[10] + (match_entry[11] << 8) +
397                (match_entry[12] << 16) + ((uint64_t)match_entry[13] << 24);
398            fileofs *= 2048;
399    
400            /*  debug("filelen=%llx fileofs=%llx\n", (long long)filelen,
401                (long long)fileofs);  */
402    
403            filebuf = malloc(filelen);
404            if (filebuf == NULL) {
405                    fatal("could not allocate %lli bytes to read the file"
406                        " from the disk image!\n", (long long)filelen);
407                    goto ret;
408            }
409    
410            tmpfname = strdup("/tmp/gxemul.XXXXXXXXXXXX");
411    
412            res2 = diskimage_access(m, disk_id, disk_type, 0, fileofs, filebuf,
413                filelen);
414            if (!res2) {
415                    fatal("could not read the file from the disk image!\n");
416                    goto ret;
417            }
418    
419            tmpfile_handle = mkstemp(tmpfname);
420            if (tmpfile_handle < 0) {
421                    fatal("could not create %s\n", tmpfname);
422                    exit(1);
423            }
424            write(tmpfile_handle, filebuf, filelen);
425            close(tmpfile_handle);
426    
427            debug("extracted %lli bytes into %s\n", (long long)filelen, tmpfname);
428    
429            /*  Add the temporary filename to the load_namesp array:  */
430            (*n_loadp)++;
431            new_array = malloc(sizeof(char *) * (*n_loadp));
432            if (new_array == NULL) {
433                    fatal("out of memory\n");
434                    exit(1);
435            }
436            memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));
437            *load_namesp = new_array;
438    
439            /*  This adds a Backspace char in front of the filename; this
440                is a special hack which causes the file to be removed once
441                it has been loaded.  */
442            tmpfname = realloc(tmpfname, strlen(tmpfname) + 2);
443            memmove(tmpfname + 1, tmpfname, strlen(tmpfname) + 1);
444            tmpfname[0] = 8;
445    
446            (*load_namesp)[*n_loadp - 1] = tmpfname;
447    
448            res = 1;
449    
450    ret:
451            if (dirbuf != NULL)
452                    free(dirbuf);
453    
454            if (filebuf != NULL)
455                    free(filebuf);
456    
457            if (match_entry != NULL)
458                    free(match_entry);
459    
460            free(filename_orig);
461    
462            debug_indentation(-iadd);
463            return res;
464    }
465    
466    
467    /*
468     *  apple_load_bootblock():
469     *
470     *  Try to load a kernel from a disk image with an Apple Partition Table.
471     *
472     *  TODO: This function uses too many magic offsets and so on; it should be
473     *  cleaned up some day. See http://www.awprofessional.com/articles/
474     *      article.asp?p=376123&seqNum=3&rl=1  for some info on the Apple
475     *  partition format.
476     *
477     *  Returns 1 on success, 0 on failure.
478     */
479    static int apple_load_bootblock(struct machine *m, struct cpu *cpu,
480            int disk_id, int disk_type, int *n_loadp, char ***load_namesp)
481    {
482            unsigned char buf[0x8000];
483            int res, partnr, n_partitions = 0, n_hfs_partitions = 0;
484            uint64_t hfs_start, hfs_length;
485    
486            res = diskimage_access(m, disk_id, disk_type, 0, 0x0, buf, sizeof(buf));
487            if (!res) {
488                    fatal("apple_load_bootblock: couldn't read the disk "
489                        "image. Aborting.\n");
490                    return 0;
491            }
492    
493            partnr = 0;
494            do {
495                    int start, length;
496                    int ofs = 0x200 * (partnr + 1);
497                    if (partnr == 0)
498                            n_partitions = buf[ofs + 7];
499                    start = ((uint64_t)buf[ofs + 8] << 24) + (buf[ofs + 9] << 16) +
500                        (buf[ofs + 10] << 8) + buf[ofs + 11];
501                    length = ((uint64_t)buf[ofs+12] << 24) + (buf[ofs + 13] << 16) +
502                        (buf[ofs + 14] << 8) + buf[ofs + 15];
503    
504                    debug("partition %i: '%s', type '%s', start %i, length %i\n",
505                        partnr, buf + ofs + 0x10, buf + ofs + 0x30,
506                        start, length);
507    
508                    if (strcmp((char *)buf + ofs + 0x30, "Apple_HFS") == 0) {
509                            n_hfs_partitions ++;
510                            hfs_start = 512 * start;
511                            hfs_length = 512 * length;
512                    }
513    
514                    /*  Any more partitions?  */
515                    partnr ++;
516            } while (partnr < n_partitions);
517    
518            if (n_hfs_partitions == 0) {
519                    fatal("Error: No HFS partition found! TODO\n");
520                    return 0;
521            }
522            if (n_hfs_partitions >= 2) {
523                    fatal("Error: Too many HFS partitions found! TODO\n");
524                    return 0;
525            }
526    
527            return 0;
528  }  }
529    
530    
# Line 137  static void fix_console(void) Line 535  static void fix_console(void)
535   *  loading a bootblock from a specific disk offset into memory, and executing   *  loading a bootblock from a specific disk offset into memory, and executing
536   *  that, instead of requiring a separate kernel file.  It is then up to the   *  that, instead of requiring a separate kernel file.  It is then up to the
537   *  bootblock to load a kernel.   *  bootblock to load a kernel.
538     *
539     *  Returns 1 on success, 0 on failure.
540   */   */
541  static void load_bootblock(struct machine *m, struct cpu *cpu)  static int load_bootblock(struct machine *m, struct cpu *cpu,
542            int *n_loadp, char ***load_namesp)
543  {  {
544          int boot_disk_id;          int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
545                iso_type, retval = 0;
546          unsigned char minibuf[0x20];          unsigned char minibuf[0x20];
547          unsigned char *bootblock_buf;          unsigned char *bootblock_buf;
548          uint64_t bootblock_offset;          uint64_t bootblock_offset, base_offset;
549          uint64_t bootblock_loadaddr, bootblock_pc;          uint64_t bootblock_loadaddr, bootblock_pc;
         int n_blocks, res, readofs;  
550    
551          boot_disk_id = diskimage_bootdev(m);          boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
552          if (boot_disk_id < 0)          if (boot_disk_id < 0)
553                  return;                  return 0;
554    
555            base_offset = diskimage_get_baseoffset(m, boot_disk_id, boot_disk_type);
556    
557          switch (m->machine_type) {          switch (m->machine_type) {
558          case MACHINE_DEC:  
559            case MACHINE_DREAMCAST:
560                    if (!diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
561                        boot_disk_type)) {
562                            fatal("The Dreamcast emulation mode can only boot"
563                                " from CD images, not from other disk types.\n");
564                            exit(1);
565                    }
566    
567                    bootblock_buf = malloc(32768);
568                    if (bootblock_buf == NULL) {
569                            fprintf(stderr, "Out of memory.\n");
570                            exit(1);
571                    }
572    
573                    debug("loading Dreamcast IP.BIN from %s id %i\n",
574                        diskimage_types[boot_disk_type], boot_disk_id);
575    
576                    res = diskimage_access(m, boot_disk_id, boot_disk_type,
577                        0, base_offset, bootblock_buf, 0x8000);
578                    if (!res) {
579                            fatal("Couldn't read the disk image. Aborting.\n");
580                            return 0;
581                    }
582    
583                    if (strncmp((char *)bootblock_buf, "SEGA ", 5) != 0) {
584                            fatal("This is not a Dreamcast IP.BIN header.\n");
585                            free(bootblock_buf);
586                            return 0;
587                    }
588    
589                    /*  Store IP.BIN at 0x8c008000, and set entry point.  */
590                    store_buf(cpu, 0x8c008000, (char *)bootblock_buf, 32768);
591                    cpu->pc = 0x8c008300;
592    
593                    /*  Remember the name of the file to boot (1ST_READ.BIN):  */
594                    if (cpu->machine->boot_kernel_filename == NULL ||
595                        cpu->machine->boot_kernel_filename[0] == '\0') {
596                            int i = 0x60;
597                            while (i < 0x70) {
598                                    if (bootblock_buf[i] == ' ')
599                                            bootblock_buf[i] = 0;
600                                    i ++;
601                            }
602                            cpu->machine->boot_kernel_filename = strdup(
603                                (char *)bootblock_buf + 0x60);
604                    }
605    
606                    debug("boot filename: %s\n",
607                        cpu->machine->boot_kernel_filename);
608    
609                    free(bootblock_buf);
610    
611                    break;
612    
613            case MACHINE_PMAX:
614                  /*                  /*
615                   *  The first few bytes of a disk contains information about                   *  The first few bytes of a disk contains information about
616                   *  where the bootblock(s) are located. (These are all 32-bit                   *  where the bootblock(s) are located. (These are all 32-bit
# Line 169  static void load_bootblock(struct machin Line 627  static void load_bootblock(struct machin
627                   *  nr of blocks to read and offset are repeated until nr of                   *  nr of blocks to read and offset are repeated until nr of
628                   *  blocks to read is zero.                   *  blocks to read is zero.
629                   */                   */
630                  res = diskimage_access(m, boot_disk_id, 0, 0,                  res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
631                      minibuf, sizeof(minibuf));                      minibuf, sizeof(minibuf));
632    
633                  bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)                  bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
634                    + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);                    + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24);
635    
636                  /*  Convert loadaddr to uncached:  */                  /*  Convert loadaddr to uncached:  */
637                  if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&                  if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
638                      (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)                      (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) {
639                          fatal("\nWARNING! Weird load address 0x%08x.\n\n",                          fatal("\nWARNING! Weird load address 0x%08"PRIx32
640                              (int)bootblock_loadaddr);                              " for SCSI id %i.\n\n",
641                                (uint32_t)bootblock_loadaddr, boot_disk_id);
642                            if (bootblock_loadaddr == 0) {
643                                    fatal("I'm assuming that this is _not_ a "
644                                        "DEC bootblock.\nAre you sure you are"
645                                        " booting from the correct disk?\n");
646                                    exit(1);
647                            }
648                    }
649    
650                  bootblock_loadaddr &= 0x0fffffffULL;                  bootblock_loadaddr &= 0x0fffffffULL;
651                  bootblock_loadaddr |= 0xffffffffa0000000ULL;                  bootblock_loadaddr |= 0xffffffffa0000000ULL;
652    
653                  bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)                  bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
654                    + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);                    + (minibuf[0x16] << 16) + ((uint64_t)minibuf[0x17] << 24);
655    
656                  bootblock_pc &= 0x0fffffffULL;                  bootblock_pc &= 0x0fffffffULL;
657                  bootblock_pc |= 0xffffffffa0000000ULL;                  bootblock_pc |= 0xffffffffa0000000ULL;
# Line 196  static void load_bootblock(struct machin Line 663  static void load_bootblock(struct machin
663                  readofs = 0x18;                  readofs = 0x18;
664    
665                  for (;;) {                  for (;;) {
666                          res = diskimage_access(m, boot_disk_id, 0, readofs,                          res = diskimage_access(m, boot_disk_id, boot_disk_type,
667                              minibuf, sizeof(minibuf));                              0, readofs, minibuf, sizeof(minibuf));
668                          if (!res) {                          if (!res) {
669                                  printf("couldn't read disk?\n");                                  fatal("Couldn't read the disk image. "
670                                  exit(1);                                      "Aborting.\n");
671                                    return 0;
672                          }                          }
673    
674                          n_blocks = minibuf[0] + (minibuf[1] << 8)                          n_blocks = minibuf[0] + (minibuf[1] << 8)
675                            + (minibuf[2] << 16) + (minibuf[3] << 24);                            + (minibuf[2] << 16) + ((uint64_t)minibuf[3] << 24);
676    
677                          bootblock_offset = (minibuf[4] + (minibuf[5] << 8)                          bootblock_offset = (minibuf[4] + (minibuf[5] << 8) +
678                            + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;                            (minibuf[6]<<16) + ((uint64_t)minibuf[7]<<24)) * 512;
679    
680                          if (n_blocks < 1)                          if (n_blocks < 1)
681                                  break;                                  break;
# Line 225  static void load_bootblock(struct machin Line 693  static void load_bootblock(struct machin
693                                  exit(1);                                  exit(1);
694                          }                          }
695    
696                          res = diskimage_access(m, boot_disk_id, 0,                          res = diskimage_access(m, boot_disk_id, boot_disk_type,
697                              bootblock_offset, bootblock_buf, n_blocks * 512);                              0, bootblock_offset, bootblock_buf, n_blocks * 512);
698                          if (!res) {                          if (!res) {
699                                  fatal("WARNING: could not load bootblocks from"                                  fatal("WARNING: could not load bootblocks from"
700                                      " disk offset 0x%llx\n",                                      " disk offset 0x%llx\n",
# Line 242  static void load_bootblock(struct machin Line 710  static void load_bootblock(struct machin
710                  }                  }
711    
712                  debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");                  debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
713                  break;                  return 1;
714            }
715    
         case MACHINE_X86:  
                 cpu->cd.x86.mode = 16;  
                 cpu->pc = 0x7c00;  
716    
717                  bootblock_buf = malloc(512);          /*
718                  if (bootblock_buf == NULL) {           *  Try reading a kernel manually from the disk. The code here
719                          fprintf(stderr, "Out of memory.\n");           *  does not rely on machine-dependent boot blocks etc.
720                          exit(1);           */
721                  }          /*  ISO9660: (0x800 bytes at 0x8000 + base_offset)  */
722            bootblock_buf = malloc(0x800);
723                  res = diskimage_access(m, boot_disk_id, 0, 0,          if (bootblock_buf == NULL) {
724                      bootblock_buf, 512);                  fprintf(stderr, "Out of memory.\n");
725                  if (!res) {                  exit(1);
726                          printf("Couldn't read the disk image. Aborting.\n");          }
                         exit(1);  
                 }  
727    
728                  debug("loading PC bootsector from disk %i\n", boot_disk_id);          res = diskimage_access(m, boot_disk_id, boot_disk_type,
729                  if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)              0, base_offset + 0x8000, bootblock_buf, 0x800);
730                          debug("WARNING! The 0x55,0xAA marker is missing! "          if (!res) {
731                              "Booting anyway.\n");                  fatal("Couldn't read the disk image. Aborting.\n");
732                  store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);                  return 0;
733                  free(bootblock_buf);          }
734                  break;  
735            iso_type = 0;
736            if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)
737                    iso_type = 1;
738            if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)
739                    iso_type = 2;
740            if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)
741                    iso_type = 3;
742    
743          default:          if (iso_type != 0) {
744                  fatal("Booting from disk without a separate kernel "                  /*
745                      "doesn't work in this emulation mode.\n");                   *  If the user specified a kernel name, then load it from
746                  exit(1);                   *  disk.
747                     */
748                    if (cpu->machine->boot_kernel_filename == NULL ||
749                        cpu->machine->boot_kernel_filename[0] == '\0')
750                            fatal("\nISO9660 filesystem, but no kernel "
751                                "specified? (Use the -j option.)\n");
752                    else
753                            retval = iso_load_bootblock(m, cpu, boot_disk_id,
754                                boot_disk_type, iso_type, bootblock_buf,
755                                n_loadp, load_namesp);
756            }
757    
758            if (retval != 0)
759                    goto ret_ok;
760    
761            /*  Apple parition table:  */
762            res = diskimage_access(m, boot_disk_id, boot_disk_type,
763                0, 0x0, bootblock_buf, 0x800);
764            if (!res) {
765                    fatal("Couldn't read the disk image. Aborting.\n");
766                    return 0;
767            }
768            if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' &&
769                bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') {
770                    if (cpu->machine->boot_kernel_filename == NULL ||
771                        cpu->machine->boot_kernel_filename[0] == '\0')
772                            fatal("\nApple partition table, but no kernel "
773                                "specified? (Use the -j option.)\n");
774                    else
775                            retval = apple_load_bootblock(m, cpu, boot_disk_id,
776                                boot_disk_type, n_loadp, load_namesp);
777          }          }
778    
779    ret_ok:
780            free(bootblock_buf);
781            return retval;
782  }  }
783    
784    
# Line 282  static void load_bootblock(struct machin Line 787  static void load_bootblock(struct machin
787   *   *
788   *  Returns a reasonably initialized struct emul.   *  Returns a reasonably initialized struct emul.
789   */   */
790  struct emul *emul_new(char *name)  struct emul *emul_new(char *name, int id)
791  {  {
792          struct emul *e;          struct emul *e;
793          e = malloc(sizeof(struct emul));          e = malloc(sizeof(struct emul));
# Line 293  struct emul *emul_new(char *name) Line 798  struct emul *emul_new(char *name)
798    
799          memset(e, 0, sizeof(struct emul));          memset(e, 0, sizeof(struct emul));
800    
801            e->path = malloc(15);
802            if (e->path == NULL) {
803                    fprintf(stderr, "out of memory\n");
804                    exit(1);
805            }
806            snprintf(e->path, 15, "emul[%i]", id);
807    
808            e->settings = settings_new();
809    
810            settings_add(e->settings, "n_machines", 0,
811                SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
812                (void *) &e->n_machines);
813    
814            /*  TODO: More settings?  */
815    
816          /*  Sane default values:  */          /*  Sane default values:  */
817          e->n_machines = 0;          e->n_machines = 0;
818            e->next_serial_nr = 1;
819    
820          if (name != NULL) {          if (name != NULL) {
821                  e->name = strdup(name);                  e->name = strdup(name);
# Line 302  struct emul *emul_new(char *name) Line 823  struct emul *emul_new(char *name)
823                          fprintf(stderr, "out of memory in emul_new()\n");                          fprintf(stderr, "out of memory in emul_new()\n");
824                          exit(1);                          exit(1);
825                  }                  }
826    
827                    settings_add(e->settings, "name", 0,
828                        SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
829                        (void *) &e->name);
830          }          }
831    
832          return e;          return e;
# Line 309  struct emul *emul_new(char *name) Line 834  struct emul *emul_new(char *name)
834    
835    
836  /*  /*
837     *  emul_destroy():
838     *
839     *  Destroys a previously created emul object.
840     */
841    void emul_destroy(struct emul *emul)
842    {
843            int i;
844    
845            if (emul->name != NULL) {
846                    settings_remove(emul->settings, "name");
847                    free(emul->name);
848            }
849    
850            for (i=0; i<emul->n_machines; i++)
851                    machine_destroy(emul->machines[i]);
852    
853            if (emul->machines != NULL)
854                    free(emul->machines);
855    
856            /*  Remove any remaining level-1 settings:  */
857            settings_remove_all(emul->settings);
858            settings_destroy(emul->settings);
859    
860            free(emul);
861    }
862    
863    
864    /*
865   *  emul_add_machine():   *  emul_add_machine():
866   *   *
867   *  Calls machine_new(), adds the new machine into the emul struct, and   *  Calls machine_new(), adds the new machine into the emul struct, and
# Line 319  struct emul *emul_new(char *name) Line 872  struct emul *emul_new(char *name)
872  struct machine *emul_add_machine(struct emul *e, char *name)  struct machine *emul_add_machine(struct emul *e, char *name)
873  {  {
874          struct machine *m;          struct machine *m;
875            char tmpstr[20];
876            int i;
877    
878          m = machine_new(name, e);          m = machine_new(name, e, e->n_machines);
879          m->serial_nr = (e->next_serial_nr ++);          m->serial_nr = (e->next_serial_nr ++);
880    
881            i = e->n_machines;
882    
883          e->n_machines ++;          e->n_machines ++;
884          e->machines = realloc(e->machines,          e->machines = realloc(e->machines,
885              sizeof(struct machine *) * e->n_machines);              sizeof(struct machine *) * e->n_machines);
# Line 331  struct machine *emul_add_machine(struct Line 888  struct machine *emul_add_machine(struct
888                  exit(1);                  exit(1);
889          }          }
890    
891          e->machines[e->n_machines - 1] = m;          e->machines[i] = m;
892    
893            snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
894            settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
895                e->machines[i]->settings);
896    
897          return m;          return m;
898  }  }
899    
# Line 357  static void add_arc_components(struct ma Line 919  static void add_arc_components(struct ma
919    
920          len += 1048576 * m->memory_offset_in_mb;          len += 1048576 * m->memory_offset_in_mb;
921    
922          /*  NOTE/TODO: magic 12MB end of load program area  */          /*
923             *  NOTE/TODO: magic 12MB end of load program area
924             *
925             *  Hm. This breaks the old FreeBSD/MIPS snapshots...
926             */
927    #if 0
928          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
929              0x60000 + m->memory_offset_in_mb * 1048576,              0x60000 + m->memory_offset_in_mb * 1048576,
930              start-0x60000 - m->memory_offset_in_mb * 1048576,              start-0x60000 - m->memory_offset_in_mb * 1048576,
931              ARCBIOS_MEM_FreeMemory);              ARCBIOS_MEM_FreeMemory);
932    #endif
933          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
934              start, len, ARCBIOS_MEM_LoadedProgram);              start, len, ARCBIOS_MEM_LoadedProgram);
935    
936          scsicontroller = arcbios_get_scsicontroller();          scsicontroller = arcbios_get_scsicontroller(m);
937          if (scsicontroller == 0)          if (scsicontroller == 0)
938                  return;                  return;
939    
# Line 413  static void add_arc_components(struct ma Line 981  static void add_arc_components(struct ma
981                                  snprintf(component_string,                                  snprintf(component_string,
982                                      sizeof(component_string),                                      sizeof(component_string),
983                                      "scsi(0)cdrom(%i)", d->id);                                      "scsi(0)cdrom(%i)", d->id);
984                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
985                                      component_string, scsidevice);                                      component_string, scsidevice);
986    
987                                  snprintf(component_string,                                  snprintf(component_string,
988                                      sizeof(component_string),                                      sizeof(component_string),
989                                      "scsi(0)cdrom(%i)fdisk(0)", d->id);                                      "scsi(0)cdrom(%i)fdisk(0)", d->id);
990                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
991                                      component_string, scsidisk);                                      component_string, scsidisk);
992                          } else {                          } else {
993                                  snprintf(component_string,                                  snprintf(component_string,
994                                      sizeof(component_string),                                      sizeof(component_string),
995                                      "scsi(0)disk(%i)", d->id);                                      "scsi(0)disk(%i)", d->id);
996                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
997                                      component_string, scsidevice);                                      component_string, scsidevice);
998    
999                                  snprintf(component_string,                                  snprintf(component_string,
1000                                      sizeof(component_string),                                      sizeof(component_string),
1001                                      "scsi(0)disk(%i)rdisk(0)", d->id);                                      "scsi(0)disk(%i)rdisk(0)", d->id);
1002                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
1003                                      component_string, scsidisk);                                      component_string, scsidisk);
1004                          }                          }
1005                  }                  }
# Line 454  static void add_arc_components(struct ma Line 1022  static void add_arc_components(struct ma
1022  void emul_machine_setup(struct machine *m, int n_load, char **load_names,  void emul_machine_setup(struct machine *m, int n_load, char **load_names,
1023          int n_devices, char **device_names)          int n_devices, char **device_names)
1024  {  {
         struct emul *emul;  
1025          struct cpu *cpu;          struct cpu *cpu;
1026          int i, iadd=4;          int i, iadd = DEBUG_INDENTATION;
1027          uint64_t addr, memory_amount, entrypoint = 0, gp = 0, toc = 0;          uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
1028          int byte_order;          int byte_order;
1029    
         emul = m->emul;  
   
1030          debug("machine \"%s\":\n", m->name);          debug("machine \"%s\":\n", m->name);
1031          debug_indentation(iadd);          debug_indentation(iadd);
1032    
# Line 482  void emul_machine_setup(struct machine * Line 1047  void emul_machine_setup(struct machine *
1047    
1048          m->cpu_family = cpu_family_ptr_by_number(m->arch);          m->cpu_family = cpu_family_ptr_by_number(m->arch);
1049    
1050            if (m->arch == ARCH_ALPHA)
1051                    m->arch_pagesize = 8192;
1052    
1053          machine_memsize_fix(m);          machine_memsize_fix(m);
1054    
1055          /*          /*
# Line 502  void emul_machine_setup(struct machine * Line 1070  void emul_machine_setup(struct machine *
1070                  debug(" (offset by %iMB)", m->memory_offset_in_mb);                  debug(" (offset by %iMB)", m->memory_offset_in_mb);
1071                  memory_amount += 1048576 * m->memory_offset_in_mb;                  memory_amount += 1048576 * m->memory_offset_in_mb;
1072          }          }
1073          m->memory = memory_new(memory_amount);          m->memory = memory_new(memory_amount, m->arch);
1074          if (m->machine_type != MACHINE_USERLAND)          if (m->machine_type != MACHINE_USERLAND)
1075                  debug("\n");                  debug("\n");
1076    
# Line 529  void emul_machine_setup(struct machine * Line 1097  void emul_machine_setup(struct machine *
1097          }          }
1098          memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);          memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
1099    
         /*  Initialize dynamic binary translation, if available:  */  
         if (m->bintrans_enable)  
                 bintrans_init(m, m->memory);  
   
1100          debug("cpu0");          debug("cpu0");
1101          if (m->ncpus > 1)          if (m->ncpus > 1)
1102                  debug(" .. cpu%i", m->ncpus - 1);                  debug(" .. cpu%i", m->ncpus - 1);
1103          debug(": ");          debug(": ");
1104          for (i=0; i<m->ncpus; i++) {          for (i=0; i<m->ncpus; i++) {
1105                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
1106                  if (m->bintrans_enable)                  if (m->cpus[i] == NULL) {
1107                          bintrans_init_cpu(m->cpus[i]);                          fprintf(stderr, "Unable to create CPU object. "
1108                                "Aborting.");
1109                            exit(1);
1110                    }
1111          }          }
1112          debug("\n");          debug("\n");
1113    
1114    #if 0
1115            /*  Special case: The Playstation Portable has an additional CPU:  */
1116            if (m->machine_type == MACHINE_PSP) {
1117                    debug("cpu%i: ", m->ncpus);
1118                    m->cpus[m->ncpus] = cpu_new(m->memory, m,
1119                        0  /*  use 0 here to show info with debug()  */,
1120                        "Allegrex" /*  TODO  */);
1121                    debug("\n");
1122                    m->ncpus ++;
1123            }
1124    #endif
1125    
1126          if (m->use_random_bootstrap_cpu)          if (m->use_random_bootstrap_cpu)
1127                  m->bootstrap_cpu = random() % m->ncpus;                  m->bootstrap_cpu = random() % m->ncpus;
1128          else          else
# Line 555  void emul_machine_setup(struct machine * Line 1134  void emul_machine_setup(struct machine *
1134          if (m->userland_emul != NULL) {          if (m->userland_emul != NULL) {
1135                  useremul_name_to_useremul(cpu,                  useremul_name_to_useremul(cpu,
1136                      m->userland_emul, NULL, NULL, NULL);                      m->userland_emul, NULL, NULL, NULL);
1137                  cpu->memory_rw = userland_memory_rw;  
1138                    switch (m->arch) {
1139    #ifdef ENABLE_ALPHA
1140                    case ARCH_ALPHA:
1141                            cpu->memory_rw = alpha_userland_memory_rw;
1142                            break;
1143    #endif
1144                    default:cpu->memory_rw = userland_memory_rw;
1145                    }
1146          }          }
1147    
1148          if (m->use_x11)          if (m->use_x11)
1149                  x11_init(m);                  x11_init(m);
1150    
1151          /*  Fill memory with random bytes:  */          /*  Fill memory with random bytes:  */
         /*  TODO: This is MIPS-specific!  */  
1152          if (m->random_mem_contents) {          if (m->random_mem_contents) {
1153                  for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {                  for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
1154                          unsigned char data[256];                          unsigned char data[256];
1155                          unsigned int j;                          unsigned int j;
1156                          for (j=0; j<sizeof(data); j++)                          for (j=0; j<sizeof(data); j++)
1157                                  data[j] = random() & 255;                                  data[j] = random() & 255;
1158                          addr = 0xffffffff80000000ULL + i;                          cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
1159                          cpu->memory_rw(cpu, m->memory, addr, data, sizeof(data),                              MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
                             MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);  
1160                  }                  }
1161          }          }
1162    
         if ((m->machine_type == MACHINE_ARC ||  
             m->machine_type == MACHINE_SGI) && m->prom_emulation)  
                 arcbios_init();  
   
1163          if (m->userland_emul != NULL) {          if (m->userland_emul != NULL) {
1164                  /*                  /*
1165                   *  For userland-only emulation, no machine emulation                   *  For userland-only emulation, no machine emulation
# Line 592  void emul_machine_setup(struct machine * Line 1173  void emul_machine_setup(struct machine *
1173          }          }
1174    
1175          diskimage_dump_info(m);          diskimage_dump_info(m);
1176            console_debug_dump(m);
1177    
1178          /*  Load files (ROM code, boot code, ...) into memory:  */          /*  Load files (ROM code, boot code, ...) into memory:  */
1179          if (n_load == 0) {          if (n_load == 0) {
1180                  if (m->first_diskimage != NULL)                  if (m->first_diskimage != NULL) {
1181                          load_bootblock(m, cpu);                          if (!load_bootblock(m, cpu, &n_load, &load_names)) {
1182                  else {                                  fprintf(stderr, "\nNo executable files were"
1183                                        " specified, and booting directly from disk"
1184                                        " failed.\n");
1185                                    exit(1);
1186                            }
1187                    } else {
1188                          fprintf(stderr, "No executable file(s) loaded, and "                          fprintf(stderr, "No executable file(s) loaded, and "
1189                              "we are not booting directly from a disk image."                              "we are not booting directly from a disk image."
1190                              "\nAborting.\n");                              "\nAborting.\n");
# Line 606  void emul_machine_setup(struct machine * Line 1193  void emul_machine_setup(struct machine *
1193          }          }
1194    
1195          while (n_load > 0) {          while (n_load > 0) {
1196                    FILE *tmp_f;
1197                    char *name_to_load = *load_names;
1198                    int remove_after_load = 0;
1199    
1200                    /*  Special hack for removing temporary files:  */
1201                    if (name_to_load[0] == 8) {
1202                            name_to_load ++;
1203                            remove_after_load = 1;
1204                    }
1205    
1206                    /*
1207                     *  gzipped files are automagically gunzipped:
1208                     *  NOTE/TODO: This isn't secure. system() is used.
1209                     */
1210                    tmp_f = fopen(name_to_load, "r");
1211                    if (tmp_f != NULL) {
1212                            unsigned char buf[2];           /*  gzip header  */
1213                            memset(buf, 0, sizeof(buf));
1214                            fread(buf, 1, sizeof(buf), tmp_f);
1215                            if (buf[0]==0x1f && buf[1]==0x8b) {
1216                                    size_t zzlen = strlen(name_to_load)*2 + 100;
1217                                    char *zz = malloc(zzlen);
1218                                    debug("gunziping %s\n", name_to_load);
1219                                    /*
1220                                     *  gzip header found.  If this was a file
1221                                     *  extracted from, say, a CDROM image, then it
1222                                     *  already has a temporary name. Otherwise we
1223                                     *  have to gunzip into a temporary file.
1224                                     */
1225                                    if (remove_after_load) {
1226                                            snprintf(zz, zzlen, "mv %s %s.gz",
1227                                                name_to_load, name_to_load);
1228                                            system(zz);
1229                                            snprintf(zz, zzlen, "gunzip %s.gz",
1230                                                name_to_load);
1231                                            system(zz);
1232                                    } else {
1233                                            /*  gunzip into new temp file:  */
1234                                            int tmpfile_handle;
1235                                            char *new_temp_name =
1236                                                strdup("/tmp/gxemul.XXXXXXXXXXXX");
1237                                            tmpfile_handle = mkstemp(new_temp_name);
1238                                            close(tmpfile_handle);
1239                                            snprintf(zz, zzlen, "gunzip -c '%s' > "
1240                                                "%s", name_to_load, new_temp_name);
1241                                            system(zz);
1242                                            name_to_load = new_temp_name;
1243                                            remove_after_load = 1;
1244                                    }
1245                                    free(zz);
1246                            }
1247                            fclose(tmp_f);
1248                    }
1249    
1250                    /*
1251                     *  Ugly (but usable) hack for Playstation Portable:  If the
1252                     *  filename ends with ".pbp" and the file contains an ELF
1253                     *  header, then extract the ELF file into a temporary file.
1254                     */
1255                    if (strlen(name_to_load) > 4 && strcasecmp(name_to_load +
1256                        strlen(name_to_load) - 4, ".pbp") == 0 &&
1257                        (tmp_f = fopen(name_to_load, "r")) != NULL) {
1258                            off_t filesize, j, found=0;
1259                            unsigned char *buf;
1260                            fseek(tmp_f, 0, SEEK_END);
1261                            filesize = ftello(tmp_f);
1262                            fseek(tmp_f, 0, SEEK_SET);
1263                            buf = malloc(filesize);
1264                            if (buf == NULL) {
1265                                    fprintf(stderr, "out of memory while trying"
1266                                        " to read %s\n", name_to_load);
1267                                    exit(1);
1268                            }
1269                            fread(buf, 1, filesize, tmp_f);
1270                            fclose(tmp_f);
1271                            /*  Search for the ELF header, from offset 1 (!):  */
1272                            for (j=1; j<filesize - 4; j++)
1273                                    if (memcmp(buf + j, ELFMAG, SELFMAG) == 0) {
1274                                            found = j;
1275                                            break;
1276                                    }
1277                            if (found != 0) {
1278                                    int tmpfile_handle;
1279                                    char *new_temp_name =
1280                                        strdup("/tmp/gxemul.XXXXXXXXXXXX");
1281                                    debug("extracting ELF from %s (offset 0x%x)\n",
1282                                        name_to_load, (int)found);
1283                                    tmpfile_handle = mkstemp(new_temp_name);
1284                                    write(tmpfile_handle, buf + found,
1285                                        filesize - found);
1286                                    close(tmpfile_handle);
1287                                    name_to_load = new_temp_name;
1288                                    remove_after_load = 1;
1289                            }
1290                    }
1291    
1292                  byte_order = NO_BYTE_ORDER_OVERRIDE;                  byte_order = NO_BYTE_ORDER_OVERRIDE;
1293    
1294                  file_load(m, m->memory, *load_names, &entrypoint,                  /*
1295                     *  Load the file:  :-)
1296                     */
1297                    file_load(m, m->memory, name_to_load, &entrypoint,
1298                      m->arch, &gp, &byte_order, &toc);                      m->arch, &gp, &byte_order, &toc);
1299    
1300                    if (remove_after_load) {
1301                            debug("removing %s\n", name_to_load);
1302                            unlink(name_to_load);
1303                    }
1304    
1305                  if (byte_order != NO_BYTE_ORDER_OVERRIDE)                  if (byte_order != NO_BYTE_ORDER_OVERRIDE)
1306                          cpu->byte_order = byte_order;                          cpu->byte_order = byte_order;
1307    
1308                  cpu->pc = entrypoint;                  cpu->pc = entrypoint;
1309    
1310                  switch (m->arch) {                  switch (m->arch) {
1311    
1312                    case ARCH_ALPHA:
1313                            /*  For position-independent code:  */
1314                            cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
1315                            break;
1316    
1317                    case ARCH_ARM:
1318                            if (cpu->pc & 3) {
1319                                    fatal("ARM: lowest bits of pc set: TODO\n");
1320                                    exit(1);
1321                            }
1322                            cpu->pc &= 0xfffffffc;
1323                            break;
1324    
1325                    case ARCH_AVR:
1326                            cpu->pc &= 0xfffff;
1327                            if (cpu->pc & 1) {
1328                                    fatal("AVR: lowest bit of pc set: TODO\n");
1329                                    exit(1);
1330                            }
1331                            break;
1332    
1333                    case ARCH_RCA180X:
1334                            cpu->pc &= 0xffff;
1335                            break;
1336    
1337                    case ARCH_M68K:
1338                            break;
1339    
1340                  case ARCH_MIPS:                  case ARCH_MIPS:
1341                          if ((cpu->pc >> 32) == 0                          if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
                             && (cpu->pc & 0x80000000ULL))  
1342                                  cpu->pc |= 0xffffffff00000000ULL;                                  cpu->pc |= 0xffffffff00000000ULL;
1343    
1344                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
# Line 631  void emul_machine_setup(struct machine * Line 1350  void emul_machine_setup(struct machine *
1350                          break;                          break;
1351    
1352                  case ARCH_PPC:                  case ARCH_PPC:
1353                            /*  See http://www.linuxbase.org/spec/ELF/ppc64/
1354                                spec/x458.html for more info.  */
1355                          cpu->cd.ppc.gpr[2] = toc;                          cpu->cd.ppc.gpr[2] = toc;
1356                            /*  TODO  */
1357                            if (cpu->cd.ppc.bits == 32)
1358                                    cpu->pc &= 0xffffffffULL;
1359                            break;
1360    
1361                    case ARCH_SH:
1362                            if (cpu->cd.sh.cpu_type.bits == 32)
1363                                    cpu->pc &= 0xffffffffULL;
1364                            cpu->pc &= ~1;
1365                          break;                          break;
1366    
                 case ARCH_ALPHA:  
                 case ARCH_HPPA:  
1367                  case ARCH_SPARC:                  case ARCH_SPARC:
                 case ARCH_URISC:  
1368                          break;                          break;
1369    
1370                  case ARCH_X86:                  case ARCH_TRANSPUTER:
1371                          /*                          cpu->pc &= 0xffffffffULL;
                          *  NOTE: The toc field is used to indicate an ELF64  
                          *  load, on AMD64!  
                          */  
                         if (toc != 0) {  
                                 cpu->cd.x86.mode = 64;  
                         } else  
                                 cpu->pc &= 0xffffffffULL;  
1372                          break;                          break;
1373    
1374                  default:                  default:
# Line 686  void emul_machine_setup(struct machine * Line 1406  void emul_machine_setup(struct machine *
1406                  useremul_setup(cpu, n_load, load_names);                  useremul_setup(cpu, n_load, load_names);
1407    
1408          /*  Startup the bootstrap CPU:  */          /*  Startup the bootstrap CPU:  */
1409          cpu->bootstrap_cpu_flag = 1;          cpu->running = 1;
         cpu->running            = 1;  
1410    
1411          /*  ... or pause all CPUs, if start_paused is set:  */          /*  ... or pause all CPUs, if start_paused is set:  */
1412          if (m->start_paused) {          if (m->start_paused) {
# Line 699  void emul_machine_setup(struct machine * Line 1418  void emul_machine_setup(struct machine *
1418          add_dump_points(m);          add_dump_points(m);
1419    
1420          /*  TODO: This is MIPS-specific!  */          /*  TODO: This is MIPS-specific!  */
1421          if (m->machine_type == MACHINE_DEC &&          if (m->machine_type == MACHINE_PMAX &&
1422              cpu->cd.mips.cpu_type.mmu_model == MMU3K)              cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1423                  add_symbol_name(&m->symbol_context,                  add_symbol_name(&m->symbol_context,
1424                      0x9fff0000, 0x10000, "r2k3k_cache", 0);                      0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
1425    
1426          symbol_recalc_sizes(&m->symbol_context);          symbol_recalc_sizes(&m->symbol_context);
1427    
         if (m->max_random_cycles_per_chunk > 0)  
                 debug("using random cycle chunks (1 to %i cycles)\n",  
                     m->max_random_cycles_per_chunk);  
   
1428          /*  Special hack for ARC/SGI emulation:  */          /*  Special hack for ARC/SGI emulation:  */
1429          if ((m->machine_type == MACHINE_ARC ||          if ((m->machine_type == MACHINE_ARC ||
1430              m->machine_type == MACHINE_SGI) && m->prom_emulation)              m->machine_type == MACHINE_SGI) && m->prom_emulation)
# Line 717  void emul_machine_setup(struct machine * Line 1432  void emul_machine_setup(struct machine *
1432    
1433          debug("starting cpu%i at ", m->bootstrap_cpu);          debug("starting cpu%i at ", m->bootstrap_cpu);
1434          switch (m->arch) {          switch (m->arch) {
1435    
1436            case ARCH_ARM:
1437                    /*  ARM cpus aren't 64-bit:  */
1438                    debug("0x%08x", (int)entrypoint);
1439                    break;
1440    
1441            case ARCH_AVR:
1442                    /*  Atmel AVR uses a 16-bit or 22-bit program counter:  */
1443                    debug("0x%04x", (int)entrypoint);
1444                    break;
1445    
1446          case ARCH_MIPS:          case ARCH_MIPS:
1447                  if (cpu->cd.mips.cpu_type.isa_level < 3 ||                  if (cpu->is_32bit) {
                     cpu->cd.mips.cpu_type.isa_level == 32) {  
1448                          debug("0x%08x", (int)m->cpus[                          debug("0x%08x", (int)m->cpus[
1449                              m->bootstrap_cpu]->pc);                              m->bootstrap_cpu]->pc);
1450                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
# Line 734  void emul_machine_setup(struct machine * Line 1459  void emul_machine_setup(struct machine *
1459                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);
1460                  }                  }
1461                  break;                  break;
1462    
1463          case ARCH_PPC:          case ARCH_PPC:
1464                  if (cpu->cd.ppc.bits == 32)                  if (cpu->cd.ppc.bits == 32)
1465                          debug("0x%08x", (int)entrypoint);                          debug("0x%08x", (int)entrypoint);
1466                  else                  else
1467                          debug("0x%016llx", (long long)entrypoint);                          debug("0x%016llx", (long long)entrypoint);
1468                  break;                  break;
1469          case ARCH_URISC:  
1470                  {          default:
1471                          char tmps[100];                  if (cpu->is_32bit)
                         unsigned char buf[sizeof(uint64_t)];  
   
                         cpu->memory_rw(cpu, m->memory, 0, buf, sizeof(buf),  
                             MEM_READ, CACHE_NONE | NO_EXCEPTIONS);  
   
                         entrypoint = 0;  
                         for (i=0; i<cpu->cd.urisc.wordlen/8; i++) {  
                                 entrypoint <<= 8;  
                                 if (cpu->byte_order == EMUL_BIG_ENDIAN)  
                                         entrypoint += buf[i];  
                                 else  
                                         entrypoint += buf[cpu->  
                                             cd.urisc.wordlen/8 - 1 - i];  
                         }  
   
                         sprintf(tmps, "0x%%0%illx", cpu->cd.urisc.wordlen / 4);  
                         debug(tmps, (long long)entrypoint);  
                         cpu->pc = entrypoint;  
                 }  
                 break;  
         case ARCH_X86:  
                 if (cpu->cd.x86.mode == 16)  
                         debug("0x%04x:0x%04x", cpu->cd.x86.s[X86_S_CS],  
                             (int)cpu->pc);  
                 else if (cpu->cd.x86.mode == 32)  
1472                          debug("0x%08x", (int)cpu->pc);                          debug("0x%08x", (int)cpu->pc);
1473                  else                  else
1474                          debug("0x%016llx", (long long)cpu->pc);                          debug("0x%016llx", (long long)cpu->pc);
                 break;  
         default:  
                 debug("0x%016llx", (long long)cpu->pc);  
1475          }          }
1476          debug("\n");          debug("\n");
1477    
# Line 788  void emul_machine_setup(struct machine * Line 1486  void emul_machine_setup(struct machine *
1486   */   */
1487  void emul_dumpinfo(struct emul *e)  void emul_dumpinfo(struct emul *e)
1488  {  {
1489          int j, nm, iadd = 4;          int j, nm, iadd = DEBUG_INDENTATION;
1490    
1491          if (e->net != NULL)          if (e->net != NULL)
1492                  net_dumpinfo(e->net);                  net_dumpinfo(e->net);
# Line 817  void emul_dumpinfo(struct emul *e) Line 1515  void emul_dumpinfo(struct emul *e)
1515   */   */
1516  void emul_simple_init(struct emul *emul)  void emul_simple_init(struct emul *emul)
1517  {  {
1518          int iadd=4;          int iadd = DEBUG_INDENTATION;
1519          struct machine *m;          struct machine *m;
1520    
1521          if (emul->n_machines != 1) {          if (emul->n_machines != 1) {
# Line 831  void emul_simple_init(struct emul *emul) Line 1529  void emul_simple_init(struct emul *emul)
1529                  debug("Simple setup...\n");                  debug("Simple setup...\n");
1530                  debug_indentation(iadd);                  debug_indentation(iadd);
1531    
1532                  /*  Create a network:  */                  /*  Create a simple network:  */
1533                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
1534                      "10.0.0.0", 8);                      NET_DEFAULT_IPV4_MASK,
1535                        NET_DEFAULT_IPV4_LEN,
1536                        NULL, 0, 0, NULL);
1537          } else {          } else {
1538                  /*  Userland pseudo-machine:  */                  /*  Userland pseudo-machine:  */
1539                  debug("Syscall emulation (userland-only) setup...\n");                  debug("Syscall emulation (userland-only) setup...\n");
# Line 852  void emul_simple_init(struct emul *emul) Line 1552  void emul_simple_init(struct emul *emul)
1552   *   *
1553   *  Create an emul struct by reading settings from a configuration file.   *  Create an emul struct by reading settings from a configuration file.
1554   */   */
1555  struct emul *emul_create_from_configfile(char *fname)  struct emul *emul_create_from_configfile(char *fname, int id)
1556  {  {
1557          int iadd = 4;          int iadd = DEBUG_INDENTATION;
1558          struct emul *e = emul_new(fname);          struct emul *e = emul_new(fname, id);
         FILE *f;  
         char buf[128];  
         size_t len;  
1559    
1560          debug("Creating emulation from configfile \"%s\":\n", fname);          debug("Creating emulation from configfile \"%s\":\n", fname);
1561          debug_indentation(iadd);          debug_indentation(iadd);
1562    
1563          f = fopen(fname, "r");          emul_parse_config(e, fname);
         if (f == NULL) {  
                 perror(fname);  
                 exit(1);  
         }  
   
         /*  Read header: (must be !!gxemul)  */  
         len = fread(buf, 1, 8, f);  
         if (len != 8 || strncmp(buf, "!!gxemul", 8) != 0) {  
                 fprintf(stderr, "%s: must start with '!!gxemul'\n", fname);  
                 exit(1);  
         }  
   
         /*  Restart from beginning:  */  
         rewind(f);  
1564    
         emul_parse_config(e, f);  
   
         fclose(f);  
1565          debug_indentation(-iadd);          debug_indentation(-iadd);
1566          return e;          return e;
1567  }  }
# Line 908  void emul_run(struct emul **emuls, int n Line 1588  void emul_run(struct emul **emuls, int n
1588    
1589          atexit(fix_console);          atexit(fix_console);
1590    
         i = 79;  
         while (i-- > 0)  
                 debug("-");  
         debug("\n\n");  
   
1591          /*  Initialize the interactive debugger:  */          /*  Initialize the interactive debugger:  */
1592          debugger_init(emuls, n_emuls);          debugger_init(emuls, n_emuls);
1593    
1594            /*  Run any additional debugger commands before starting:  */
1595            for (i=0; i<n_emuls; i++) {
1596                    struct emul *emul = emuls[i];
1597                    if (emul->n_debugger_cmds > 0) {
1598                            int j;
1599                            if (i == 0)
1600                                    print_separator();
1601                            for (j = 0; j < emul->n_debugger_cmds; j ++) {
1602                                    debug("> %s\n", emul->debugger_cmds[j]);
1603                                    debugger_execute_cmd(emul->debugger_cmds[j],
1604                                        strlen(emul->debugger_cmds[j]));
1605                            }
1606                    }
1607            }
1608    
1609            print_separator();
1610            debug("\n");
1611    
1612    
1613          /*          /*
1614           *  console_init_main() makes sure that the terminal is in a           *  console_init_main() makes sure that the terminal is in a
1615           *  reasonable state.           *  reasonable state.
# Line 940  void emul_run(struct emul **emuls, int n Line 1634  void emul_run(struct emul **emuls, int n
1634                  if (e == NULL)                  if (e == NULL)
1635                          continue;                          continue;
1636                  for (j=0; j<e->n_machines; j++)                  for (j=0; j<e->n_machines; j++)
1637                          cpu_run_init(e, e->machines[j]);                          cpu_run_init(e->machines[j]);
1638          }          }
1639    
1640            /*  TODO: Generalize:  */
1641            if (emuls[0]->machines[0]->show_trace_tree)
1642                    cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1643                        emuls[0]->machines[0]->cpus[0]->pc);
1644    
1645            /*  Start emulated clocks:  */
1646            timer_start();
1647    
1648          /*          /*
1649           *  MAIN LOOP:           *  MAIN LOOP:
1650           *           *
# Line 952  void emul_run(struct emul **emuls, int n Line 1654  void emul_run(struct emul **emuls, int n
1654          while (go) {          while (go) {
1655                  go = 0;                  go = 0;
1656    
1657                  x11_check_event(emuls, n_emuls);                  /*  Flush X11 and serial console output every now and then:  */
1658                    if (emuls[0]->machines[0]->ninstrs >
1659                        emuls[0]->machines[0]->ninstrs_flush + (1<<19)) {
1660                            x11_check_event(emuls, n_emuls);
1661                            console_flush();
1662                            emuls[0]->machines[0]->ninstrs_flush =
1663                                emuls[0]->machines[0]->ninstrs;
1664                    }
1665    
1666                    if (emuls[0]->machines[0]->ninstrs >
1667                        emuls[0]->machines[0]->ninstrs_show + (1<<25)) {
1668                            emuls[0]->machines[0]->ninstrs_since_gettimeofday +=
1669                                (emuls[0]->machines[0]->ninstrs -
1670                                 emuls[0]->machines[0]->ninstrs_show);
1671                            cpu_show_cycles(emuls[0]->machines[0], 0);
1672                            emuls[0]->machines[0]->ninstrs_show =
1673                                emuls[0]->machines[0]->ninstrs;
1674                    }
1675    
1676                    if (single_step == ENTER_SINGLE_STEPPING) {
1677                            /*  TODO: Cleanup!  */
1678                            old_instruction_trace =
1679                                emuls[0]->machines[0]->instruction_trace;
1680                            old_quiet_mode = quiet_mode;
1681                            old_show_trace_tree =
1682                                emuls[0]->machines[0]->show_trace_tree;
1683                            emuls[0]->machines[0]->instruction_trace = 1;
1684                            emuls[0]->machines[0]->show_trace_tree = 1;
1685                            quiet_mode = 0;
1686                            single_step = SINGLE_STEPPING;
1687                    }
1688    
1689                    if (single_step == SINGLE_STEPPING)
1690                            debugger();
1691    
1692                  for (i=0; i<n_emuls; i++) {                  for (i=0; i<n_emuls; i++) {
1693                          e = emuls[i];                          e = emuls[i];
                         if (e == NULL)  
                                 continue;  
1694    
1695                          for (j=0; j<e->n_machines; j++) {                          for (j=0; j<e->n_machines; j++) {
1696                                  /*  TODO: cpu_run() is a strange name, since                                  if (e->machines[j]->gdb.port > 0)
1697                                      there can be multiple cpus in a machine  */                                          debugger_gdb_check_incoming(
1698                                  anything = cpu_run(e, e->machines[j]);                                              e->machines[j]);
1699    
1700                                    anything = machine_run(e->machines[j]);
1701                                  if (anything)                                  if (anything)
1702                                          go = 1;                                          go = 1;
1703                          }                          }
1704                  }                  }
1705          }          }
1706    
1707            /*  Stop any running timers:  */
1708            timer_stop();
1709    
1710          /*  Deinitialize all CPUs in all machines in all emulations:  */          /*  Deinitialize all CPUs in all machines in all emulations:  */
1711          for (i=0; i<n_emuls; i++) {          for (i=0; i<n_emuls; i++) {
1712                  e = emuls[i];                  e = emuls[i];
1713                  if (e == NULL)                  if (e == NULL)
1714                          continue;                          continue;
1715                  for (j=0; j<e->n_machines; j++)                  for (j=0; j<e->n_machines; j++)
1716                          cpu_run_deinit(e, e->machines[j]);                          cpu_run_deinit(e->machines[j]);
1717          }          }
1718    
1719          /*  force_debugger_at_exit flag set? Then enter the debugger:  */          /*  force_debugger_at_exit flag set? Then enter the debugger:  */
# Line 985  void emul_run(struct emul **emuls, int n Line 1723  void emul_run(struct emul **emuls, int n
1723                  debugger();                  debugger();
1724          }          }
1725    
1726          /*  Any machine using X11? Then we should wait before exiting:  */          /*  Any machine using X11? Then wait before exiting:  */
1727          n = 0;          n = 0;
1728          for (i=0; i<n_emuls; i++)          for (i=0; i<n_emuls; i++)
1729                  for (j=0; j<emuls[i]->n_machines; j++)                  for (j=0; j<emuls[i]->n_machines; j++)
# Line 995  void emul_run(struct emul **emuls, int n Line 1733  void emul_run(struct emul **emuls, int n
1733                  printf("Press enter to quit.\n");                  printf("Press enter to quit.\n");
1734                  while (!console_charavail(MAIN_CONSOLE)) {                  while (!console_charavail(MAIN_CONSOLE)) {
1735                          x11_check_event(emuls, n_emuls);                          x11_check_event(emuls, n_emuls);
1736                          usleep(1);                          usleep(10000);
1737                  }                  }
1738                  console_readchar(MAIN_CONSOLE);                  console_readchar(MAIN_CONSOLE);
1739          }          }
1740    
1741          console_deinit();          console_deinit_main();
1742  }  }
1743    

Legend:
Removed from v.4  
changed lines
  Added in v.34

  ViewVC Help
Powered by ViewVC 1.1.26