/[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 10 by dpavlin, Mon Oct 8 16:18:27 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 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.211 2005/06/26 11:36:28 debug Exp $   *  $Id: emul.c,v 1.297 2007/06/15 17:02:37 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"
# Line 52  Line 51 
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 "sgi_arcbios.h"  #include "settings.h"
55    #include "timer.h"
56    #include "useremul.h"
57  #include "x11.h"  #include "x11.h"
58    
59    
 extern int force_debugger_at_exit;  
   
60  extern int extra_argc;  extern int extra_argc;
61  extern char **extra_argv;  extern char **extra_argv;
62    
63  extern int verbose;  extern int verbose;
64  extern int quiet_mode;  extern int quiet_mode;
65    extern int force_debugger_at_exit;
66  extern struct emul *debugger_emul;  extern int single_step;
67  extern struct diskimage *diskimages[];  extern int old_show_trace_tree;
68    extern int old_instruction_trace;
69  static char *diskimage_types[] = DISKIMAGE_TYPES;  extern int old_quiet_mode;
70    extern int quiet_mode;
71    extern int native_code_translation_enabled;
72    
73    
74  /*  /*
75   *  add_dump_points():   *  add_breakpoints():
76   *   *
77   *  Take the strings breakpoint_string[] and convert to addresses   *  Take the strings breakpoint_string[] and convert to addresses
78   *  (and store them in breakpoint_addr[]).   *  (and store them in breakpoint_addr[]).
79   *   *
80   *  TODO: This function should be moved elsewhere.   *  TODO: This function should be moved elsewhere.
81   */   */
82  static void add_dump_points(struct machine *m)  static void add_breakpoints(struct machine *m)
83  {  {
84          int i;          int i;
85          int string_flag;          int string_flag;
86          uint64_t dp;          uint64_t dp;
87    
88          for (i=0; i<m->n_breakpoints; i++) {          for (i=0; i<m->breakpoints.n; i++) {
89                  string_flag = 0;                  string_flag = 0;
90                  dp = strtoull(m->breakpoint_string[i], NULL, 0);                  dp = strtoull(m->breakpoints.string[i], NULL, 0);
91    
92                  /*                  /*
93                   *  If conversion resulted in 0, then perhaps it is a                   *  If conversion resulted in 0, then perhaps it is a
# Line 95  static void add_dump_points(struct machi Line 96  static void add_dump_points(struct machi
96                  if (dp == 0) {                  if (dp == 0) {
97                          uint64_t addr;                          uint64_t addr;
98                          int res = get_symbol_addr(&m->symbol_context,                          int res = get_symbol_addr(&m->symbol_context,
99                              m->breakpoint_string[i], &addr);                              m->breakpoints.string[i], &addr);
100                          if (!res)                          if (!res) {
101                                  fprintf(stderr,                                  fprintf(stderr,
102                                      "WARNING! Breakpoint '%s' could not be"                                      "ERROR! Breakpoint '%s' could not be"
103                                          " parsed\n",                                          " parsed\n",
104                                      m->breakpoint_string[i]);                                      m->breakpoints.string[i]);
105                          else {                                  exit(1);
106                            } else {
107                                  dp = addr;                                  dp = addr;
108                                  string_flag = 1;                                  string_flag = 1;
109                          }                          }
# Line 112  static void add_dump_points(struct machi Line 114  static void add_dump_points(struct machi
114                   *  were automatically converted into the correct address.                   *  were automatically converted into the correct address.
115                   */                   */
116    
117                  if ((dp >> 32) == 0 && ((dp >> 31) & 1))                  if (m->arch == ARCH_MIPS) {
118                          dp |= 0xffffffff00000000ULL;                          if ((dp >> 32) == 0 && ((dp >> 31) & 1))
119                  m->breakpoint_addr[i] = dp;                                  dp |= 0xffffffff00000000ULL;
120                    }
121    
122                    m->breakpoints.addr[i] = dp;
123    
124                  debug("breakpoint %i: 0x%016llx", i, (long long)dp);                  debug("breakpoint %i: 0x%llx", i, (long long)dp);
125                  if (string_flag)                  if (string_flag)
126                          debug(" (%s)", m->breakpoint_string[i]);                          debug(" (%s)", m->breakpoints.string[i]);
127                  debug("\n");                  debug("\n");
128          }          }
129  }  }
# Line 129  static void add_dump_points(struct machi Line 134  static void add_dump_points(struct machi
134   */   */
135  static void fix_console(void)  static void fix_console(void)
136  {  {
137          console_deinit();          console_deinit_main();
138  }  }
139    
140    
141  /*  /*
142   *  iso_load_bootblock():   *  emul_new():
  *  
  *  Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for  
  *  "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra).  
  *  
  *  TODO: This function uses too many magic offsets and so on; it should be  
  *  cleaned up some day.  
143   *   *
144   *  Returns 1 on success, 0 on failure.   *  Returns a reasonably initialized struct emul.
145   */   */
146  static int iso_load_bootblock(struct machine *m, struct cpu *cpu,  struct emul *emul_new(char *name, int id)
         int disk_id, int disk_type, int iso_type, unsigned char *buf,  
         int *n_loadp, char ***load_namesp)  
147  {  {
148          char str[35];          struct emul *e;
         int filenr, i, ofs, dirlen, res = 0, res2, iadd = 4;  
         int found_dir;  
         uint64_t dirofs;  
         uint64_t fileofs, filelen;  
         unsigned char *dirbuf = NULL, *dp;  
         unsigned char *match_entry = NULL;  
         char *p, *filename_orig;  
         char *filename = strdup(cpu->machine->boot_kernel_filename);  
         unsigned char *filebuf = NULL;  
         char *tmpfilename = NULL;  
         char **new_array;  
         int tmpfile_handle;  
   
         if (filename == NULL) {  
                 fatal("out of memory\n");  
                 exit(1);  
         }  
         filename_orig = filename;  
   
         debug("ISO9660 boot:\n");  
         debug_indentation(iadd);  
   
         /*  Volume ID:  */  
         ofs = iso_type == 3? 48 : 40;  
         memcpy(str, buf + ofs, sizeof(str));  
         str[32] = '\0';  i = 31;  
         while (i >= 0 && str[i]==' ')  
                 str[i--] = '\0';  
         if (str[0])  
                 debug("\"%s\"", str);  
         else {  
                 /*  System ID:  */  
                 ofs = iso_type == 3? 16 : 8;  
                 memcpy(str, buf + ofs, sizeof(str));  
                 str[32] = '\0';  i = 31;  
                 while (i >= 0 && str[i]==' ')  
                         str[i--] = '\0';  
                 if (str[0])  
                         debug("\"%s\"", str);  
                 else  
                         debug("(no ID)");  
         }  
   
         debug(":%s\n", filename);  
   
   
         /*  
          *  Traverse the directory structure to find the kernel.  
          */  
   
         dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86];  
         if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89])  
                 fatal("WARNING: Root directory length mismatch?\n");  
   
         dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) +  
             (buf[0x8f] << 24)) * 2048;  
   
         /*  debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs);  */  
   
         dirbuf = malloc(dirlen);  
         if (dirbuf == NULL) {  
                 fatal("out of memory in iso_load_bootblock()\n");  
                 exit(1);  
         }  
   
         res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf,  
             dirlen);  
         if (!res2) {  
                 fatal("Couldn't read the disk image. Aborting.\n");  
                 goto ret;  
         }  
   
         found_dir = 1;  /*  Assume root dir  */  
         dp = dirbuf; filenr = 1;  
         p = NULL;  
         while (dp < dirbuf + dirlen) {  
                 int i, nlen = dp[0];  
                 int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) + (dp[5] << 24);  
                 int y = dp[6] + (dp[7] << 8);  
                 char direntry[65];  
   
                 dp += 8;  
   
                 /*  
                  *  As long as there is an \ or / in the filename, then we  
                  *  have not yet found the directory.  
                  */  
                 p = strchr(filename, '/');  
                 if (p == NULL)  
                         p = strchr(filename, '\\');  
   
                 /*  debug("%i%s: %i, %i, \"", filenr, filenr == found_dir?  
                     " [CURRENT]" : "", x, y);  */  
                 for (i=0; i<nlen && i<sizeof(direntry)-1; i++)  
                         if (dp[i]) {  
                                 direntry[i] = dp[i];  
                                 /*  debug("%c", dp[i]);  */  
                         } else  
                                 break;  
                 /*  debug("\"\n");  */  
                 direntry[i] = '\0';  
   
                 /*  A directory name match?  */  
                 if (p != NULL && strncasecmp(filename, direntry, nlen) == 0  
                     && nlen == (size_t)p - (size_t)filename && found_dir == y) {  
                         found_dir = filenr;  
                         filename = p+1;  
                         dirofs = 2048 * (int64_t)x;  
                 }  
   
                 dp += nlen;  
   
                 /*  16-bit aligned lenght:  */  
                 if (nlen & 1)  
                         dp ++;  
   
                 filenr ++;  
         }  
   
         p = strchr(filename, '/');  
         if (p == NULL)  
                 p = strchr(filename, '\\');  
   
         if (p != NULL) {  
                 char *blah = filename_orig;  
   
                 fatal("could not find '%s' in /", filename);  
   
                 /*  Print the first part of the filename:  */  
                 while (blah != filename)  
                         fatal("%c", *blah++);  
                   
                 fatal("\n");  
                 goto ret;  
         }  
   
         /*  debug("dirofs = 0x%llx\n", (long long)dirofs);  */  
   
         /*  Free the old dirbuf, and allocate a new one:  */  
         free(dirbuf);  
         dirbuf = malloc(512);  
         if (dirbuf == NULL) {  
                 fatal("out of memory in iso_load_bootblock()\n");  
                 exit(1);  
         }  
   
         for (;;) {  
                 int len, i;  
   
                 /*  Too close to another sector? Then realign.  */  
                 if ((dirofs & 2047) + 70 > 2047) {  
                         dirofs = (dirofs | 2047) + 1;  
                         /*  debug("realign dirofs = 0x%llx\n", dirofs);  */  
                 }  
   
                 res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs,  
                     dirbuf, 256);  
                 if (!res2) {  
                         fatal("Couldn't read the disk image. Aborting.\n");  
                         goto ret;  
                 }  
   
                 dp = dirbuf;  
                 len = dp[0];  
                 if (len < 2)  
                         break;  
   
                 /*  
                  *  TODO: Actually parse the directory entry!  
                  *  
                  *  Haha, this must be rewritten.  
                  */  
                 for (i=32; i<len; i++) {  
                         if (i < len - strlen(filename))  
                                 if (strncasecmp(filename, (char *)dp + i,  
                                     strlen(filename)) == 0) {  
                                         /*  The filename was found somewhere  
                                             in the directory entry.  */  
                                         if (match_entry != NULL) {  
                                                 fatal("TODO: I'm too lazy to"  
                                                     " implement a correct "  
                                                     "directory parser right "  
                                                     "now... (BUG)\n");  
                                                 exit(1);  
                                         }  
                                         match_entry = malloc(512);  
                                         if (match_entry == NULL) {  
                                                 fatal("out of memory\n");  
                                                 exit(1);  
                                         }  
                                         memcpy(match_entry, dp, 512);  
                                         break;  
                                 }  
                 }  
   
                 dirofs += len;  
         }  
   
         if (match_entry == NULL) {  
                 char *blah = filename_orig;  
   
                 fatal("could not find '%s' in /", filename);  
   
                 /*  Print the first part of the filename:  */  
                 while (blah != filename)  
                         fatal("%c", *blah++);  
                   
                 fatal("\n");  
                 goto ret;  
         }  
