/[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 24 by dpavlin, Mon Oct 8 16:19:56 2007 UTC revision 40 by dpavlin, Mon Oct 8 16:22:11 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2006  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.254 2006/06/22 13:22:40 debug Exp $   *  $Id: emul.c,v 1.284 2007/04/19 15:18:15 debug Exp $
29   *   *
30   *  Emulation startup and misc. routines.   *  Emulation startup and misc. routines.
31   */   */
# Line 51  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 "settings.h"
55  #include "sgi_arcbios.h"  #include "sgi_arcbios.h"
56    #include "timer.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 int single_step;
67    extern int old_show_trace_tree;
68    extern int old_instruction_trace;
69    extern int old_quiet_mode;
70    extern int quiet_mode;
71    
72  extern struct emul *debugger_emul;  extern struct emul *debugger_emul;
73  extern struct diskimage *diskimages[];  extern struct diskimage *diskimages[];
74    
 static char *diskimage_types[] = DISKIMAGE_TYPES;  
   
75    
76  static void print_separator(void)  static void print_separator(void)
77  {  {
# Line 140  static void add_dump_points(struct machi Line 144  static void add_dump_points(struct machi
144   */   */
145  static void fix_console(void)  static void fix_console(void)
146  {  {
147          console_deinit();          console_deinit_main();
148  }  }
149    
150    
151  /*  /*
152   *  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.  
153   *   *
154   *  Returns 1 on success, 0 on failure.   *  Returns a reasonably initialized struct emul.
155   */   */
156  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)  
157  {  {
158          char str[35];          struct emul *e;
159          int filenr, i, ofs, dirlen, res = 0, res2, iadd = DEBUG_INDENTATION;          e = malloc(sizeof(struct emul));
160          int found_dir;          if (e == NULL) {
161          uint64_t dirofs;                  fprintf(stderr, "out of memory in emul_new()\n");
         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 *tmpfname = 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) +  
             ((uint64_t)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) {  
                 size_t i, nlen = dp[0];  
                 int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) +  
                     ((uint64_t)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 (;;) {  
                 size_t 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;  
         }  
   
         fileofs = match_entry[2] + (match_entry[3] << 8) +  
             (match_entry[4] << 16) + ((uint64_t)match_entry[5] << 24);  
         filelen = match_entry[10] + (match_entry[11] << 8) +  
             (match_entry[12] << 16) + ((uint64_t)match_entry[13] << 24);  
         fileofs *= 2048;  
   
         /*  debug("filelen=%llx fileofs=%llx\n", (long long)filelen,  
             (long long)fileofs);  */  
   
         filebuf = malloc(filelen);  
         if (filebuf == NULL) {  
                 fatal("could not allocate %lli bytes to read the file"  
                     " from the disk image!\n", (long long)filelen);  
                 goto ret;  
         }  
   
         tmpfname = strdup("/tmp/gxemul.XXXXXXXXXXXX");  
   
         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;  
         }  
   
         tmpfile_handle = mkstemp(tmpfname);  
         if (tmpfile_handle < 0) {  
                 fatal("could not create %s\n", tmpfname);  
162                  exit(1);                  exit(1);
163          }          }
         write(tmpfile_handle, filebuf, filelen);  
         close(tmpfile_handle);  
164    
165          debug("extracted %lli bytes into %s\n", (long long)filelen, tmpfname);          memset(e, 0, sizeof(struct emul));
166    
167          /*  Add the temporary filename to the load_namesp array:  */          e->path = malloc(15);
168          (*n_loadp)++;          if (e->path == NULL) {
169          new_array = malloc(sizeof(char *) * (*n_loadp));                  fprintf(stderr, "out of memory\n");
         if (new_array == NULL) {  
                 fatal("out of memory\n");  
170                  exit(1);                  exit(1);
171          }          }
172          memcpy(new_array, *load_namesp, sizeof(char *) * (*n_loadp));          snprintf(e->path, 15, "emul[%i]", id);
         *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.  */  
         tmpfname = realloc(tmpfname, strlen(tmpfname) + 2);  
         memmove(tmpfname + 1, tmpfname, strlen(tmpfname) + 1);  
         tmpfname[0] = 8;  
   
         (*load_namesp)[*n_loadp - 1] = tmpfname;  
   
         res = 1;  
   
 ret:  
         if (dirbuf != NULL)  
                 free(dirbuf);  
   
         if (filebuf != NULL)  
                 free(filebuf);  
   
         if (match_entry != NULL)  
                 free(match_entry);  
   
         free(filename_orig);  
   
         debug_indentation(-iadd);  
         return res;  
 }  
   
   
 /*  
  *  apple_load_bootblock():  
  *  
  *  Try to load a kernel from a disk image with an Apple Partition Table.  
  *  
  *  TODO: This function uses too many magic offsets and so on; it should be  
  *  cleaned up some day. See http://www.awprofessional.com/articles/  
  *      article.asp?p=376123&seqNum=3&rl=1  for some info on the Apple  
  *  partition format.  
  *  
  *  Returns 1 on success, 0 on failure.  
  */  
 static int apple_load_bootblock(struct machine *m, struct cpu *cpu,  
         int disk_id, int disk_type, int *n_loadp, char ***load_namesp)  
 {  
         unsigned char buf[0x8000];  
         int res, partnr, n_partitions = 0, n_hfs_partitions = 0;  
         uint64_t hfs_start, hfs_length;  
   
         res = diskimage_access(m, disk_id, disk_type, 0, 0x0, buf, sizeof(buf));  
         if (!res) {  
                 fatal("apple_load_bootblock: couldn't read the disk "  
                     "image. Aborting.\n");  
                 return 0;  
         }  
   
         partnr = 0;  
         do {  
                 int start, length;  
                 int ofs = 0x200 * (partnr + 1);  
                 if (partnr == 0)  
                         n_partitions = buf[ofs + 7];  
                 start = ((uint64_t)buf[ofs + 8] << 24) + (buf[ofs + 9] << 16) +  
                     (buf[ofs + 10] << 8) + buf[ofs + 11];  
                 length = ((uint64_t)buf[ofs+12] << 24) + (buf[ofs + 13] << 16) +  
                     (buf[ofs + 14] << 8) + buf[ofs + 15];  
   
                 debug("partition %i: '%s', type '%s', start %i, length %i\n",  
                     partnr, buf + ofs + 0x10, buf + ofs + 0x30,  
                     start, length);  
   
                 if (strcmp((char *)buf + ofs + 0x30, "Apple_HFS") == 0) {  
                         n_hfs_partitions ++;  
                         hfs_start = 512 * start;  
                         hfs_length = 512 * length;  
                 }  
   
                 /*  Any more partitions?  */  
                 partnr ++;  
         } while (partnr < n_partitions);  
   
         if (n_hfs_partitions == 0) {  
                 fatal("Error: No HFS partition found! TODO\n");  
                 return 0;  
         }  
         if (n_hfs_partitions >= 2) {  
                 fatal("Error: Too many HFS partitions found! TODO\n");  
                 return 0;  
         }  
173    
174          return 0;          e->settings = settings_new();
 }  
175    
176            settings_add(e->settings, "n_machines", 0,
177                SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
178                (void *) &e->n_machines);
179    
180  /*          /*  TODO: More settings?  */
  *  load_bootblock():  
  *  
  *  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.  
  *  
  *  Returns 1 on success, 0 on failure.  
  */  
 static int load_bootblock(struct machine *m, struct cpu *cpu,  
         int *n_loadp, char ***load_namesp)  
 {  
         int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,  
             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_PMAX:  
                 /*  
                  *  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));  
181    
182                  bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)          /*  Sane default values:  */
183                    + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24);          e->n_machines = 0;
184            e->next_serial_nr = 1;
                 /*  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) + ((uint64_t)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) + ((uint64_t)minibuf[3] << 24);  
   
                         bootblock_offset = (minibuf[4] + (minibuf[5] << 8) +  
                           (minibuf[6]<<16) + ((uint64_t)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;  
185    
186                  bootblock_buf = malloc(512);          if (name != NULL) {
187                  if (bootblock_buf == NULL) {                  e->name = strdup(name);
188                          fprintf(stderr, "Out of memory.\n");                  if (e->name == NULL) {
189                            fprintf(stderr, "out of memory in emul_new()\n");
190                          exit(1);                          exit(1);
191                  }                  }
192    
193                  debug("loading PC bootsector from %s id %i\n",                  settings_add(e->settings, "name", 0,
194                      diskimage_types[boot_disk_type], boot_disk_id);                      SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
195                        (void *) &e->name);
                 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-dependent boot blocks etc.  
          */  
         /*  ISO9660: (0x800 bytes at 0x8000)  */  
         bootblock_buf = malloc(0x800);  
         if (bootblock_buf == NULL) {  
                 fprintf(stderr, "Out of memory.\n");  
                 exit(1);  
196          }          }
197    
198          res = diskimage_access(m, boot_disk_id, boot_disk_type,          return e;
             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);  
         }  
   
         if (retval != 0)  
                 goto ret_ok;  
   
         /*  Apple parition table:  */  
         res = diskimage_access(m, boot_disk_id, boot_disk_type,  
             0, 0x0, bootblock_buf, 0x800);  
         if (!res) {  
                 fatal("Couldn't read the disk image. Aborting.\n");  
                 return 0;  
         }  
         if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' &&  
             bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') {  
                 /*  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("\nApple partition table, but no kernel "  
                             "specified? (Use the -j option.)\n");  
                 else  
                         retval = apple_load_bootblock(m, cpu, boot_disk_id,  
                             boot_disk_type, n_loadp, load_namesp);  
         }  
   
 ret_ok:  
         free(bootblock_buf);  
         return retval;  
199  }  }
200    
201    
202  /*  /*
203   *  emul_new():   *  emul_destroy():
204   *   *
205   *  Returns a reasonably initialized struct emul.   *  Destroys a previously created emul object.
206   */   */
207  struct emul *emul_new(char *name)  void emul_destroy(struct emul *emul)
208  {  {
209          struct emul *e;          int i;
210          e = malloc(sizeof(struct emul));  
211          if (e == NULL) {          if (emul->name != NULL) {
212                  fprintf(stderr, "out of memory in emul_new()\n");                  settings_remove(emul->settings, "name");
213                  exit(1);                  free(emul->name);
214          }          }
215    
216          memset(e, 0, sizeof(struct emul));          for (i=0; i<emul->n_machines; i++)
217                    machine_destroy(emul->machines[i]);
218    
219          /*  Sane default values:  */          if (emul->machines != NULL)
220          e->n_machines = 0;                  free(emul->machines);
         e->next_serial_nr = 1;  
221    
222          if (name != NULL) {          /*  Remove any remaining level-1 settings:  */
223                  e->name = strdup(name);          settings_remove_all(emul->settings);
224                  if (e->name == NULL) {          settings_destroy(emul->settings);
                         fprintf(stderr, "out of memory in emul_new()\n");  
                         exit(1);  
                 }  
         }  
225    
226          return e;          free(emul);
227  }  }
228    
229    
# Line 770  struct emul *emul_new(char *name) Line 238  struct emul *emul_new(char *name)
238  struct machine *emul_add_machine(struct emul *e, char *name)  struct machine *emul_add_machine(struct emul *e, char *name)
239  {  {
240          struct machine *m;          struct machine *m;
241            char tmpstr[20];
242            int i;
243    
244          m = machine_new(name, e);          m = machine_new(name, e, e->n_machines);
245          m->serial_nr = (e->next_serial_nr ++);          m->serial_nr = (e->next_serial_nr ++);
246    
247            i = e->n_machines;
248    
249          e->n_machines ++;          e->n_machines ++;
250          e->machines = realloc(e->machines,          e->machines = realloc(e->machines,
251              sizeof(struct machine *) * e->n_machines);              sizeof(struct machine *) * e->n_machines);
# Line 782  struct machine *emul_add_machine(struct Line 254  struct machine *emul_add_machine(struct
254                  exit(1);                  exit(1);
255          }          }
256    
257          e->machines[e->n_machines - 1] = m;          e->machines[i] = m;
258    
259            snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
260            settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
261                e->machines[i]->settings);
262    
263          return m;          return m;
264  }  }
265    
# Line 1178  void emul_machine_setup(struct machine * Line 655  void emul_machine_setup(struct machine *
655                          }                          }
656                  }                  }
657    
                 /*  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;  
                 }  
   
658                  byte_order = NO_BYTE_ORDER_OVERRIDE;                  byte_order = NO_BYTE_ORDER_OVERRIDE;
659    
660                  /*                  /*
# Line 1233  void emul_machine_setup(struct machine * Line 696  void emul_machine_setup(struct machine *
696                          }                          }
697                          break;                          break;
698    
699                  case ARCH_HPPA:                  case ARCH_M88K:
                         break;  
   
                 case ARCH_I960:  
                         break;  
   
                 case ARCH_IA64:  
                         break;  
   
                 case ARCH_M68K:  
700                          break;                          break;
701    
702                  case ARCH_MIPS:                  case ARCH_MIPS:
# Line 1267  void emul_machine_setup(struct machine * Line 721  void emul_machine_setup(struct machine *
721                          break;                          break;
722    
723                  case ARCH_SH:                  case ARCH_SH:
724                          if (cpu->cd.sh.bits == 32)                          if (cpu->cd.sh.cpu_type.bits == 32)
725                                  cpu->pc &= 0xffffffffULL;                                  cpu->pc &= 0xffffffffULL;
726                          cpu->pc &= ~1;                          cpu->pc &= ~1;
727                          break;                          break;
# Line 1275  void emul_machine_setup(struct machine * Line 729  void emul_machine_setup(struct machine *
729                  case ARCH_SPARC:                  case ARCH_SPARC:
730                          break;                          break;
731    
                 case ARCH_X86:  
                         /*  
                          *  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);  
                         }  
                         break;  
   
732                  default:                  default:
733                          fatal("emul_machine_setup(): Internal error: "                          fatal("emul_machine_setup(): Internal error: "
734                              "Unimplemented arch %i\n", m->arch);                              "Unimplemented arch %i\n", m->arch);
# Line 1328  void emul_machine_setup(struct machine * Line 764  void emul_machine_setup(struct machine *
764                  useremul_setup(cpu, n_load, load_names);                  useremul_setup(cpu, n_load, load_names);
765    
766          /*  Startup the bootstrap CPU:  */          /*  Startup the bootstrap CPU:  */
767          cpu->bootstrap_cpu_flag = 1;          cpu->running = 1;
         cpu->running            = 1;  