149    
150          fileofs = match_entry[2] + (match_entry[3] << 8) +          CHECK_ALLOCATION(e = malloc(sizeof(struct emul)));
151              (match_entry[4] << 16) + (match_entry[5] << 24);          memset(e, 0, sizeof(struct emul));
         filelen = match_entry[10] + (match_entry[11] << 8) +  
             (match_entry[12] << 16) + (match_entry[13] << 24);  
         fileofs *= 2048;  
152    
153          /*  debug("filelen=%llx fileofs=%llx\n", (long long)filelen,          CHECK_ALLOCATION(e->path = malloc(15));
154              (long long)fileofs);  */          snprintf(e->path, 15, "emul[%i]", id);
155    
156          filebuf = malloc(filelen);          e->settings = settings_new();
         if (filebuf == NULL) {  
                 fatal("could not allocate %lli bytes to read the file"  
                     " from the disk image!\n", (long long)filelen);  
                 goto ret;  
         }  
157    
158          tmpfilename = strdup("/tmp/gxemul.XXXXXXXXXXXX");          settings_add(e->settings, "n_machines", 0,
159                SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
160                (void *) &e->n_machines);
161    
162          debug("extracting %lli bytes into %s\n",          /*  TODO: More settings?  */
             (long long)filelen, tmpfilename);  
   
         res2 = diskimage_access(m, disk_id, disk_type, 0, fileofs, filebuf,  
             filelen);  
         if (!res2) {  
                 fatal("could not read the file from the disk image!\n");  
                 goto ret;  
         }  
163    
164          tmpfile_handle = mkstemp(tmpfilename);          /*  Sane default values:  */
165          if (tmpfile_handle < 0) {          e->n_machines = 0;
166                  fatal("could not create %s\n", tmpfilename);          e->next_serial_nr = 1;
                 exit(1);  
         }  
         write(tmpfile_handle, filebuf, filelen);  
         close(tmpfile_handle);  
167    
168          /*  Add the temporary filename to the load_namesp array:  */          if (name != NULL) {
169          (*n_loadp)++;                  CHECK_ALLOCATION(e->name = strdup(name));
170          new_array = malloc(sizeof(char *) * (*n_loadp));                  settings_add(e->settings, "name", 0,
171          if (new_array == NULL) {                      SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
172                  fatal("out of memory\n");                      (void *) &e->name);
                 exit(1);  
173          }          }
         memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));  
         *load_namesp = new_array;  
   
         /*  This adds a Backspace char in front of the filename; this  
             is a special hack which causes the file to be removed once  
             it has been loaded.  */  
         tmpfilename = realloc(tmpfilename, strlen(tmpfilename) + 2);  
         memmove(tmpfilename + 1, tmpfilename, strlen(tmpfilename) + 1);  
         tmpfilename[0] = 8;  
   
         (*load_namesp)[*n_loadp - 1] = tmpfilename;  
   
         res = 1;  
   
 ret:  
         if (dirbuf != NULL)  
                 free(dirbuf);  
   
         if (filebuf != NULL)  
                 free(filebuf);  
174    
175          if (match_entry != NULL)          return e;
                 free(match_entry);  
   
         free(filename_orig);  
   
         debug_indentation(-iadd);  
         return res;  
176  }  }
177    
178    
179  /*  /*
180   *  load_bootblock():   *  emul_destroy():
  *  
  *  For some emulation modes, it is possible to boot from a harddisk image by  
  *  loading a bootblock from a specific disk offset into memory, and executing  
  *  that, instead of requiring a separate kernel file.  It is then up to the  
  *  bootblock to load a kernel.  
181   *   *
182   *  Returns 1 on success, 0 on failure.   *  Destroys a previously created emul object.
183   */   */
184  static int load_bootblock(struct machine *m, struct cpu *cpu,  void emul_destroy(struct emul *emul)
         int *n_loadp, char ***load_namesp)  
185  {  {
186          int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,          int i;
             iso_type, retval = 0;  
         unsigned char minibuf[0x20];  
         unsigned char *bootblock_buf;  
         uint64_t bootblock_offset;  
         uint64_t bootblock_loadaddr, bootblock_pc;  
   
         boot_disk_id = diskimage_bootdev(m, &boot_disk_type);  
         if (boot_disk_id < 0)  
                 return 0;  
   
         switch (m->machine_type) {  
         case MACHINE_DEC:  
                 /*  
                  *  The first few bytes of a disk contains information about  
                  *  where the bootblock(s) are located. (These are all 32-bit  
                  *  little-endian words.)  
                  *  
                  *  Offset 0x10 = load address  
                  *         0x14 = initial PC value  
                  *         0x18 = nr of 512-byte blocks to read  
                  *         0x1c = offset on disk to where the bootblocks  
                  *                are (in 512-byte units)  
                  *         0x20 = nr of blocks to read...  
                  *         0x24 = offset...  
                  *  
                  *  nr of blocks to read and offset are repeated until nr of  
                  *  blocks to read is zero.  
                  */  
                 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,  
                     minibuf, sizeof(minibuf));  
   
                 bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)  
                   + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);  
   
                 /*  Convert loadaddr to uncached:  */  
                 if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&  
                     (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)  
                         fatal("\nWARNING! Weird load address 0x%08x.\n\n",  
                             (int)bootblock_loadaddr);  
                 bootblock_loadaddr &= 0x0fffffffULL;  
                 bootblock_loadaddr |= 0xffffffffa0000000ULL;  
   
                 bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)  
                   + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);  
   
                 bootblock_pc &= 0x0fffffffULL;  
                 bootblock_pc |= 0xffffffffa0000000ULL;  
                 cpu->pc = bootblock_pc;  
   
                 debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",  
                     (int)bootblock_loadaddr, (int)bootblock_pc);  
   
                 readofs = 0x18;  
   
                 for (;;) {  
                         res = diskimage_access(m, boot_disk_id, boot_disk_type,  
                             0, readofs, minibuf, sizeof(minibuf));  
                         if (!res) {  
                                 fatal("Couldn't read the disk image. "  
                                     "Aborting.\n");  
                                 return 0;  
                         }  
   
                         n_blocks = minibuf[0] + (minibuf[1] << 8)  
                           + (minibuf[2] << 16) + (minibuf[3] << 24);  
   
                         bootblock_offset = (minibuf[4] + (minibuf[5] << 8)  
                           + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;  
   
                         if (n_blocks < 1)  
                                 break;  
   
                         debug(readofs == 0x18? ": %i" : " + %i", n_blocks);  
   
                         if (n_blocks * 512 > 65536)  
                                 fatal("\nWARNING! Unusually large bootblock "  
                                     "(%i bytes)\n\n", n_blocks * 512);  
   
                         bootblock_buf = malloc(n_blocks * 512);  
                         if (bootblock_buf == NULL) {  
                                 fprintf(stderr, "out of memory in "  
                                     "load_bootblock()\n");  
                                 exit(1);  
                         }  
   
                         res = diskimage_access(m, boot_disk_id, boot_disk_type,  
                             0, bootblock_offset, bootblock_buf, n_blocks * 512);  
                         if (!res) {  
                                 fatal("WARNING: could not load bootblocks from"  
                                     " disk offset 0x%llx\n",  
                                     (long long)bootblock_offset);  
                         }  
   
                         store_buf(cpu, bootblock_loadaddr,  
                             (char *)bootblock_buf, n_blocks * 512);  
   
                         bootblock_loadaddr += 512*n_blocks;  
                         free(bootblock_buf);  
                         readofs += 8;  
                 }  
   
                 debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");  
                 return 1;  
   
         case MACHINE_X86:  
                 /*  TODO: "El Torito" etc?  */  
                 if (diskimage_is_a_cdrom(cpu->machine, boot_disk_id,  
                     boot_disk_type))  
                         break;  
   
                 bootblock_buf = malloc(512);  
                 if (bootblock_buf == NULL) {  
                         fprintf(stderr, "Out of memory.\n");  
                         exit(1);  
                 }  
   
                 debug("loading PC bootsector from %s id %i\n",  
                     diskimage_types[boot_disk_type], boot_disk_id);  
   
                 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,  
                     bootblock_buf, 512);  
                 if (!res) {  
                         fatal("Couldn't read the disk image. Aborting.\n");  
                         return 0;  
                 }  
   
                 if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)  
                         debug("WARNING! The 0x55,0xAA marker is missing! "  
                             "Booting anyway.\n");  
                 store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);  
                 free(bootblock_buf);  
   
                 return 1;  
         }  
   
   
         /*  
          *  Try reading a kernel manually from the disk. The code here  
          *  does not rely on machine-dependant boot blocks etc.  
          */  
         /*  ISO9660: (0x800 bytes at 0x8000)  */  
         bootblock_buf = malloc(0x800);  
         if (bootblock_buf == NULL) {  
                 fprintf(stderr, "Out of memory.\n");  
                 exit(1);  
         }  
   
         res = diskimage_access(m, boot_disk_id, boot_disk_type,  
             0, 0x8000, bootblock_buf, 0x800);  
         if (!res) {  
                 fatal("Couldn't read the disk image. Aborting.\n");  
                 return 0;  
         }  
   
         iso_type = 0;  
         if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)  
                 iso_type = 1;  
         if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)  
                 iso_type = 2;  
         if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)  
                 iso_type = 3;  
   
         if (iso_type != 0) {  
                 /*  We can't load a kernel if the name  
                     isn't specified.  */  
                 if (cpu->machine->boot_kernel_filename == NULL ||  
                     cpu->machine->boot_kernel_filename[0] == '\0')  
                         fatal("\nISO9660 filesystem, but no kernel "  
                             "specified? (Use the -j option.)\n");  
                 else  
                         retval = iso_load_bootblock(m, cpu, boot_disk_id,  
                             boot_disk_type, iso_type, bootblock_buf,  
                             n_loadp, load_namesp);  
         }  
   
         free(bootblock_buf);  
         return retval;  
 }  
   