768    
769          /*  ... or pause all CPUs, if start_paused is set:  */          /*  ... or pause all CPUs, if start_paused is set:  */
770          if (m->start_paused) {          if (m->start_paused) {
# Line 1358  void emul_machine_setup(struct machine * Line 793  void emul_machine_setup(struct machine *
793    
794          case ARCH_ARM:          case ARCH_ARM:
795                  /*  ARM cpus aren't 64-bit:  */                  /*  ARM cpus aren't 64-bit:  */
796                  debug("0x%08x", (int)entrypoint);                  debug("0x%08"PRIx32, (uint32_t) entrypoint);
797                  break;                  break;
798    
799          case ARCH_AVR:          case ARCH_AVR:
800                  /*  Atmel AVR uses a 16-bit or 22-bit program counter:  */                  /*  Atmel AVR uses a 16-bit or 22-bit program counter:  */
801                  debug("0x%04x", (int)entrypoint);                  debug("0x%04x", (int) entrypoint);
802                  break;                  break;
803    
804          case ARCH_MIPS:          case ARCH_MIPS:
805                  if (cpu->is_32bit) {                  if (cpu->is_32bit) {
806                          debug("0x%08x", (int)m->cpus[                          debug("0x%08"PRIx32, (uint32_t)
807                              m->bootstrap_cpu]->pc);                              m->cpus[m->bootstrap_cpu]->pc);
808                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
809                                  debug(" (gp=0x%08x)", (int)m->cpus[                                  debug(" (gp=0x%08"PRIx32")", (uint32_t)
810                                      m->bootstrap_cpu]->cd.mips.gpr[                                      m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
811                                      MIPS_GPR_GP]);                                      MIPS_GPR_GP]);
812                  } else {                  } else {
813                          debug("0x%016llx", (long long)m->cpus[                          debug("0x%016"PRIx64, (uint64_t)
814                              m->bootstrap_cpu]->pc);                              m->cpus[m->bootstrap_cpu]->pc);
815                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
816                                  debug(" (gp=0x%016llx)", (long long)                                  debug(" (gp=0x%016"PRIx64")", (uint64_t)
817                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);
818                  }                  }
819                  break;                  break;
820    
821          case ARCH_PPC:          case ARCH_PPC:
822                  if (cpu->cd.ppc.bits == 32)                  if (cpu->cd.ppc.bits == 32)
823                          debug("0x%08x", (int)entrypoint);                          debug("0x%08"PRIx32, (uint32_t) entrypoint);
824                  else                  else
825                          debug("0x%016llx", (long long)entrypoint);                          debug("0x%016"PRIx64, (uint64_t) entrypoint);
                 break;  
   
         case ARCH_X86:  
                 debug("0x%04x:0x%llx", cpu->cd.x86.s[X86_S_CS],  
                     (long long)cpu->pc);  
826                  break;                  break;
827    
828          default:          default:
829                  if (cpu->is_32bit)                  if (cpu->is_32bit)
830                          debug("0x%08x", (int)cpu->pc);                          debug("0x%08"PRIx32, (uint32_t) cpu->pc);
831                  else                  else
832                          debug("0x%016llx", (long long)cpu->pc);                          debug("0x%016"PRIx64, (uint64_t) cpu->pc);
833          }          }
834          debug("\n");          debug("\n");
835    
# Line 1459  void emul_simple_init(struct emul *emul) Line 889  void emul_simple_init(struct emul *emul)
889    
890                  /*  Create a simple network:  */                  /*  Create a simple network:  */
891                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
892                      "10.0.0.0", 8, NULL, 0, 0);                      NET_DEFAULT_IPV4_MASK,
893                        NET_DEFAULT_IPV4_LEN,
894                        NULL, 0, 0, NULL);
895          } else {          } else {
896                  /*  Userland pseudo-machine:  */                  /*  Userland pseudo-machine:  */
897                  debug("Syscall emulation (userland-only) setup...\n");                  debug("Syscall emulation (userland-only) setup...\n");
# Line 1478  void emul_simple_init(struct emul *emul) Line 910  void emul_simple_init(struct emul *emul)
910   *   *
911   *  Create an emul struct by reading settings from a configuration file.   *  Create an emul struct by reading settings from a configuration file.
912   */   */
913  struct emul *emul_create_from_configfile(char *fname)  struct emul *emul_create_from_configfile(char *fname, int id)
914  {  {
915          int iadd = DEBUG_INDENTATION;          int iadd = DEBUG_INDENTATION;
916          struct emul *e = emul_new(fname);          struct emul *e = emul_new(fname, id);
917    
918          debug("Creating emulation from configfile \"%s\":\n", fname);          debug("Creating emulation from configfile \"%s\":\n", fname);
919          debug_indentation(iadd);          debug_indentation(iadd);
# Line 1568  void emul_run(struct emul **emuls, int n Line 1000  void emul_run(struct emul **emuls, int n
1000                  cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],                  cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0],
1001                      emuls[0]->machines[0]->cpus[0]->pc);                      emuls[0]->machines[0]->cpus[0]->pc);
1002    
1003            /*  Start emulated clocks:  */
1004            timer_start();
1005    
1006          /*          /*
1007           *  MAIN LOOP:           *  MAIN LOOP:
1008           *           *
# Line 1577  void emul_run(struct emul **emuls, int n Line 1012  void emul_run(struct emul **emuls, int n
1012          while (go) {          while (go) {
1013                  go = 0;                  go = 0;
1014    
1015                  x11_check_event(emuls, n_emuls);                  /*  Flush X11 and serial console output every now and then:  */
1016                    if (emuls[0]->machines[0]->ninstrs >
1017                        emuls[0]->machines[0]->ninstrs_flush + (1<<19)) {
1018                            x11_check_event(emuls, n_emuls);
1019                            console_flush();
1020                            emuls[0]->machines[0]->ninstrs_flush =
1021                                emuls[0]->machines[0]->ninstrs;
1022                    }
1023    
1024                    if (emuls[0]->machines[0]->ninstrs >
1025                        emuls[0]->machines[0]->ninstrs_show + (1<<25)) {
1026                            emuls[0]->machines[0]->ninstrs_since_gettimeofday +=
1027                                (emuls[0]->machines[0]->ninstrs -
1028                                 emuls[0]->machines[0]->ninstrs_show);
1029                            cpu_show_cycles(emuls[0]->machines[0], 0);
1030                            emuls[0]->machines[0]->ninstrs_show =
1031                                emuls[0]->machines[0]->ninstrs;
1032                    }
1033    
1034                    if (single_step == ENTER_SINGLE_STEPPING) {
1035                            /*  TODO: Cleanup!  */
1036                            old_instruction_trace =
1037                                emuls[0]->machines[0]->instruction_trace;
1038                            old_quiet_mode = quiet_mode;
1039                            old_show_trace_tree =
1040                                emuls[0]->machines[0]->show_trace_tree;
1041                            emuls[0]->machines[0]->instruction_trace = 1;
1042                            emuls[0]->machines[0]->show_trace_tree = 1;
1043                            quiet_mode = 0;
1044                            single_step = SINGLE_STEPPING;
1045                    }
1046    
1047                    if (single_step == SINGLE_STEPPING)
1048                            debugger();
1049    
1050                  for (i=0; i<n_emuls; i++) {                  for (i=0; i<n_emuls; i++) {
1051                          e = emuls[i];                          e = emuls[i];
                         if (e == NULL)  
                                 continue;  
1052    
1053                          for (j=0; j<e->n_machines; j++) {                          for (j=0; j<e->n_machines; j++) {
1054                                  if (e->machines[j]->gdb.port > 0)                                  anything = machine_run(e->machines[j]);
                                         debugger_gdb_check_incoming(  
                                             e->machines[j]);  
   
                                 /*  TODO: cpu_run() is a strange name, since  
                                     there can be multiple cpus in a machine  */  
                                 anything = cpu_run(e, e->machines[j]);  
1055                                  if (anything)                                  if (anything)
1056                                          go = 1;                                          go = 1;
1057                          }                          }
1058                  }                  }
1059          }          }
1060    
1061            /*  Stop any running timers:  */
1062            timer_stop();
1063    
1064          /*  Deinitialize all CPUs in all machines in all emulations:  */          /*  Deinitialize all CPUs in all machines in all emulations:  */
1065          for (i=0; i<n_emuls; i++) {          for (i=0; i<n_emuls; i++) {
1066                  e = emuls[i];                  e = emuls[i];
# Line 1614  void emul_run(struct emul **emuls, int n Line 1077  void emul_run(struct emul **emuls, int n
1077                  debugger();                  debugger();
1078          }          }
1079    
1080          /*  Any machine using X11? Then we should wait before exiting:  */          /*  Any machine using X11? Then wait before exiting:  */
1081          n = 0;          n = 0;
1082          for (i=0; i<n_emuls; i++)          for (i=0; i<n_emuls; i++)
1083                  for (j=0; j<emuls[i]->n_machines; j++)                  for (j=0; j<emuls[i]->n_machines; j++)
# Line 1624  void emul_run(struct emul **emuls, int n Line 1087  void emul_run(struct emul **emuls, int n
1087                  printf("Press enter to quit.\n");                  printf("Press enter to quit.\n");
1088                  while (!console_charavail(MAIN_CONSOLE)) {                  while (!console_charavail(MAIN_CONSOLE)) {
1089                          x11_check_event(emuls, n_emuls);                          x11_check_event(emuls, n_emuls);
1090                          usleep(1);                          usleep(10000);
1091                  }                  }
1092                  console_readchar(MAIN_CONSOLE);                  console_readchar(MAIN_CONSOLE);
1093          }          }
1094    
1095          console_deinit();          console_deinit_main();
1096  }  }
1097    

Legend:
Removed from v.24  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26