187    
188  /*          if (emul->name != NULL) {
189   *  emul_new():                  settings_remove(emul->settings, "name");
190   *                  free(emul->name);
  *  Returns a reasonably initialized struct emul.  
  */  
 struct emul *emul_new(char *name)  
 {  
         struct emul *e;  
         e = malloc(sizeof(struct emul));  
         if (e == NULL) {  
                 fprintf(stderr, "out of memory in emul_new()\n");  
                 exit(1);  
191          }          }
192    
193          memset(e, 0, sizeof(struct emul));          for (i=0; i<emul->n_machines; i++)
194                    machine_destroy(emul->machines[i]);
195    
196          /*  Sane default values:  */          if (emul->machines != NULL)
197          e->n_machines = 0;                  free(emul->machines);
         e->next_serial_nr = 1;  
198    
199          if (name != NULL) {          /*  Remove any remaining level-1 settings:  */
200                  e->name = strdup(name);          settings_remove_all(emul->settings);
201                  if (e->name == NULL) {          settings_destroy(emul->settings);
                         fprintf(stderr, "out of memory in emul_new()\n");  
                         exit(1);  
                 }  
         }  
202    
203          return e;          free(emul);
204  }  }
205    
206    
# Line 671  struct emul *emul_new(char *name) Line 215  struct emul *emul_new(char *name)
215  struct machine *emul_add_machine(struct emul *e, char *name)  struct machine *emul_add_machine(struct emul *e, char *name)
216  {  {
217          struct machine *m;          struct machine *m;
218            char tmpstr[20];
219            int i;
220    
221          m = machine_new(name, e);          m = machine_new(name, e, e->n_machines);
222          m->serial_nr = (e->next_serial_nr ++);          m->serial_nr = (e->next_serial_nr ++);
223    
224          e->n_machines ++;          i = e->n_machines ++;
225          e->machines = realloc(e->machines,  
226              sizeof(struct machine *) * e->n_machines);          CHECK_ALLOCATION(e->machines = realloc(e->machines,
227          if (e->machines == NULL) {              sizeof(struct machine *) * e->n_machines));
228                  fprintf(stderr, "emul_add_machine(): out of memory\n");  
229                  exit(1);          e->machines[i] = m;
230          }  
231            snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
232            settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
233                e->machines[i]->settings);
234    
         e->machines[e->n_machines - 1] = m;  
235          return m;          return m;
236  }  }
237    
# Line 709  static void add_arc_components(struct ma Line 257  static void add_arc_components(struct ma
257    
258          len += 1048576 * m->memory_offset_in_mb;          len += 1048576 * m->memory_offset_in_mb;
259    
260          /*  NOTE/TODO: magic 12MB end of load program area  */          /*
261             *  NOTE/TODO: magic 12MB end of load program area
262             *
263             *  Hm. This breaks the old FreeBSD/MIPS snapshots...
264             */
265    #if 0
266          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
267              0x60000 + m->memory_offset_in_mb * 1048576,              0x60000 + m->memory_offset_in_mb * 1048576,
268              start-0x60000 - m->memory_offset_in_mb * 1048576,              start-0x60000 - m->memory_offset_in_mb * 1048576,
269              ARCBIOS_MEM_FreeMemory);              ARCBIOS_MEM_FreeMemory);
270    #endif
271          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
272              start, len, ARCBIOS_MEM_LoadedProgram);              start, len, ARCBIOS_MEM_LoadedProgram);
273    
# Line 806  static void add_arc_components(struct ma Line 360  static void add_arc_components(struct ma
360  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,
361          int n_devices, char **device_names)          int n_devices, char **device_names)
362  {  {
         struct emul *emul;  
363          struct cpu *cpu;          struct cpu *cpu;
364          int i, iadd=4;          int i, iadd = DEBUG_INDENTATION;
365          uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;          uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
366          int byte_order;          int byte_order;
367    
         emul = m->emul;  
   
368          debug("machine \"%s\":\n", m->name);          debug("machine \"%s\":\n", m->name);
369          debug_indentation(iadd);          debug_indentation(iadd);
370    
# Line 834  void emul_machine_setup(struct machine * Line 385  void emul_machine_setup(struct machine *
385    
386          m->cpu_family = cpu_family_ptr_by_number(m->arch);          m->cpu_family = cpu_family_ptr_by_number(m->arch);
387    
388          if (m->arch != ARCH_MIPS)          if (m->arch == ARCH_ALPHA)
389                  m->bintrans_enable = 0;                  m->arch_pagesize = 8192;
390    
391          machine_memsize_fix(m);          machine_memsize_fix(m);
392    
# Line 857  void emul_machine_setup(struct machine * Line 408  void emul_machine_setup(struct machine *
408                  debug(" (offset by %iMB)", m->memory_offset_in_mb);                  debug(" (offset by %iMB)", m->memory_offset_in_mb);
409                  memory_amount += 1048576 * m->memory_offset_in_mb;                  memory_amount += 1048576 * m->memory_offset_in_mb;
410          }          }
411          m->memory = memory_new(memory_amount);          m->memory = memory_new(memory_amount, m->arch);
412          if (m->machine_type != MACHINE_USERLAND)          if (m->machine_type != MACHINE_USERLAND)
413                  debug("\n");                  debug("\n");
414    
# Line 868  void emul_machine_setup(struct machine * Line 419  void emul_machine_setup(struct machine *
419                  /*  TODO: This should be moved elsewhere...  */                  /*  TODO: This should be moved elsewhere...  */
420                  if (m->machine_type == MACHINE_BEBOX)                  if (m->machine_type == MACHINE_BEBOX)
421                          m->ncpus = 2;                          m->ncpus = 2;
                 else if (m->machine_type == MACHINE_ARC &&  
                     m->machine_subtype == MACHINE_ARC_NEC_R96)  
                         m->ncpus = 2;  
                 else if (m->machine_type == MACHINE_ARC &&  
                     m->machine_subtype == MACHINE_ARC_NEC_R98)  
                         m->ncpus = 4;  
422                  else                  else
423                          m->ncpus = 1;                          m->ncpus = 1;
424          }          }
         m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);  
         if (m->cpus == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
         memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);  
425    
426          /*  Initialize dynamic binary translation, if available:  */          CHECK_ALLOCATION(m->cpus = malloc(sizeof(struct cpu *) * m->ncpus));
427          if (m->bintrans_enable)          memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
                 bintrans_init(m, m->memory);  
428    
429          debug("cpu0");          debug("cpu0");
430          if (m->ncpus > 1)          if (m->ncpus > 1)
# Line 894  void emul_machine_setup(struct machine * Line 432  void emul_machine_setup(struct machine *
432          debug(": ");          debug(": ");
433          for (i=0; i<m->ncpus; i++) {          for (i=0; i<m->ncpus; i++) {
434                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
435                  if (m->bintrans_enable)                  if (m->cpus[i] == NULL) {
436                          bintrans_init_cpu(m->cpus[i]);                          fprintf(stderr, "Unable to create CPU object. "
437                                "Aborting.");
438                            exit(1);
439                    }
440          }          }
441          debug("\n");          debug("\n");
442    
 #if 0  
         /*  Special case: The Playstation Portable has an additional CPU:  */  
         if (m->machine_type == MACHINE_PSP) {  
                 debug("cpu%i: ", m->ncpus);  
                 m->cpus[m->ncpus] = cpu_new(m->memory, m,  
                     0  /*  use 0 here to show info with debug()  */,  
                     "Allegrex" /*  TODO  */);  
                 if (m->bintrans_enable)  
                         bintrans_init_cpu(m->cpus[m->ncpus]);  
                 debug("\n");  
                 m->ncpus ++;  
         }  
 #endif  
   
443          if (m->use_random_bootstrap_cpu)          if (m->use_random_bootstrap_cpu)
444                  m->bootstrap_cpu = random() % m->ncpus;                  m->bootstrap_cpu = random() % m->ncpus;
445          else          else
# Line 924  void emul_machine_setup(struct machine * Line 451  void emul_machine_setup(struct machine *
451          if (m->userland_emul != NULL) {          if (m->userland_emul != NULL) {
452                  useremul_name_to_useremul(cpu,                  useremul_name_to_useremul(cpu,
453                      m->userland_emul, NULL, NULL, NULL);                      m->userland_emul, NULL, NULL, NULL);
454                  cpu->memory_rw = userland_memory_rw;  
455                    switch (m->arch) {
456    
457                    case ARCH_ALPHA:
458                            cpu->memory_rw = alpha_userland_memory_rw;
459                            break;
460    
461                    default:
462                            cpu->memory_rw = userland_memory_rw;
463                    }
464          }          }
465    
466          if (m->use_x11)          if (m->x11_md.in_use)
467                  x11_init(m);                  x11_init(m);
468    
469          /*  Fill memory with random bytes:  */          /*  Fill memory with random bytes:  */
# Line 955  void emul_machine_setup(struct machine * Line 491  void emul_machine_setup(struct machine *
491          }          }
492    
493          diskimage_dump_info(m);          diskimage_dump_info(m);
494            console_debug_dump(m);
495    
496          /*  Load files (ROM code, boot code, ...) into memory:  */          /*  Load files (ROM code, boot code, ...) into memory:  */
497          if (n_load == 0) {          if (n_load == 0) {
# Line 995  void emul_machine_setup(struct machine * Line 532  void emul_machine_setup(struct machine *
532                          fread(buf, 1, sizeof(buf), tmp_f);                          fread(buf, 1, sizeof(buf), tmp_f);
533                          if (buf[0]==0x1f && buf[1]==0x8b) {                          if (buf[0]==0x1f && buf[1]==0x8b) {
534                                  size_t zzlen = strlen(name_to_load)*2 + 100;                                  size_t zzlen = strlen(name_to_load)*2 + 100;
535                                  char *zz = malloc(zzlen);                                  char *zz;
536    
537                                    CHECK_ALLOCATION(zz = malloc(zzlen));
538                                  debug("gunziping %s\n", name_to_load);                                  debug("gunziping %s\n", name_to_load);
539    
540                                  /*                                  /*
541                                   *  gzip header found.  If this was a file                                   *  gzip header found.  If this was a file
542                                   *  extracted from, say, a CDROM image, then it                                   *  extracted from, say, a CDROM image, then it
# Line 1013  void emul_machine_setup(struct machine * Line 553  void emul_machine_setup(struct machine *
553                                  } else {                                  } else {
554                                          /*  gunzip into new temp file:  */                                          /*  gunzip into new temp file:  */
555                                          int tmpfile_handle;                                          int tmpfile_handle;
556                                          char *new_temp_name =                                          char *new_temp_name;
557                                              strdup("/tmp/gxemul.XXXXXXXXXXXX");                                          CHECK_ALLOCATION(new_temp_name =
558                                                strdup("/tmp/gxemul.XXXXXXXXXXXX"));
559                                          tmpfile_handle = mkstemp(new_temp_name);                                          tmpfile_handle = mkstemp(new_temp_name);
560                                          close(tmpfile_handle);                                          close(tmpfile_handle);
561                                          snprintf(zz, zzlen, "gunzip -c '%s' > "                                          snprintf(zz, zzlen, "gunzip -c '%s' > "
# Line 1028  void emul_machine_setup(struct machine * Line 569  void emul_machine_setup(struct machine *
569                          fclose(tmp_f);                          fclose(tmp_f);
570                  }                  }
571    
                 /*  
                  *  Ugly (but usable) hack for Playstation Portable:  If the  
                  *  filename ends with ".pbp" and the file contains an ELF  
                  *  header, then extract the ELF file into a temporary file.  
                  */  
                 if (strlen(name_to_load) > 4 && strcasecmp(name_to_load +  
                     strlen(name_to_load) - 4, ".pbp") == 0 &&  
                     (tmp_f = fopen(name_to_load, "r")) != NULL) {  
                         off_t filesize, j, found=0;  
                         unsigned char *buf;  
                         fseek(tmp_f, 0, SEEK_END);  
                         filesize = ftello(tmp_f);  
                         fseek(tmp_f, 0, SEEK_SET);  
                         buf = malloc(filesize);  
                         if (buf == NULL) {  
                                 fprintf(stderr, "out of memory while trying"  
                                     " to read %s\n", name_to_load);  
                                 exit(1);  
                         }  
                         fread(buf, 1, filesize, tmp_f);  
                         fclose(tmp_f);  
                         /*  Search for the ELF header, from offset 1 (!):  */  
                         for (j=1; j<filesize - 4; j++)  
                                 if (memcmp(buf + j, ELFMAG, SELFMAG) == 0) {  
                                         found = j;  
                                         break;  
                                 }  
                         if (found != 0) {  
                                 int tmpfile_handle;  
                                 char *new_temp_name =  
                                     strdup("/tmp/gxemul.XXXXXXXXXXXX");  
                                 debug("extracting ELF from %s (offset 0x%x)\n",  
                                     name_to_load, (int)found);  
                                 tmpfile_handle = mkstemp(new_temp_name);  
                                 write(tmpfile_handle, buf + found,  
                                     filesize - found);  
                                 close(tmpfile_handle);  
                                 name_to_load = new_temp_name;  
                                 remove_after_load = 1;  
                         }  
                 }  
   
                 /*  Special things required _before_ loading the file:  */  
                 switch (m->arch) {  
                 case ARCH_X86:  
                         /*  
                          *  X86 machines normally don't need to load any files,  
                          *  they can boot from disk directly. Therefore, an x86  
                          *  machine usually boots up in 16-bit real mode. When  
                          *  loading a 32-bit (or even 64-bit) ELF, that's not  
                          *  very nice, hence this special case.  
                          */  
                         pc_bios_simple_pmode_setup(cpu);  
                         break;  
                 }  
   
572                  byte_order = NO_BYTE_ORDER_OVERRIDE;                  byte_order = NO_BYTE_ORDER_OVERRIDE;
573    
574                  /*                  /*
# Line 1103  void emul_machine_setup(struct machine * Line 588  void emul_machine_setup(struct machine *
588                  cpu->pc = entrypoint;                  cpu->pc = entrypoint;
589    
590                  switch (m->arch) {                  switch (m->arch) {
591    
592                    case ARCH_ALPHA:
593                            /*  For position-independent code:  */
594                            cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
595                            break;
596    
597                    case ARCH_ARM:
598                            if (cpu->pc & 3) {
599                                    fatal("ARM: lowest bits of pc set: TODO\n");
600                                    exit(1);
601                            }
602                            cpu->pc &= 0xfffffffc;
603                            break;
604    
605                    case ARCH_M88K:
606                            if (cpu->pc & 3) {
607                                    fatal("M88K: lowest bits of pc set: TODO\n");
608                                    exit(1);
609                            }
610                            cpu->pc &= 0xfffffffc;
611                            break;
612    
613                  case ARCH_MIPS:                  case ARCH_MIPS:
614                          if ((cpu->pc >> 32) == 0                          if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
                             && (cpu->pc & 0x80000000ULL))  
615                                  cpu->pc |= 0xffffffff00000000ULL;                                  cpu->pc |= 0xffffffff00000000ULL;
616    
617                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
# Line 1121  void emul_machine_setup(struct machine * Line 627  void emul_machine_setup(struct machine *
627                              spec/x458.html for more info.  */                              spec/x458.html for more info.  */
628                          cpu->cd.ppc.gpr[2] = toc;                          cpu->cd.ppc.gpr[2] = toc;
629                          /*  TODO  */                          /*  TODO  */
630                            if (cpu->cd.ppc.bits == 32)
631                                    cpu->pc &= 0xffffffffULL;
632                          break;                          break;
633    
634                  case ARCH_ALPHA:                  case ARCH_SH:
635                  case ARCH_HPPA:                          if (cpu->cd.sh.cpu_type.bits == 32)
636                  case ARCH_SPARC:                                  cpu->pc &= 0xffffffffULL;
637                  case ARCH_URISC:                          cpu->pc &= ~1;
                         break;  
   
                 case ARCH_ARM:  
                         cpu->pc &= 0xfffffffc;  
                         cpu->cd.arm.r[ARM_PC] = cpu->pc;  
638                          break;                          break;
639    
640                  case ARCH_X86:                  case ARCH_SPARC:
                         /*  
                          *  NOTE: The toc field is used to indicate an ELF32  
                          *  or ELF64 load.  
                          */  
                         switch (toc) {  
                         case 0: /*  16-bit? TODO  */  
                                 cpu->pc &= 0xffffffffULL;  
                                 break;  
                         case 1: /*  32-bit.  */  
                                 cpu->pc &= 0xffffffffULL;  
                                 break;  
                         case 2: /*  64-bit:  TODO  */  
                                 fatal("64-bit x86 load. TODO\n");  
                                 exit(1);  
                         }  
641                          break;                          break;
642    
643                  default:                  default:
# Line 1187  void emul_machine_setup(struct machine * Line 675  void emul_machine_setup(struct machine *
675                  useremul_setup(cpu, n_load, load_names);                  useremul_setup(cpu, n_load, load_names);
676    
677          /*  Startup the bootstrap CPU:  */          /*  Startup the bootstrap CPU:  */
678          cpu->bootstrap_cpu_flag = 1;          cpu->running = 1;
         cpu->running            = 1;  
679    
680          /*  ... or pause all CPUs, if start_paused is set:  */          /*  ... or pause all CPUs, if start_paused is set:  */
681          if (m->start_paused) {          if (m->start_paused) {
# Line 1196  void emul_machine_setup(struct machine * Line 683  void emul_machine_setup(struct machine *
683                          m->cpus[i]->running = 0;                          m->cpus[i]->running = 0;
684          }          }
685    
686          /*  Add PC dump points:  */          /*  Parse and add breakpoints:  */
687          add_dump_points(m);          add_breakpoints(m);
688    
689          /*  TODO: This is MIPS-specific!  */          /*  TODO: This is MIPS-specific!  */
690          if (m->machine_type == MACHINE_DEC &&          if (m->machine_type == MACHINE_PMAX &&
691              cpu->cd.mips.cpu_type.mmu_model == MMU3K)              cpu->cd.mips.cpu_type.mmu_model == MMU3K)
692                  add_symbol_name(&m->symbol_context,                  add_symbol_name(&m->symbol_context,
693                      0x9fff0000, 0x10000, "r2k3k_cache", 0);                      0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
694    
695          symbol_recalc_sizes(&m->symbol_context);          symbol_recalc_sizes(&m->symbol_context);
696    
         if (m->max_random_cycles_per_chunk > 0)  
                 debug("using random cycle chunks (1 to %i cycles)\n",  
                     m->max_random_cycles_per_chunk);  
   
697          /*  Special hack for ARC/SGI emulation:  */          /*  Special hack for ARC/SGI emulation:  */
698          if ((m->machine_type == MACHINE_ARC ||          if ((m->machine_type == MACHINE_ARC ||
699              m->machine_type == MACHINE_SGI) && m->prom_emulation)              m->machine_type == MACHINE_SGI) && m->prom_emulation)
# Line 1218  void emul_machine_setup(struct machine * Line 701  void emul_machine_setup(struct machine *
701    
702          debug("starting cpu%i at ", m->bootstrap_cpu);          debug("starting cpu%i at ", m->bootstrap_cpu);
703          switch (m->arch) {          switch (m->arch) {
704    
705            case ARCH_ARM:
706                    /*  ARM cpus aren't 64-bit:  */
707                    debug("0x%08"PRIx32, (uint32_t) entrypoint);
708                    break;
709    
710          case ARCH_MIPS:          case ARCH_MIPS:
711                  if (cpu->cd.mips.cpu_type.isa_level < 3 ||                  if (cpu->is_32bit) {
712                      cpu->cd.mips.cpu_type.isa_level == 32) {                          debug("0x%08"PRIx32, (uint32_t)
713                          debug("0x%08x", (int)m->cpus[                              m->cpus[m->bootstrap_cpu]->pc);
                             m->bootstrap_cpu]->pc);  
714                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
715                                  debug(" (gp=0x%08x)", (int)m->cpus[                                  debug(" (gp=0x%08"PRIx32")", (uint32_t)
716                                      m->bootstrap_cpu]->cd.mips.gpr[                                      m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
717                                      MIPS_GPR_GP]);                                      MIPS_GPR_GP]);
718                  } else {                  } else {
719                          debug("0x%016llx", (long long)m->cpus[                          debug("0x%016"PRIx64, (uint64_t)
720                              m->bootstrap_cpu]->pc);                              m->cpus[m->bootstrap_cpu]->pc);
721                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
722                                  debug(" (gp=0x%016llx)", (long long)                                  debug(" (gp=0x%016"PRIx64")", (uint64_t)
723                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);
724                  }                  }
725                  break;                  break;
726    
727          case ARCH_PPC:          case ARCH_PPC:
728                  if (cpu->cd.ppc.bits == 32)                  if (cpu->cd.ppc.bits == 32)
729                          debug("0x%08x", (int)entrypoint);                          debug("0x%08"PRIx32, (uint32_t) entrypoint);
730                  else                  else
731                          debug("0x%016llx", (long long)entrypoint);                          debug("0x%016"PRIx64, (uint64_t) entrypoint);
732                  break;                  break;
         case ARCH_ARM:  
                 /*  ARM cpus aren't 64-bit:  */  
                 debug("0x%08x", (int)entrypoint);  
                 break;  
         case ARCH_URISC:  
                 {  
                         char tmps[100];  
                         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];  
                         }  
733    
                         snprintf(tmps, sizeof(tmps), "0x%%0%illx",  
                             cpu->cd.urisc.wordlen / 4);  
                         debug(tmps, (long long)entrypoint);  
                         cpu->pc = entrypoint;  
                 }  
                 break;  
         case ARCH_X86:  
                 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],  
                     (long long)cpu->pc);  
                 break;  
734          default:          default:
735                  debug("0x%016llx", (long long)cpu->pc);                  if (cpu->is_32bit)
736                            debug("0x%08"PRIx32, (uint32_t) cpu->pc);
737                    else
738                            debug("0x%016"PRIx64, (uint64_t) cpu->pc);
739          }          }
740          debug("\n");          debug("\n");
741    
# Line 1289  void emul_machine_setup(struct machine * Line 750  void emul_machine_setup(struct machine *
750   */   */
751  void emul_dumpinfo(struct emul *e)  void emul_dumpinfo(struct emul *e)
752  {  {
753          int j, nm, iadd = 4;          int j, nm, iadd = DEBUG_INDENTATION;
754    
755          if (e->net != NULL)          if (e->net != NULL)
756                  net_dumpinfo(e->net);                  net_dumpinfo(e->net);
# Line 1318  void emul_dumpinfo(struct emul *e) Line 779  void emul_dumpinfo(struct emul *e)
779   */   */
780  void emul_simple_init(struct emul *emul)  void emul_simple_init(struct emul *emul)
781  {  {
782          int iadd=4;          int iadd = DEBUG_INDENTATION;
783          struct machine *m;          struct machine *m;
784    
785          if (emul->n_machines != 1) {          if (emul->n_machines != 1) {
# Line 1334  void emul_simple_init(struct emul *emul) Line 795  void emul_simple_init(struct emul *emul)
795    
796                  /*  Create a simple network:  */                  /*  Create a simple network:  */
797                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
798                      "10.0.0.0", 8, NULL, 0, 0);                      NET_DEFAULT_IPV4_MASK,
799                        NET_DEFAULT_IPV4_LEN,
800                        NULL, 0, 0, NULL);
801          } else {          } else {
802                  /*  Userland pseudo-machine:  */                  /*  Userland pseudo-machine:  */
803                  debug("Syscall emulation (userland-only) setup...\n");                  debug("Syscall emulation (userland-only) setup...\n");
# Line 1353  void emul_simple_init(struct emul *emul) Line 816  void emul_simple_init(struct emul *emul)
816   *   *
817   *  Create an emul struct by reading settings from a configuration file.   *  Create an emul struct by reading settings from a configuration file.
818   */   */
819  struct emul *emul_create_from_configfile(char *fname)  struct emul *emul_create_from_configfile(char *fname, int id)
820  {  {
821          int iadd = 4;          int iadd = DEBUG_INDENTATION;
822          struct emul *e = emul_new(fname);          struct emul *e = emul_new(fname, id);
         FILE *f;  
         char buf[128];  
         size_t len;  
823    
824          debug("Creating emulation from configfile \"%s\":\n", fname);          debug("Creating emulation from configfile \"%s\":\n", fname);
825          debug_indentation(iadd);          debug_indentation(iadd);
826    
827          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);  
828    
         emul_parse_config(e, f);  
   
         fclose(f);  
829          debug_indentation(-iadd);          debug_indentation(-iadd);
830          return e;          return e;
831  }  }
# Line 1409  void emul_run(struct emul **emuls, int n Line 852  void emul_run(struct emul **emuls, int n
852    
853          atexit(fix_console);          atexit(fix_console);
854    
         i = 79;  
         while (i-- > 0)  
                 debug("-");  
         debug("\n\n");  
   
855          /*  Initialize the interactive debugger:  */          /*  Initialize the interactive debugger:  */
856          debugger_init(emuls, n_emuls);          debugger_init(emuls, n_emuls);
857    
858            /*  Run any additional debugger commands before starting:  */
859            for (i=0; i<n_emuls; i++) {
860                    struct emul *emul = emuls[i];
861                    if (emul->n_debugger_cmds > 0) {
862                            int j;
863                            if (i == 0)
864                                    print_separator_line();
865                            for (j = 0; j < emul->n_debugger_cmds; j ++) {
866                                    debug("> %s\n", emul->debugger_cmds[j]);
867                                    debugger_execute_cmd(emul->debugger_cmds[j],
868                                        strlen(emul->debugger_cmds[j]));
869                            }
870                    }
871            }
872    
873            print_separator_line();
874            debug("\n");
875    
876    
877          /*          /*
878           *  console_init_main() makes sure that the terminal is in a           *  console_init_main() makes sure that the terminal is in a
879           *  reasonable state.           *  reasonable state.
# Line 1441  void emul_run(struct emul **emuls, int n Line 898  void emul_run(struct emul **emuls, int n
898                  if (e == NULL)                  if (e == NULL)
899                          continue;                          continue;
900                  for (j=0; j<e->n_machines; j++)                  for (j=0; j<e->n_machines; j++)
901                          cpu_run_init(e, e->machines[j]);                          cpu_run_init(e->machines[j]);
902          }          }
903    
904            /*  TODO: Generalize:  */
905            if (emuls[0]->machines[0]->show_trace_tree)
906                    cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
907                        emuls[0]->machines[0]->cpus[0]->pc);
908    
909            /*  Start emulated clocks:  */
910            timer_start();
911    
912          /*          /*
913           *  MAIN LOOP:           *  MAIN LOOP:
914           *           *
915           *  Run all emulations in parallel, running each machine in           *  Run all emulations in parallel, running instructions from each
916           *  each emulation.           *  cpu in each machine in each emulation.
917           */           */
918          while (go) {          while (go) {
919                    struct cpu *bootcpu = emuls[0]->machines[0]->cpus[
920                        emuls[0]->machines[0]->bootstrap_cpu];
921    
922                  go = 0;                  go = 0;
923    
924                  x11_check_event(emuls, n_emuls);                  /*  Flush X11 and serial console output every now and then:  */
925                    if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) {
926                            x11_check_event(emuls, n_emuls);
927                            console_flush();
928                            bootcpu->ninstrs_flush = bootcpu->ninstrs;
929                    }
930    
931                    if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) {
932                            bootcpu->ninstrs_since_gettimeofday +=
933                                (bootcpu->ninstrs - bootcpu->ninstrs_show);
934                            cpu_show_cycles(emuls[0]->machines[0], 0);
935                            bootcpu->ninstrs_show = bootcpu->ninstrs;
936                    }
937    
938                    if (single_step == ENTER_SINGLE_STEPPING) {
939                            /*  TODO: Cleanup!  */
940                            old_instruction_trace =
941                                emuls[0]->machines[0]->instruction_trace;
942                            old_quiet_mode = quiet_mode;
943                            old_show_trace_tree =
944                                emuls[0]->machines[0]->show_trace_tree;
945                            emuls[0]->machines[0]->instruction_trace = 1;
946                            emuls[0]->machines[0]->show_trace_tree = 1;
947                            quiet_mode = 0;
948                            single_step = SINGLE_STEPPING;
949                    }
950    
951                    if (single_step == SINGLE_STEPPING)
952                            debugger();
953    
954                  for (i=0; i<n_emuls; i++) {                  for (i=0; i<n_emuls; i++) {
955                          e = emuls[i];                          e = emuls[i];
                         if (e == NULL)  
                                 continue;  
956    
957                          for (j=0; j<e->n_machines; j++) {                          for (j=0; j<e->n_machines; j++) {
958                                  /*  TODO: cpu_run() is a strange name, since                                  anything = machine_run(e->machines[j]);
                                     there can be multiple cpus in a machine  */  
                                 anything = cpu_run(e, e->machines[j]);  
959                                  if (anything)                                  if (anything)
960                                          go = 1;                                          go = 1;
961                          }                          }
962                  }                  }
963          }          }
964    
965            /*  Stop any running timers:  */
966            timer_stop();
967    
968          /*  Deinitialize all CPUs in all machines in all emulations:  */          /*  Deinitialize all CPUs in all machines in all emulations:  */
969          for (i=0; i<n_emuls; i++) {          for (i=0; i<n_emuls; i++) {
970                  e = emuls[i];                  e = emuls[i];
971                  if (e == NULL)                  if (e == NULL)
972                          continue;                          continue;
973                  for (j=0; j<e->n_machines; j++)                  for (j=0; j<e->n_machines; j++)
974                          cpu_run_deinit(e, e->machines[j]);                          cpu_run_deinit(e->machines[j]);
975          }          }
976    
977          /*  force_debugger_at_exit flag set? Then enter the debugger:  */          /*  force_debugger_at_exit flag set? Then enter the debugger:  */
# Line 1486  void emul_run(struct emul **emuls, int n Line 981  void emul_run(struct emul **emuls, int n
981                  debugger();                  debugger();
982          }          }
983    
984          /*  Any machine using X11? Then we should wait before exiting:  */          /*  Any machine using X11? Then wait before exiting:  */
985          n = 0;          n = 0;
986          for (i=0; i<n_emuls; i++)          for (i=0; i<n_emuls; i++)
987                  for (j=0; j<emuls[i]->n_machines; j++)                  for (j=0; j<emuls[i]->n_machines; j++)
988                          if (emuls[i]->machines[j]->use_x11)                          if (emuls[i]->machines[j]->x11_md.in_use)
989                                  n++;                                  n++;
990          if (n > 0) {          if (n > 0) {
991                  printf("Press enter to quit.\n");                  printf("Press enter to quit.\n");
992                  while (!console_charavail(MAIN_CONSOLE)) {                  while (!console_charavail(MAIN_CONSOLE)) {
993                          x11_check_event(emuls, n_emuls);                          x11_check_event(emuls, n_emuls);
994                          usleep(1);                          usleep(10000);
995                  }                  }
996                  console_readchar(MAIN_CONSOLE);                  console_readchar(MAIN_CONSOLE);
997          }          }
998    
999          console_deinit();          console_deinit_main();
1000  }  }
1001    

Legend:
Removed from v.10  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26