/[gxemul]/trunk/src/cpu_x86.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/cpu_x86.c

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

revision 4 by dpavlin, Mon Oct 8 16:18:00 2007 UTC revision 6 by dpavlin, Mon Oct 8 16:18:11 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_x86.c,v 1.24 2005/04/20 02:05:56 debug Exp $   *  $Id: cpu_x86.c,v 1.161 2005/05/31 06:20:38 debug Exp $
29   *   *
30   *  x86 (and amd64) CPU emulation.   *  x86 (and amd64) CPU emulation.
31   *   *
32   *   *
33   *  TODO:  Pretty much everything.   *  TODO:  Pretty much everything that has to do with 64-bit and 32-bit modes,
34     *  memory translation, flag bits, and so on.
35   *   *
36   *  See http://www.amd.com/us-en/Processors/DevelopWithAMD/   *  See http://www.amd.com/us-en/Processors/DevelopWithAMD/
37   *      0,,30_2252_875_7044,00.html for more info on AMD64.   *      0,,30_2252_875_7044,00.html for more info on AMD64.
38   *   *
39   *  http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a   *  http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
40   *  nice overview of the standard i386 opcodes.   *  nice overview of the standard i386 opcodes.
41     *
42     *  HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful.
43   */   */
44    
45  #include <stdio.h>  #include <stdio.h>
# Line 52  Line 55 
55    
56  #include "cpu_x86.h"  #include "cpu_x86.h"
57    
58    /*  (Bogus, when ENABLE_X86 isn't defined.)  */
59  /*  int x86_cpu_family_init(struct cpu_family *fp) { return 0; }
  *  x86_cpu_family_init():  
  *  
  *  Bogus, when ENABLE_X86 isn't defined.  
  */  
 int x86_cpu_family_init(struct cpu_family *fp)  
 {  
         return 0;  
 }  
60    
61    
62  #else   /*  ENABLE_X86  */  #else   /*  ENABLE_X86  */
# Line 69  int x86_cpu_family_init(struct cpu_famil Line 64  int x86_cpu_family_init(struct cpu_famil
64    
65  #include "cpu.h"  #include "cpu.h"
66  #include "cpu_x86.h"  #include "cpu_x86.h"
67    #include "devices.h"
68  #include "machine.h"  #include "machine.h"
69  #include "memory.h"  #include "memory.h"
70  #include "symbol.h"  #include "symbol.h"
# Line 83  extern int quiet_mode; Line 79  extern int quiet_mode;
79    
80  static struct x86_model models[] = x86_models;  static struct x86_model models[] = x86_models;
81  static char *reg_names[N_X86_REGS] = x86_reg_names;  static char *reg_names[N_X86_REGS] = x86_reg_names;
82    static char *reg_names_bytes[8] = x86_reg_names_bytes;
83  static char *seg_names[N_X86_SEGS] = x86_seg_names;  static char *seg_names[N_X86_SEGS] = x86_seg_names;
84  static char *cond_names[N_X86_CONDS] = x86_cond_names;  static char *cond_names[N_X86_CONDS] = x86_cond_names;
85    
86    #define REP_REP         1
87    #define REP_REPNE       2
88    
89    
90  /*  /*
91   *  x86_cpu_new():   *  x86_cpu_new():
# Line 128  struct cpu *x86_cpu_new(struct memory *m Line 128  struct cpu *x86_cpu_new(struct memory *m
128          cpu->running            = 0;          cpu->running            = 0;
129    
130          cpu->cd.x86.model = models[i];          cpu->cd.x86.model = models[i];
         cpu->cd.x86.mode = 32;  
         cpu->cd.x86.bits = 32;  
131    
132          if (cpu->cd.x86.model.model_number == X86_MODEL_AMD64)          /*  Initial startup is in 16-bit real mode:  */
133                  cpu->cd.x86.bits = 64;          cpu->pc = 0xfff0;
134    
135          cpu->cd.x86.r[X86_R_SP] = 0xff0;          /*  Initial segments:  */
136            cpu->cd.x86.descr_cache[X86_S_CS].valid = 1;
137            cpu->cd.x86.descr_cache[X86_S_CS].default_op_size = 16;
138            cpu->cd.x86.descr_cache[X86_S_CS].access_rights = 0x93;
139            cpu->cd.x86.descr_cache[X86_S_CS].base = 0xf0000; /* ffff0000  */
140            cpu->cd.x86.descr_cache[X86_S_CS].limit = 0xffff;
141            cpu->cd.x86.descr_cache[X86_S_CS].descr_type = DESCR_TYPE_CODE;
142            cpu->cd.x86.descr_cache[X86_S_CS].readable = 1;
143            cpu->cd.x86.descr_cache[X86_S_CS].writable = 1;
144            cpu->cd.x86.descr_cache[X86_S_CS].granularity = 0;
145            cpu->cd.x86.s[X86_S_CS] = 0xf000;
146    
147            cpu->cd.x86.idtr = 0;
148            cpu->cd.x86.idtr_limit = 0x3ff;
149    
150            cpu->translate_address = translate_address_x86;
151    
152            cpu->cd.x86.rflags = 0x0002;
153            if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
154                    cpu->cd.x86.rflags |= 0xf000;
155    
156          /*  Only show name and caches etc for CPU nr 0 (in SMP machines):  */          /*  Only show name and caches etc for CPU nr 0 (in SMP machines):  */
157          if (cpu_id == 0) {          if (cpu_id == 0) {
# Line 150  struct cpu *x86_cpu_new(struct memory *m Line 167  struct cpu *x86_cpu_new(struct memory *m
167   */   */
168  void x86_cpu_dumpinfo(struct cpu *cpu)  void x86_cpu_dumpinfo(struct cpu *cpu)
169  {  {
170          debug(" (%i-bit)", cpu->cd.x86.bits);          debug(", currently in %s mode", PROTECTED_MODE? "protected" : "real");
         debug(", currently in %i-bit mode", cpu->cd.x86.mode);  
171          debug("\n");          debug("\n");
172  }  }
173    
# Line 189  void x86_cpu_register_dump(struct cpu *c Line 205  void x86_cpu_register_dump(struct cpu *c
205          uint64_t offset;          uint64_t offset;
206          int i, x = cpu->cpu_id;          int i, x = cpu->cpu_id;
207    
208          if (cpu->cd.x86.mode == 16) {          if (REAL_MODE) {
209                    /*  Real-mode:  */
210                  debug("cpu%i:  cs:ip = 0x%04x:0x%04x\n", x,                  debug("cpu%i:  cs:ip = 0x%04x:0x%04x\n", x,
211                      cpu->cd.x86.s[X86_S_CS], (int)cpu->pc);                      cpu->cd.x86.s[X86_S_CS], (int)cpu->pc);
212    
# Line 206  void x86_cpu_register_dump(struct cpu *c Line 223  void x86_cpu_register_dump(struct cpu *c
223                      "= 0x%04x\n", x,                      "= 0x%04x\n", x,
224                      (int)cpu->cd.x86.s[X86_S_DS], (int)cpu->cd.x86.s[X86_S_ES],                      (int)cpu->cd.x86.s[X86_S_DS], (int)cpu->cd.x86.s[X86_S_ES],
225                      (int)cpu->cd.x86.s[X86_S_SS], (int)cpu->cd.x86.rflags);                      (int)cpu->cd.x86.s[X86_S_SS], (int)cpu->cd.x86.rflags);
226          } else if (cpu->cd.x86.mode == 32) {          } else {
227                  symbol = get_symbol_name(&cpu->machine->symbol_context,                  symbol = get_symbol_name(&cpu->machine->symbol_context,
228                      cpu->pc, &offset);                      cpu->pc, &offset);
229    
# Line 222  void x86_cpu_register_dump(struct cpu *c Line 239  void x86_cpu_register_dump(struct cpu *c
239                      "0x%08x\n", x,                      "0x%08x\n", x,
240                      (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],                      (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
241                      (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);                      (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
242    #if 0
243          } else {          } else {
244                  /*  64-bit  */                  /*  64-bit  */
245                  symbol = get_symbol_name(&cpu->machine->symbol_context,                  symbol = get_symbol_name(&cpu->machine->symbol_context,
# Line 239  void x86_cpu_register_dump(struct cpu *c Line 257  void x86_cpu_register_dump(struct cpu *c
257                          if ((i & 1) == 1)                          if ((i & 1) == 1)
258                                  debug("\n");                                  debug("\n");
259                  }                  }
260    #endif
261          }          }
262    
263          if (cpu->cd.x86.mode >= 32) {          if (coprocs != 0) {
264                    for (i=0; i<6; i++) {
265                            debug("cpu%i:  %s=0x%04x (", x, seg_names[i],
266                                cpu->cd.x86.s[i]);
267                            if (cpu->cd.x86.descr_cache[i].valid) {
268                                    debug("base=0x%08x, limit=0x%08x, ",
269                                        (int)cpu->cd.x86.descr_cache[i].base,
270                                        (int)cpu->cd.x86.descr_cache[i].limit);
271                                    debug("%s", cpu->cd.x86.descr_cache[i].
272                                        descr_type==DESCR_TYPE_CODE?"CODE":"DATA");
273                                    debug(", %i-bit", cpu->cd.x86.descr_cache[i].
274                                        default_op_size);
275                                    debug(", %s%s", cpu->cd.x86.descr_cache[i].
276                                        readable? "R" : "-", cpu->cd.x86.
277                                        descr_cache[i].writable? "W" : "-");
278                            } else
279                                    debug("invalid");
280                            debug(")\n");
281                    }
282                    debug("cpu%i:  gdtr=0x%08llx:0x%04x  idtr=0x%08llx:0x%04x "
283                        " ldtr=0x%08x:0x%04x\n", x, (long long)cpu->cd.x86.gdtr,
284                        (int)cpu->cd.x86.gdtr_limit, (long long)cpu->cd.x86.idtr,
285                        (int)cpu->cd.x86.idtr_limit, (long long)cpu->cd.x86.
286                        ldtr_base, (int)cpu->cd.x86.ldtr_limit);
287                    debug("cpu%i:  pic1: irr=0x%02x ier=0x%02x isr=0x%02x "
288                        "base=0x%02x\n", x, cpu->machine->md.pc.pic1->irr,
289                        cpu->machine->md.pc.pic1->ier,cpu->machine->md.pc.pic1->isr,
290                        cpu->machine->md.pc.pic1->irq_base);
291                    debug("cpu%i:  pic2: irr=0x%02x ier=0x%02x isr=0x%02x "
292                        "base=0x%02x\n", x, cpu->machine->md.pc.pic2->irr,
293                        cpu->machine->md.pc.pic2->ier,cpu->machine->md.pc.pic2->isr,
294                        cpu->machine->md.pc.pic2->irq_base);
295            } else if (PROTECTED_MODE) {
296                    /*  Protected mode:  */
297                  debug("cpu%i:  cs=0x%04x  ds=0x%04x  es=0x%04x  "                  debug("cpu%i:  cs=0x%04x  ds=0x%04x  es=0x%04x  "
298                      "fs=0x%04x  gs=0x%04x  ss=0x%04x\n", x,                      "fs=0x%04x  gs=0x%04x  ss=0x%04x\n", x,
299                      (int)cpu->cd.x86.s[X86_S_CS], (int)cpu->cd.x86.s[X86_S_DS],                      (int)cpu->cd.x86.s[X86_S_CS], (int)cpu->cd.x86.s[X86_S_DS],
# Line 249  void x86_cpu_register_dump(struct cpu *c Line 301  void x86_cpu_register_dump(struct cpu *c
301                      (int)cpu->cd.x86.s[X86_S_GS], (int)cpu->cd.x86.s[X86_S_SS]);                      (int)cpu->cd.x86.s[X86_S_GS], (int)cpu->cd.x86.s[X86_S_SS]);
302          }          }
303    
304          if (cpu->cd.x86.mode == 32) {          if (PROTECTED_MODE) {
305                  debug("cpu%i:  cr0 = 0x%08x  cr3 = 0x%08x  eflags = 0x%08x\n",                  /*  Protected mode:  */
306                      x, (int)cpu->cd.x86.cr[0],                  debug("cpu%i:  cr0=0x%08x  cr2=0x%08x  cr3=0x%08x  eflags="
307                      (int)cpu->cd.x86.cr[3], (int)cpu->cd.x86.rflags);                      "0x%08x\n", x, (int)cpu->cd.x86.cr[0],
308          }                      (int)cpu->cd.x86.cr[2], (int)cpu->cd.x86.cr[3],
309                        (int)cpu->cd.x86.rflags);
310          if (cpu->cd.x86.mode == 64) {                  debug("cpu%i:  tr = 0x%04x (base=0x%llx, limit=0x%x)\n",
311                  debug("cpu%i:  cr0 = 0x%016llx  cr3 = 0x%016llx\n", x,                      x, (int)cpu->cd.x86.tr, (long long)cpu->cd.x86.tr_base,
312                      "0x%016llx\n", x, (long long)cpu->cd.x86.cr[0], (long long)                      (int)cpu->cd.x86.tr_limit);
                     cpu->cd.x86.cr[3]);  
                 debug("cpu%i:  rflags = 0x%016llx\n", x,  
                     (long long)cpu->cd.x86.rflags);  
313          }          }
314  }  }
315    
# Line 269  void x86_cpu_register_dump(struct cpu *c Line 318  void x86_cpu_register_dump(struct cpu *c
318   *  x86_cpu_register_match():   *  x86_cpu_register_match():
319   */   */
320  void x86_cpu_register_match(struct machine *m, char *name,  void x86_cpu_register_match(struct machine *m, char *name,
321          int writeflag, uint64_t *valuep, int *match_register)          int writeflag, uint64_t *valuep, int *mr)
322  {  {
323          int cpunr = 0;          int cpunr = 0;
324            int r;
325    
326          /*  CPU number:  */          /*  CPU number:  TODO  */
327    
328          /*  TODO  */          if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) {
   
         /*  Register name:  */  
         if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "ip") == 0  
             || strcasecmp(name, "eip") == 0) {  
329                  if (writeflag) {                  if (writeflag) {
330                          m->cpus[cpunr]->pc = *valuep;                          m->cpus[cpunr]->pc = *valuep;
331                            m->cpus[cpunr]->cd.x86.halted = 0;
332                  } else                  } else
333                          *valuep = m->cpus[cpunr]->pc;                          *valuep = m->cpus[cpunr]->pc;
334                  *match_register = 1;                  *mr = 1;
335                    return;
336            }
337            if (strcasecmp(name, "ip") == 0) {
338                    if (writeflag) {
339                            m->cpus[cpunr]->pc = (m->cpus[cpunr]->pc & ~0xffff)
340                                | (*valuep & 0xffff);
341                            m->cpus[cpunr]->cd.x86.halted = 0;
342                    } else
343                            *valuep = m->cpus[cpunr]->pc & 0xffff;
344                    *mr = 1;
345                    return;
346            }
347            if (strcasecmp(name, "eip") == 0) {
348                    if (writeflag) {
349                            m->cpus[cpunr]->pc = *valuep;
350                            m->cpus[cpunr]->cd.x86.halted = 0;
351                    } else
352                            *valuep = m->cpus[cpunr]->pc & 0xffffffffULL;
353                    *mr = 1;
354                    return;
355          }          }
356    
357  #if 0          if (strcasecmp(name, "rflags") == 0) {
358  TODO: regmatch for 64, 32, 16, and 8 bit register names                  if (writeflag)
359  #endif                          m->cpus[cpunr]->cd.x86.rflags = *valuep;
360                    else
361                            *valuep = m->cpus[cpunr]->cd.x86.rflags;
362                    *mr = 1;
363                    return;
364            }
365            if (strcasecmp(name, "eflags") == 0) {
366                    if (writeflag)
367                            m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
368                                cd.x86.rflags & ~0xffffffffULL) | (*valuep &
369                                0xffffffffULL);
370                    else
371                            *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffffffffULL;
372                    *mr = 1;
373                    return;
374            }
375            if (strcasecmp(name, "flags") == 0) {
376                    if (writeflag)
377                            m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
378                                cd.x86.rflags & ~0xffff) | (*valuep & 0xffff);
379                    else
380                            *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffff;
381                    *mr = 1;
382                    return;
383            }
384    
385            /*  8-bit low:  */
386            for (r=0; r<4; r++)
387                    if (strcasecmp(name, reg_names_bytes[r]) == 0) {
388                            if (writeflag)
389                                    m->cpus[cpunr]->cd.x86.r[r] =
390                                        (m->cpus[cpunr]->cd.x86.r[r] & ~0xff)
391                                        | (*valuep & 0xff);
392                            else
393                                    *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xff;
394                            *mr = 1;
395                            return;
396                    }
397    
398            /*  8-bit high:  */
399            for (r=0; r<4; r++)
400                    if (strcasecmp(name, reg_names_bytes[r+4]) == 0) {
401                            if (writeflag)
402                                    m->cpus[cpunr]->cd.x86.r[r] =
403                                        (m->cpus[cpunr]->cd.x86.r[r] & ~0xff00)
404                                        | ((*valuep & 0xff) << 8);
405                            else
406                                    *valuep = (m->cpus[cpunr]->cd.x86.r[r] >>
407                                        8) & 0xff;
408                            *mr = 1;
409                            return;
410                    }
411    
412            /*  16-, 32-, 64-bit registers:  */
413            for (r=0; r<N_X86_REGS; r++) {
414                    /*  16-bit:  */
415                    if (r<8 && strcasecmp(name, reg_names[r]) == 0) {
416                            if (writeflag)
417                                    m->cpus[cpunr]->cd.x86.r[r] =
418                                        (m->cpus[cpunr]->cd.x86.r[r] & ~0xffff)
419                                        | (*valuep & 0xffff);
420                            else
421                                    *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xffff;
422                            *mr = 1;
423                            return;
424                    }
425    
426                    /*  32-bit:  */
427                    if (r<8 && (name[0]=='e' || name[0]=='E') &&
428                        strcasecmp(name+1, reg_names[r]) == 0) {
429                            if (writeflag)
430                                    m->cpus[cpunr]->cd.x86.r[r] =
431                                        *valuep & 0xffffffffULL;
432                            else
433                                    *valuep = m->cpus[cpunr]->cd.x86.r[r] &
434                                        0xffffffffULL;
435                            *mr = 1;
436                            return;
437                    }
438    
439                    /*  64-bit:  */
440                    if ((name[0]=='r' || name[0]=='R') &&
441                        strcasecmp(name+1, reg_names[r]) == 0) {
442                            if (writeflag)
443                                    m->cpus[cpunr]->cd.x86.r[r] = *valuep;
444                            else
445                                    *valuep = m->cpus[cpunr]->cd.x86.r[r];
446                            *mr = 1;
447                            return;
448                    }
449            }
450    
451            /*  segment names:  */
452            for (r=0; r<N_X86_SEGS; r++) {
453                    if (strcasecmp(name, seg_names[r]) == 0) {
454                            if (writeflag)
455                                    m->cpus[cpunr]->cd.x86.s[r] =
456                                        (m->cpus[cpunr]->cd.x86.s[r] & ~0xffff)
457                                        | (*valuep & 0xffff);
458                            else
459                                    *valuep = m->cpus[cpunr]->cd.x86.s[r] & 0xffff;
460                            *mr = 1;
461                            return;
462                    }
463            }
464    
465            /*  control registers: (TODO: 32- vs 64-bit on AMD64?)  */
466            if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) {
467                    int r = atoi(name+2);
468                    if (writeflag)
469                            m->cpus[cpunr]->cd.x86.cr[r] = *valuep;
470                    else
471                            *valuep = m->cpus[cpunr]->cd.x86.cr[r];
472                    *mr = 1;
473                    return;
474            }
475  }  }
476    
477    
# Line 298  TODO: regmatch for 64, 32, 16, and 8 bit Line 480  TODO: regmatch for 64, 32, 16, and 8 bit
480  #define modify(old,new) (                                       \  #define modify(old,new) (                                       \
481                  mode==16? (                                     \                  mode==16? (                                     \
482                          ((old) & ~0xffff) + ((new) & 0xffff)    \                          ((old) & ~0xffff) + ((new) & 0xffff)    \
483                  ) : (new) )                  ) : ((new) & 0xffffffffULL) )
484    
485  #define HEXPRINT(x,n) { int j; for (j=0; j<(n); j++) debug("%02x",(x)[j]); }  /*  "volatile" here, because some versions of gcc with -O3 on i386 are buggy  */
486  #define HEXSPACES(i) { int j; for (j=0; j<10-(i);j++) debug("  "); debug(" "); }  #define HEXPRINT(x,n) { volatile int j; for (j=0; j<(n); j++) \
487            debug("%02x",(x)[j]); }
488    #define HEXSPACES(i) { int j; j = (i)>10? 10:(i); while (j++<10) debug("  "); \
489            debug(" "); }
490  #define SPACES  HEXSPACES(ilen)  #define SPACES  HEXSPACES(ilen)
491    
492    
493  static uint32_t read_imm_common(unsigned char **instrp, int *ilenp,  static uint32_t read_imm_common(unsigned char **instrp, uint64_t *ilenp,
494          int len, int printflag)          int len, int printflag)
495  {  {
496          uint32_t imm;          uint32_t imm;
# Line 322  static uint32_t read_imm_common(unsigned Line 507  static uint32_t read_imm_common(unsigned
507          if (printflag)          if (printflag)
508                  HEXPRINT(instr, len / 8);                  HEXPRINT(instr, len / 8);
509    
510          (*ilenp) += len/8;          if (ilenp != NULL)
511                    (*ilenp) += len/8;
512    
513          (*instrp) += len/8;          (*instrp) += len/8;
514          return imm;          return imm;
515  }  }
516    
517    
518  static uint32_t read_imm_and_print(unsigned char **instrp, int *ilenp,  static uint32_t read_imm_and_print(unsigned char **instrp, uint64_t *ilenp,
519          int mode)          int mode)
520  {  {
521          return read_imm_common(instrp, ilenp, mode, 1);          return read_imm_common(instrp, ilenp, mode, 1);
522  }  }
523    
524    
525  static uint32_t read_imm(unsigned char **instrp, uint64_t *newpc,  static uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
526          int mode)          int mode)
527  {  {
528          int x = 0;          return read_imm_common(instrp, newpcp, mode, 0);
         uint32_t r = read_imm_common(instrp, &x, mode, 0);  
         (*newpc) += x;  
         return r;  
529  }  }
530    
531    
532  static void print_csip(struct cpu *cpu)  static void print_csip(struct cpu *cpu)
533  {  {
534          if (cpu->cd.x86.mode < 64)          fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
535                  fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);          if (PROTECTED_MODE)
536          switch (cpu->cd.x86.mode) {                  fatal("0x%llx", (long long)cpu->pc);
537          case 16: fatal("0x%04x", (int)cpu->pc); break;          else
538          case 32: fatal("0x%08x", (int)cpu->pc); break;                  fatal("0x%04x", (int)cpu->pc);
539          case 64: fatal("0x%016llx", (long long)cpu->pc); break;  }
540    
541    
542    /*
543     *  x86_cpu_interrupt():
544     *
545     *  NOTE: Interacting with the 8259 PIC is done in src/machine.c.
546     */
547    int x86_cpu_interrupt(struct cpu *cpu, uint64_t nr)
548    {
549            if (cpu->machine->md_interrupt != NULL)
550                    cpu->machine->md_interrupt(cpu->machine, cpu, nr, 1);
551            else {
552                    fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
553                    return 1;
554            }
555    
556            return 1;
557    }
558    
559    
560    /*
561     *  x86_cpu_interrupt_ack():
562     *
563     *  NOTE: Interacting with the 8259 PIC is done in src/machine.c.
564     */
565    int x86_cpu_interrupt_ack(struct cpu *cpu, uint64_t nr)
566    {
567            if (cpu->machine->md_interrupt != NULL)
568                    cpu->machine->md_interrupt(cpu->machine, cpu, nr, 0);
569            else {
570                    fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
571                    return 1;
572          }          }
573    
574            return 1;
575  }  }
576    
577    
578  static char modrm_dst[65];  /*  (NOTE: Don't use the lowest 3 bits in these defines)  */
579  static char modrm_src[65];  #define RELOAD_TR               0x1000
580  static void read_modrm(int mode, unsigned char **instrp, int *ilenp)  #define RELOAD_LDTR             0x1008
581    
582    
583    /*
584     *  x86_task_switch():
585     *
586     *  Save away current state into the current task state segment, and
587     *  load the new state from the new task.
588     *
589     *  TODO: 16-bit TSS, etc. And clean up all of this :)
590     *
591     *  TODO: Link word. AMD64 stuff. And lots more.
592     */
593    void x86_task_switch(struct cpu *cpu, int new_tr, uint64_t *curpc)
594  {  {
595          uint32_t imm = read_imm_and_print(instrp, ilenp, 8);          unsigned char old_descr[8];
596          modrm_dst[0] = modrm_dst[64] = '\0';          unsigned char new_descr[8];
597          modrm_src[0] = modrm_src[64] = '\0';          uint32_t value, ofs;
598            int i;
599            unsigned char buf[4];
600    
601            fatal("x86_task_switch():\n");
602            cpu->pc = *curpc;
603    
604            if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
605                old_descr, sizeof(old_descr), MEM_READ, NO_SEGMENTATION)) {
606                    fatal("x86_task_switch(): TODO: 1\n");
607                    cpu->running = 0;
608                    return;
609            }
610    
611            /*  Check the busy bit, and then clear it:  */
612            if (!(old_descr[5] & 0x02)) {
613                    fatal("x86_task_switch(): TODO: switching FROM a non-BUSY"
614                        " TSS descriptor?\n");
615                    cpu->running = 0;
616                    return;
617            }
618            old_descr[5] &= ~0x02;
619            if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
620                old_descr, sizeof(old_descr), MEM_WRITE, NO_SEGMENTATION)) {
621                    fatal("x86_task_switch(): TODO: could not clear busy bit\n");
622                    cpu->running = 0;
623                    return;
624            }
625    
626            x86_cpu_register_dump(cpu, 1, 1);
627    
628            /*  Set the task-switched bit in CR0:  */
629            cpu->cd.x86.cr[0] |= X86_CR0_TS;
630    
631            /*  Save away all the old registers:  */
632    #define WRITE_VALUE { buf[0]=value; buf[1]=value>>8; buf[2]=value>>16; \
633            buf[3]=value>>24; cpu->memory_rw(cpu, cpu->mem, \
634            cpu->cd.x86.tr_base + ofs, buf, sizeof(buf), MEM_WRITE,  \
635            NO_SEGMENTATION); }
636    
637            ofs = 0x1c; value = cpu->cd.x86.cr[3]; WRITE_VALUE;
638            ofs = 0x20; value = cpu->pc; WRITE_VALUE;
639            ofs = 0x24; value = cpu->cd.x86.rflags; WRITE_VALUE;
640            for (i=0; i<N_X86_REGS; i++) {
641                    ofs = 0x28+i*4; value = cpu->cd.x86.r[i]; WRITE_VALUE;
642            }
643            for (i=0; i<6; i++) {
644                    ofs = 0x48+i*4; value = cpu->cd.x86.s[i]; WRITE_VALUE;
645            }
646    
647            fatal("-------\n");
648    
649            if ((cpu->cd.x86.tr & 0xfffc) == 0) {
650                    fatal("TODO: x86_task_switch(): task switch, but old TR"
651                        " was 0?\n");
652                    cpu->running = 0;
653                    return;
654            }
655    
656            if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + new_tr,
657                new_descr, sizeof(new_descr), MEM_READ, NO_SEGMENTATION)) {
658                    fatal("x86_task_switch(): TODO: 1\n");
659                    cpu->running = 0;
660                    return;
661            }
662            if (new_descr[5] & 0x02) {
663                    fatal("x86_task_switch(): TODO: switching TO an already BUSY"
664                        " TSS descriptor?\n");
665                    cpu->running = 0;
666                    return;
667            }
668    
669            reload_segment_descriptor(cpu, RELOAD_TR, new_tr, NULL);
670    
671  fatal("read_modrm(): TODO\n");          if (cpu->cd.x86.tr_limit < 0x67)
672                    fatal("WARNING: tr_limit = 0x%x, must be at least 0x67!\n",
673                        (int)cpu->cd.x86.tr_limit);
674    
675            /*  Read new registers:  */
676    #define READ_VALUE { cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.tr_base + \
677            ofs, buf, sizeof(buf), MEM_READ, NO_SEGMENTATION); \
678            value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); }
679    
680            ofs = 0x1c; READ_VALUE; cpu->cd.x86.cr[3] = value;
681            ofs = 0x20; READ_VALUE; cpu->pc = value;
682            ofs = 0x24; READ_VALUE; cpu->cd.x86.rflags = value;
683            for (i=0; i<N_X86_REGS; i++) {
684                    ofs = 0x28+i*4; READ_VALUE; cpu->cd.x86.r[i] = value;
685            }
686            for (i=0; i<6; i++) {
687                    ofs = 0x48+i*4; READ_VALUE;
688                    reload_segment_descriptor(cpu, i, value, NULL);
689            }
690            ofs = 0x60; READ_VALUE; value &= 0xffff;
691            reload_segment_descriptor(cpu, RELOAD_LDTR, value, NULL);
692    
693            if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) !=
694                (cpu->cd.x86.s[X86_S_SS] & X86_PL_MASK))
695                    fatal("WARNING: rpl in CS and SS differ!\n");
696    
697            if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) == X86_RING3 &&
698                !(cpu->cd.x86.rflags & X86_FLAGS_IF))
699                    fatal("WARNING (?): switching to userland task, but interrupts"
700                        " are disabled?\n");
701    
702          if ((imm & 0xc0) == 0xc0) {          x86_cpu_register_dump(cpu, 1, 1);
703            fatal("-------\n");
704    
705            *curpc = cpu->pc;
706    
707            /*  cpu->machine->instruction_trace = 1;  */
708            /*  cpu->running = 0;  */
709    }
710    
711    
712    /*
713     *  reload_segment_descriptor():
714     *
715     *  Loads base, limit and other settings from the Global Descriptor Table into
716     *  segment descriptors.
717     *
718     *  This function can also be used to reload the TR (task register).
719     *
720     *  And also to do a task switch, or jump into a trap handler etc.
721     *  (Perhaps this function should be renamed.)
722     */
723    void reload_segment_descriptor(struct cpu *cpu, int segnr, int selector,
724            uint64_t *curpcp)
725    {
726            int res, i, readable, writable, granularity, descr_type;
727            int segment = 1, rpl, orig_selector = selector;
728            unsigned char descr[8];
729            char *table_name = "GDT";
730            uint64_t base, limit, table_base, table_limit;
731    
732            if (segnr > 0x100)      /*  arbitrary, larger than N_X86_SEGS  */
733                    segment = 0;
734    
735            if (segment && (segnr < 0 || segnr >= N_X86_SEGS)) {
736                    fatal("reload_segment_descriptor(): segnr = %i\n", segnr);
737                    exit(1);
738            }
739    
740            if (segment && REAL_MODE) {
741                    /*  Real mode:  */
742                    cpu->cd.x86.descr_cache[segnr].valid = 1;
743                    cpu->cd.x86.descr_cache[segnr].default_op_size = 16;
744                    cpu->cd.x86.descr_cache[segnr].access_rights = 0x93;
745                    cpu->cd.x86.descr_cache[segnr].descr_type =
746                        segnr == X86_S_CS? DESCR_TYPE_CODE : DESCR_TYPE_DATA;
747                    cpu->cd.x86.descr_cache[segnr].readable = 1;
748                    cpu->cd.x86.descr_cache[segnr].writable = 1;
749                    cpu->cd.x86.descr_cache[segnr].granularity = 0;
750                    cpu->cd.x86.descr_cache[segnr].base = selector << 4;
751                    cpu->cd.x86.descr_cache[segnr].limit = 0xffff;
752                    cpu->cd.x86.s[segnr] = selector;
753                    return;
754            }
755    
756            /*
757             *  Protected mode:  Load the descriptor cache from the GDT.
758             */
759    
760            table_base = cpu->cd.x86.gdtr;
761            table_limit = cpu->cd.x86.gdtr_limit;
762            if (selector & 4) {
763                    table_name = "LDT";
764                    /*  fatal("TODO: x86 translation via LDT: 0x%04x\n",
765                        selector);  */
766                    table_base = cpu->cd.x86.ldtr_base;
767                    table_limit = cpu->cd.x86.ldtr_limit;
768            }
769    
770            /*  Special case: Null-descriptor:  */
771            if (segment && (selector & ~3) == 0) {
772                    cpu->cd.x86.descr_cache[segnr].valid = 0;
773                    cpu->cd.x86.s[segnr] = selector;
774                    return;
775            }
776    
777            rpl = selector & 3;
778    
779            /*  TODO: check rpl  */
780    
781            selector &= ~7;
782    
783            if (selector + 7 > table_limit) {
784                    fatal("TODO: selector 0x%04x outside %s limit (0x%04x)\n",
785                        selector, table_name, (int)table_limit);
786                    cpu->running = 0;
787                    return;
788            }
789    
790            res = cpu->memory_rw(cpu, cpu->mem, table_base + selector,
791                descr, sizeof(descr), MEM_READ, NO_SEGMENTATION);
792            if (!res) {
793                    fatal("reload_segment_descriptor(): TODO: "
794                        "could not read the GDT\n");
795                    cpu->running = 0;
796                    return;
797            }
798    
799            base = descr[2] + (descr[3] << 8) + (descr[4] << 16) +
800                (descr[7] << 24);
801            limit = descr[0] + (descr[1] << 8) + ((descr[6]&15) << 16);
802    
803            descr_type = readable = writable = granularity = 0;
804            granularity = (descr[6] & 0x80)? 1 : 0;
805            if (limit == 0) {
806                    fatal("WARNING: descriptor limit = 0\n");
807                    limit = 0xfffff;
808            }
809            if (granularity)
810                    limit = (limit << 12) | 0xfff;
811    
812    #if 0
813    printf("base = %llx\n",(long long)base);
814    for (i=0; i<8; i++)
815            fatal(" %02x", descr[i]);
816    #endif
817    
818            if (selector != 0x0000 && (descr[5] & 0x80) == 0x00) {
819                    fatal("TODO: nonpresent descriptor?\n");
820                    goto fail_dump;
821            }
822    
823            if (!segment) {
824                    switch (segnr) {
825                    case RELOAD_TR:
826                            /*  Check that this is indeed a TSS descriptor:  */
827                            if ((descr[5] & 0x15) != 0x01) {
828                                    fatal("TODO: load TR but entry in table is"
829                                        " not a TSS descriptor?\n");
830                                    goto fail_dump;
831                            }
832    
833                            /*  Reload the task register:  */
834                            cpu->cd.x86.tr = selector;
835                            cpu->cd.x86.tr_base = base;
836                            cpu->cd.x86.tr_limit = limit;
837    
838                            /*  Mark the TSS as busy:  */
839                            descr[5] |= 0x02;
840                            res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr +
841                                selector, descr, sizeof(descr), MEM_WRITE,
842                                NO_SEGMENTATION);
843                            break;
844                    case RELOAD_LDTR:
845                            /*  Reload the Local Descriptor Table register:  */
846                            cpu->cd.x86.ldtr = selector;
847                            cpu->cd.x86.ldtr_base = base;
848                            cpu->cd.x86.ldtr_limit = limit;
849                            break;
850                    }
851                    return;
852            }
853    
854            if ((descr[5] & 0x18) == 0x18) {
855                    descr_type = DESCR_TYPE_CODE;
856                    readable = descr[5] & 0x02? 1 : 0;
857                    if ((descr[5] & 0x98) != 0x98) {
858                            fatal("TODO CODE\n");
859                            goto fail_dump;
860                    }
861            } else if ((descr[5] & 0x18) == 0x10) {
862                    descr_type = DESCR_TYPE_DATA;
863                    readable = 1;
864                    writable = descr[5] & 0x02? 1 : 0;
865                    if ((descr[5] & 0x98) != 0x90) {
866                            fatal("TODO DATA\n");
867                            goto fail_dump;
868                    }
869            } else if (segnr == X86_S_CS && (descr[5] & 0x15) == 0x01
870                && curpcp != NULL) {
871                    /*  TSS  */
872                    x86_task_switch(cpu, selector, curpcp);
873                    return;
874          } else {          } else {
875                  fatal("read_modrm(): unimplemented modr/m\n");                  fatal("TODO: other\n");
876                    goto fail_dump;
877          }          }
878    
879            cpu->cd.x86.descr_cache[segnr].valid = 1;
880            cpu->cd.x86.descr_cache[segnr].default_op_size =
881                (descr[6] & 0x40)? 32 : 16;
882            cpu->cd.x86.descr_cache[segnr].access_rights = descr[5];
883            cpu->cd.x86.descr_cache[segnr].descr_type = descr_type;
884            cpu->cd.x86.descr_cache[segnr].readable = readable;
885            cpu->cd.x86.descr_cache[segnr].writable = writable;
886            cpu->cd.x86.descr_cache[segnr].granularity = granularity;
887            cpu->cd.x86.descr_cache[segnr].base = base;
888            cpu->cd.x86.descr_cache[segnr].limit = limit;
889            cpu->cd.x86.s[segnr] = orig_selector;
890            return;
891    
892    fail_dump:
893            for (i=0; i<8; i++)
894                    fatal(" %02x", descr[i]);
895            cpu->running = 0;
896    }
897    
898    
899    /*
900     *  x86_load():
901     *
902     *  Returns same error code as memory_rw().
903     */
904    static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
905    {
906            unsigned char databuf[8];
907            int res;
908            uint64_t d;
909    
910            res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
911                MEM_READ, CACHE_DATA);
912    
913            d = databuf[0];
914            if (len > 1) {
915                    d += ((uint64_t)databuf[1] << 8);
916                    if (len > 2) {
917                            d += ((uint64_t)databuf[2] << 16);
918                            d += ((uint64_t)databuf[3] << 24);
919                            if (len > 4) {
920                                    d += ((uint64_t)databuf[4] << 32);
921                                    d += ((uint64_t)databuf[5] << 40);
922                                    d += ((uint64_t)databuf[6] << 48);
923                                    d += ((uint64_t)databuf[7] << 56);
924                            }
925                    }
926            }
927    
928            *data = d;
929            return res;
930    }
931    
932    
933    /*
934     *  x86_store():
935     *
936     *  Returns same error code as memory_rw().
937     */
938    static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
939    {
940            unsigned char databuf[8];
941    
942            /*  x86 is always little-endian:  */
943            databuf[0] = data;
944            if (len > 1) {
945                    databuf[1] = data >> 8;
946                    if (len > 2) {
947                            databuf[2] = data >> 16;
948                            databuf[3] = data >> 24;
949                            if (len > 4) {
950                                    databuf[4] = data >> 32;
951                                    databuf[5] = data >> 40;
952                                    databuf[6] = data >> 48;
953                                    databuf[7] = data >> 56;
954                            }
955                    }
956            }
957    
958            return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
959                MEM_WRITE, CACHE_DATA);
960    }
961    
962    
963    /*
964     *  x86_write_cr():
965     *
966     *  Write to a control register.
967     */
968    static void x86_write_cr(struct cpu *cpu, int r, uint64_t value)
969    {
970            uint64_t new, tmp;
971    
972            switch (r) {
973            case 0: new = cpu->cd.x86.cr[r] = value;
974                    /*  Warn about unimplemented bits:  */
975                    tmp = new & ~(X86_CR0_PE | X86_CR0_PG);
976                    if (cpu->cd.x86.model.model_number <= X86_MODEL_80386) {
977                            if (tmp & X86_CR0_WP)
978                                    fatal("WARNING: cr0 WP bit set, but this is"
979                                        " not an 80486 or higher (?)\n");
980                    }
981                    tmp &= ~X86_CR0_WP;
982                    if (tmp != 0)
983                            fatal("x86_write_cr(): unimplemented cr0 bits: "
984                                "0x%08llx\n", (long long)tmp);
985                    break;
986            case 2:
987            case 3: new = cpu->cd.x86.cr[r] = value;
988                    break;
989            case 4: new = cpu->cd.x86.cr[r] = value;
990                    /*  Warn about unimplemented bits:  */
991                    tmp = new; /*  & ~(X86_CR0_PE | X86_CR0_PG); */
992                    if (tmp != 0)
993                            fatal("x86_write_cr(): unimplemented cr4 bits: "
994                                "0x%08llx\n", (long long)tmp);
995                    break;
996            default:fatal("x86_write_cr(): write to UNIMPLEMENTED cr%i\n", r);
997                    cpu->running = 0;
998            }
999    }
1000    
1001    
1002    static char *ofs_string(int32_t imm)
1003    {
1004            static char buf[25];
1005            buf[0] = buf[sizeof(buf)-1] = '\0';
1006    
1007            if (imm > 32)
1008                    sprintf(buf, "+0x%x", imm);
1009            else if (imm > 0)
1010                    sprintf(buf, "+%i", imm);
1011            else if (imm < -32)
1012                    sprintf(buf, "-0x%x", -imm);
1013            else if (imm < 0)
1014                    sprintf(buf, "-%i", -imm);
1015    
1016            return buf;
1017    }
1018    
1019    
1020    static char modrm_r[65];
1021    static char modrm_rm[65];
1022    #define MODRM_READ      0
1023    #define MODRM_WRITE_RM  1
1024    #define MODRM_WRITE_R   2
1025    /*  flags:  */
1026    #define MODRM_EIGHTBIT          1
1027    #define MODRM_SEG               2
1028    #define MODRM_JUST_GET_ADDR     4
1029    #define MODRM_CR                8
1030    #define MODRM_DR                16
1031    #define MODRM_R_NONEIGHTBIT     32
1032    #define MODRM_RM_16BIT          64
1033    
1034    
1035    /*
1036     *  modrm():
1037     *
1038     *  Yuck. I have a feeling that this function will become really ugly.
1039     */
1040    static int modrm(struct cpu *cpu, int writeflag, int mode, int mode67,
1041            int flags, unsigned char **instrp, uint64_t *lenp,
1042            uint64_t *op1p, uint64_t *op2p)
1043    {
1044            uint32_t imm, imm2;
1045            uint64_t addr = 0;
1046            int mod, r, rm, res = 1, z, q = mode/8, sib, s, i, b, immlen;
1047            char *e, *f;
1048            int disasm = (op1p == NULL);
1049    
1050            /*  e for data, f for addresses  */
1051            e = f = "";
1052    
1053            if (disasm) {
1054                    if (mode == 32)
1055                            e = "e";
1056                    if (mode == 64)
1057                            e = "r";
1058                    if (mode67 == 32)
1059                            f = "e";
1060                    if (mode67 == 64)
1061                            f = "r";
1062                    modrm_rm[0] = modrm_rm[sizeof(modrm_rm)-1] = '\0';
1063                    modrm_r[0] = modrm_r[sizeof(modrm_r)-1] = '\0';
1064            }
1065    
1066            immlen = mode67;
1067            if (immlen == 64)
1068                    immlen = 32;
1069    
1070            imm = read_imm_common(instrp, lenp, 8, disasm);
1071            mod = (imm >> 6) & 3; r = (imm >> 3) & 7; rm = imm & 7;
1072    
1073            if (flags & MODRM_EIGHTBIT)
1074                    q = 1;
1075    
1076            /*
1077             *  R/M:
1078             */
1079    
1080            switch (mod) {
1081            case 0:
1082                    if (disasm) {
1083                            if (mode67 >= 32) {
1084                                    if (rm == 5) {
1085                                            imm2 = read_imm_common(instrp, lenp,
1086                                                immlen, disasm);
1087                                            sprintf(modrm_rm, "[0x%x]", imm2);
1088                                    } else if (rm == 4) {
1089                                            char tmp[20];
1090                                            sib = read_imm_common(instrp, lenp,
1091                                                8, disasm);
1092                                            s = 1 << (sib >> 6);
1093                                            i = (sib >> 3) & 7;
1094                                            b = sib & 7;
1095                                            if (b == 5) {   /*  imm base  */
1096                                                    imm2 = read_imm_common(instrp,
1097                                                        lenp, immlen, disasm);
1098                                                    sprintf(tmp, ofs_string(imm2));
1099                                            } else
1100                                                    sprintf(tmp, "+%s%s", f,
1101                                                        reg_names[b]);
1102                                            if (i == 4)
1103                                                    sprintf(modrm_rm, "[%s]", tmp);
1104                                            else if (s == 1)
1105                                                    sprintf(modrm_rm, "[%s%s%s]",
1106                                                        f, reg_names[i], tmp);
1107                                            else
1108                                                    sprintf(modrm_rm, "[%s%s*%i%s"
1109                                                        "]", f, reg_names[i],
1110                                                        s, tmp);
1111                                    } else {
1112                                            sprintf(modrm_rm, "[%s%s]", f,
1113                                                reg_names[rm]);
1114                                    }
1115                            } else {
1116                                    switch (rm) {
1117                                    case 0: sprintf(modrm_rm, "[bx+si]");
1118                                            break;
1119                                    case 1: sprintf(modrm_rm, "[bx+di]");
1120                                            break;
1121                                    case 2: sprintf(modrm_rm, "[bp+si]");
1122                                            break;
1123                                    case 3: sprintf(modrm_rm, "[bp+di]");
1124                                            break;
1125                                    case 4: sprintf(modrm_rm, "[si]");
1126                                            break;
1127                                    case 5: sprintf(modrm_rm, "[di]");
1128                                            break;
1129                                    case 6: imm2 = read_imm_common(instrp, lenp,
1130                                                immlen, disasm);
1131                                            sprintf(modrm_rm, "[0x%x]", imm2);
1132                                            break;
1133                                    case 7: sprintf(modrm_rm, "[bx]");
1134                                            break;
1135                                    }
1136                            }
1137                    } else {
1138                            if (mode67 >= 32) {
1139                                    if (rm == 5) {
1140                                            addr = read_imm_common(instrp, lenp,
1141                                                immlen, disasm);
1142                                    } else if (rm == 4) {
1143                                            sib = read_imm_common(instrp, lenp,
1144                                                8, disasm);
1145                                            s = 1 << (sib >> 6);
1146                                            i = (sib >> 3) & 7;
1147                                            b = sib & 7;
1148                                            if (b == 4 &&
1149                                                !cpu->cd.x86.seg_override)
1150                                                    cpu->cd.x86.cursegment=X86_S_SS;
1151                                            if (b == 5)
1152                                                    addr = read_imm_common(instrp,
1153                                                        lenp, mode67, disasm);
1154                                            else
1155                                                    addr = cpu->cd.x86.r[b];
1156                                            if (i != 4)
1157                                                    addr += cpu->cd.x86.r[i] * s;
1158                                    } else {
1159                                            addr = cpu->cd.x86.r[rm];
1160                                    }
1161                            } else {
1162                                    switch (rm) {
1163                                    case 0: addr = cpu->cd.x86.r[X86_R_BX] +
1164                                                cpu->cd.x86.r[X86_R_SI]; break;
1165                                    case 1: addr = cpu->cd.x86.r[X86_R_BX] +
1166                                                cpu->cd.x86.r[X86_R_DI]; break;
1167                                    case 2: addr = cpu->cd.x86.r[X86_R_BP] +
1168                                                cpu->cd.x86.r[X86_R_SI];
1169                                            if (!cpu->cd.x86.seg_override)
1170                                                    cpu->cd.x86.cursegment=X86_S_SS;
1171                                            break;
1172                                    case 3: addr = cpu->cd.x86.r[X86_R_BP] +
1173                                                cpu->cd.x86.r[X86_R_DI];
1174                                            if (!cpu->cd.x86.seg_override)
1175                                                    cpu->cd.x86.cursegment=X86_S_SS;
1176                                            break;
1177                                    case 4: addr = cpu->cd.x86.r[X86_R_SI]; break;
1178                                    case 5: addr = cpu->cd.x86.r[X86_R_DI]; break;
1179                                    case 6: addr = read_imm_common(instrp, lenp,
1180                                                immlen, disasm); break;
1181                                    case 7: addr = cpu->cd.x86.r[X86_R_BX]; break;
1182                                    }
1183                            }
1184    
1185                            if (mode67 == 16)
1186                                    addr &= 0xffff;
1187                            if (mode67 == 32)
1188                                    addr &= 0xffffffffULL;
1189    
1190                            switch (writeflag) {
1191                            case MODRM_WRITE_RM:
1192                                    res = x86_store(cpu, addr, *op1p, q);
1193                                    break;
1194                            case MODRM_READ:        /*  read  */
1195                                    if (flags & MODRM_JUST_GET_ADDR)
1196                                            *op1p = addr;
1197                                    else
1198                                            res = x86_load(cpu, addr, op1p, q);
1199                            }
1200                    }
1201                    break;
1202            case 1:
1203            case 2:
1204                    z = (mod == 1)? 8 : immlen;
1205                    if (disasm) {
1206                            if (mode67 >= 32) {
1207                                    if (rm == 4) {
1208                                            sib = read_imm_common(instrp, lenp,
1209                                                8, disasm);
1210                                            s = 1 << (sib >> 6);
1211                                            i = (sib >> 3) & 7;
1212                                            b = sib & 7;
1213                                            imm2 = read_imm_common(instrp, lenp,
1214                                                z, disasm);
1215                                            if (z == 8)  imm2 = (signed char)imm2;
1216                                            if (i == 4)
1217                                                    sprintf(modrm_rm, "[%s%s%s]",
1218                                                        f, reg_names[b],
1219                                                        ofs_string(imm2));
1220                                            else if (s == 1)
1221                                                    sprintf(modrm_rm, "[%s%s%s"
1222                                                        "%s%s]", f, reg_names[i],
1223                                                        f, reg_names[b],
1224                                                        ofs_string(imm2));
1225                                            else
1226                                                    sprintf(modrm_rm, "[%s%s*%i+%s"
1227                                                        "%s%s]", f, reg_names[i], s,
1228                                                        f, reg_names[b],
1229                                                        ofs_string(imm2));
1230                                    } else {
1231                                            imm2 = read_imm_common(instrp, lenp,
1232                                                z, disasm);
1233                                            if (z == 8)  imm2 = (signed char)imm2;
1234                                            sprintf(modrm_rm, "[%s%s%s]", f,
1235                                                reg_names[rm], ofs_string(imm2));
1236                                    }
1237                            } else
1238                            switch (rm) {
1239                            case 0: imm2 = read_imm_common(instrp, lenp, z, disasm);
1240                                    if (z == 8)  imm2 = (signed char)imm2;
1241                                    sprintf(modrm_rm, "[bx+si%s]",ofs_string(imm2));
1242                                    break;
1243                            case 1: imm2 = read_imm_common(instrp, lenp, z, disasm);
1244                                    if (z == 8)  imm2 = (signed char)imm2;
1245                                    sprintf(modrm_rm, "[bx+di%s]",ofs_string(imm2));
1246                                    break;
1247                            case 2: imm2 = read_imm_common(instrp, lenp, z, disasm);
1248                                    if (z == 8)  imm2 = (signed char)imm2;
1249                                    sprintf(modrm_rm, "[bp+si%s]",ofs_string(imm2));
1250                                    break;
1251                            case 3: imm2 = read_imm_common(instrp, lenp, z, disasm);
1252                                    if (z == 8)  imm2 = (signed char)imm2;
1253                                    sprintf(modrm_rm, "[bp+di%s]",ofs_string(imm2));
1254                                    break;
1255                            case 4: imm2 = read_imm_common(instrp, lenp, z, disasm);
1256                                    if (z == 8)  imm2 = (signed char)imm2;
1257                                    sprintf(modrm_rm, "[si%s]", ofs_string(imm2));
1258                                    break;
1259                            case 5: imm2 = read_imm_common(instrp, lenp, z, disasm);
1260                                    if (z == 8)  imm2 = (signed char)imm2;
1261                                    sprintf(modrm_rm, "[di%s]", ofs_string(imm2));
1262                                    break;
1263                            case 6: imm2 = read_imm_common(instrp, lenp, z, disasm);
1264                                    if (z == 8)  imm2 = (signed char)imm2;
1265                                    sprintf(modrm_rm, "[bp%s]", ofs_string(imm2));
1266                                    break;
1267                            case 7: imm2 = read_imm_common(instrp, lenp, z, disasm);
1268                                    if (z == 8)  imm2 = (signed char)imm2;
1269                                    sprintf(modrm_rm, "[bx%s]", ofs_string(imm2));
1270                                    break;
1271                            }
1272                    } else {
1273                            if (mode67 >= 32) {
1274                                    if (rm == 4) {
1275                                            sib = read_imm_common(instrp, lenp,
1276                                                8, disasm);
1277                                            s = 1 << (sib >> 6);
1278                                            i = (sib >> 3) & 7;
1279                                            b = sib & 7;
1280                                            addr = read_imm_common(instrp, lenp,
1281                                                z, disasm);
1282                                            if ((b == 4 || b == 5) &&
1283                                                !cpu->cd.x86.seg_override)
1284                                                    cpu->cd.x86.cursegment=X86_S_SS;
1285                                            if (z == 8)
1286                                                    addr = (signed char)addr;
1287                                            if (i == 4)
1288                                                    addr = cpu->cd.x86.r[b] + addr;
1289                                            else
1290                                                    addr = cpu->cd.x86.r[i] * s +
1291                                                        cpu->cd.x86.r[b] + addr;
1292                                    } else {
1293                                            addr = read_imm_common(instrp, lenp,
1294                                                z, disasm);
1295                                            if (z == 8)
1296                                                    addr = (signed char)addr;
1297                                            addr = cpu->cd.x86.r[rm] + addr;
1298                                    }
1299                            } else {
1300                                    addr = read_imm_common(instrp, lenp, z, disasm);
1301                                    if (z == 8)
1302                                            addr = (signed char)addr;
1303                                    switch (rm) {
1304                                    case 0: addr += cpu->cd.x86.r[X86_R_BX]
1305                                                + cpu->cd.x86.r[X86_R_SI];
1306                                            break;
1307                                    case 1: addr += cpu->cd.x86.r[X86_R_BX]
1308                                                + cpu->cd.x86.r[X86_R_DI];
1309                                            break;
1310                                    case 2: addr += cpu->cd.x86.r[X86_R_BP]
1311                                                + cpu->cd.x86.r[X86_R_SI];
1312                                            if (!cpu->cd.x86.seg_override)
1313                                                    cpu->cd.x86.cursegment=X86_S_SS;
1314                                            break;
1315                                    case 3: addr += cpu->cd.x86.r[X86_R_BP]
1316                                                + cpu->cd.x86.r[X86_R_DI];
1317                                            if (!cpu->cd.x86.seg_override)
1318                                                    cpu->cd.x86.cursegment=X86_S_SS;
1319                                            break;
1320                                    case 4: addr += cpu->cd.x86.r[X86_R_SI];
1321                                            break;
1322                                    case 5: addr += cpu->cd.x86.r[X86_R_DI];
1323                                            break;
1324                                    case 6: addr += cpu->cd.x86.r[X86_R_BP];
1325                                            if (!cpu->cd.x86.seg_override)
1326                                                    cpu->cd.x86.cursegment=X86_S_SS;
1327                                            break;
1328                                    case 7: addr += cpu->cd.x86.r[X86_R_BX];
1329                                            break;
1330                                    }
1331                            }
1332    
1333                            if (mode67 == 16)
1334                                    addr &= 0xffff;
1335                            if (mode67 == 32)
1336                                    addr &= 0xffffffffULL;
1337    
1338                            switch (writeflag) {
1339                            case MODRM_WRITE_RM:
1340                                    res = x86_store(cpu, addr, *op1p, q);
1341                                    break;
1342                            case MODRM_READ:        /*  read  */
1343                                    if (flags & MODRM_JUST_GET_ADDR)
1344                                            *op1p = addr;
1345                                    else
1346                                            res = x86_load(cpu, addr, op1p, q);
1347                            }
1348                    }
1349                    break;
1350            case 3:
1351                    if (flags & MODRM_EIGHTBIT) {
1352                            if (disasm) {
1353                                    strcpy(modrm_rm, reg_names_bytes[rm]);
1354                            } else {
1355                                    switch (writeflag) {
1356                                    case MODRM_WRITE_RM:
1357                                            if (rm < 4)
1358                                                    cpu->cd.x86.r[rm] =
1359                                                        (cpu->cd.x86.r[rm] &
1360                                                        ~0xff) | (*op1p & 0xff);
1361                                            else
1362                                                    cpu->cd.x86.r[rm&3] = (cpu->
1363                                                        cd.x86.r[rm&3] & ~0xff00) |
1364                                                        ((*op1p & 0xff) << 8);
1365                                            break;
1366                                    case MODRM_READ:
1367                                            if (rm < 4)
1368                                                    *op1p = cpu->cd.x86.r[rm] &
1369                                                        0xff;
1370                                            else
1371                                                    *op1p = (cpu->cd.x86.r[rm&3] &
1372                                                         0xff00) >> 8;
1373                                    }
1374                            }
1375                    } else {
1376                            if (disasm) {
1377                                    if (mode == 16 || flags & MODRM_RM_16BIT)
1378                                            strcpy(modrm_rm, reg_names[rm]);
1379                                    else
1380                                            sprintf(modrm_rm, "%s%s", e,
1381                                                reg_names[rm]);
1382                            } else {
1383                                    switch (writeflag) {
1384                                    case MODRM_WRITE_RM:
1385                                            if (mode == 16 ||
1386                                                flags & MODRM_RM_16BIT)
1387                                                    cpu->cd.x86.r[rm] = (
1388                                                        cpu->cd.x86.r[rm] & ~0xffff)
1389                                                        | (*op1p & 0xffff);
1390                                            else
1391                                                    cpu->cd.x86.r[rm] =
1392                                                        modify(cpu->cd.x86.r[rm],
1393                                                        *op1p);
1394                                            break;
1395                                    case MODRM_READ:        /*  read  */
1396                                            if (mode == 16 ||
1397                                                flags & MODRM_RM_16BIT)
1398                                                    *op1p = cpu->cd.x86.r[rm]
1399                                                        & 0xffff;
1400                                            else
1401                                                    *op1p = cpu->cd.x86.r[rm];
1402                                    }
1403                            }
1404                    }
1405                    break;
1406            default:
1407                    fatal("modrm(): unimplemented mod %i\n", mod);
1408                    exit(1);
1409            }
1410    
1411    
1412            /*
1413             *  R:
1414             */
1415    
1416            if (flags & MODRM_EIGHTBIT && !(flags & MODRM_R_NONEIGHTBIT)) {
1417                    if (disasm) {
1418                            strcpy(modrm_r, reg_names_bytes[r]);
1419                    } else {
1420                            switch (writeflag) {
1421                            case MODRM_WRITE_R:
1422                                    if (r < 4)
1423                                            cpu->cd.x86.r[r] = (cpu->cd.x86.r[r] &
1424                                                ~0xff) | (*op2p & 0xff);
1425                                    else
1426                                            cpu->cd.x86.r[r&3] = (cpu->cd.x86.r[r&3]
1427                                                & ~0xff00) | ((*op2p & 0xff) << 8);
1428                                    break;
1429                            case MODRM_READ:
1430                                    if (r < 4)
1431                                            *op2p = cpu->cd.x86.r[r] & 0xff;
1432                                    else
1433                                            *op2p = (cpu->cd.x86.r[r&3] &
1434                                                0xff00) >>8;
1435                            }
1436                    }
1437            } else {
1438                    if (disasm) {
1439                            if (flags & MODRM_SEG)
1440                                    strcpy(modrm_r, seg_names[r]);
1441                            else if (flags & MODRM_CR)
1442                                    sprintf(modrm_r, "cr%i", r);
1443                            else if (flags & MODRM_DR)
1444                                    sprintf(modrm_r, "dr%i", r);
1445                            else {
1446                                    if (mode >= 32)
1447                                            sprintf(modrm_r, "%s%s", e,
1448                                                reg_names[r]);
1449                                    else
1450                                            strcpy(modrm_r, reg_names[r]);
1451                            }
1452                    } else {
1453                            switch (writeflag) {
1454                            case MODRM_WRITE_R:
1455                                    if (flags & MODRM_SEG)
1456                                            cpu->cd.x86.s[r] = *op2p;
1457                                    else if (flags & MODRM_CR)
1458                                            x86_write_cr(cpu, r, *op2p);
1459                                    else if (flags & MODRM_DR)
1460                                            cpu->cd.x86.dr[r] = *op2p;
1461                                    else
1462                                            cpu->cd.x86.r[r] =
1463                                                modify(cpu->cd.x86.r[r], *op2p);
1464                                    break;
1465                            case MODRM_READ:
1466                                    if (flags & MODRM_SEG)
1467                                            *op2p = cpu->cd.x86.s[r];
1468                                    else if (flags & MODRM_CR)
1469                                            *op2p = cpu->cd.x86.cr[r];
1470                                    else if (flags & MODRM_DR)
1471                                            *op2p = cpu->cd.x86.dr[r];
1472                                    else
1473                                            *op2p = cpu->cd.x86.r[r];
1474                            }
1475                    }
1476            }
1477    
1478            if (!disasm) {
1479                    switch (mode) {
1480                    case 16:*op1p &= 0xffff; *op2p &= 0xffff; break;
1481                    case 32:*op1p &= 0xffffffffULL; *op2p &= 0xffffffffULL; break;
1482                    }
1483            }
1484    
1485            return res;
1486  }  }
1487    
1488    
# Line 381  fatal("read_modrm(): TODO\n"); Line 1492  fatal("read_modrm(): TODO\n");
1492   *  Convert an instruction word into human readable format, for instruction   *  Convert an instruction word into human readable format, for instruction
1493   *  tracing.   *  tracing.
1494   *   *
1495   *  If running is 1, cpu->pc should be the address of the instruction.   *  If running&1 is 1, cpu->pc should be the address of the instruction.
1496   *   *
1497   *  If running is 0, things that depend on the runtime environment (eg.   *  If running&1 is 0, things that depend on the runtime environment (eg.
1498   *  register contents) will not be shown, and addr will be used instead of   *  register contents) will not be shown, and addr will be used instead of
1499   *  cpu->pc for relative addresses.   *  cpu->pc for relative addresses.
1500     *
1501     *  The rest of running tells us the default (code) operand size.
1502   */   */
1503  int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,  int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
1504          int running, uint64_t dumpaddr, int bintrans)          int running, uint64_t dumpaddr, int bintrans)
1505  {  {
1506          int ilen = 0, op, rep = 0, n_prefix_bytes = 0;          int op, rep = 0, lock = 0, n_prefix_bytes = 0;
1507          uint64_t offset;          uint64_t ilen = 0, offset;
1508          uint32_t imm=0, imm2, mode = cpu->cd.x86.mode;          uint32_t imm=0, imm2;
1509          char *symbol, *tmp = "ERROR", *mnem = "ERROR", *e = "e",          int mode = running & ~1;
1510              *prefix = NULL;          int mode67;
1511            char *symbol, *mnem = "ERROR", *e = "e", *prefix = NULL;
1512    
1513          if (running)          if (running)
1514                  dumpaddr = cpu->pc;                  dumpaddr = cpu->pc;
1515    
1516            if (mode == 0) {
1517                    mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
1518                    if (mode == 0) {
1519                            fatal("x86_cpu_disassemble_instr(): no mode: TODO\n");
1520                            return 1;
1521                    }
1522            }
1523    
1524            mode67 = mode;
1525    
1526          symbol = get_symbol_name(&cpu->machine->symbol_context,          symbol = get_symbol_name(&cpu->machine->symbol_context,
1527              dumpaddr, &offset);              dumpaddr, &offset);
1528          if (symbol != NULL && offset==0)          if (symbol != NULL && offset==0)
# Line 412  int x86_cpu_disassemble_instr(struct cpu Line 1536  int x86_cpu_disassemble_instr(struct cpu
1536          else if (mode == 64)          else if (mode == 64)
1537                  debug("%016llx:  ", (long long)dumpaddr);                  debug("%016llx:  ", (long long)dumpaddr);
1538          else { /*  16-bit mode  */          else { /*  16-bit mode  */
1539                  if (running)                  debug("%04x:%04x  ", cpu->cd.x86.s[X86_S_CS],
1540                          debug("%04x:%04x  ", cpu->cd.x86.s[X86_S_CS],                      (int)dumpaddr & 0xffff);
                             (int)dumpaddr);  
                 else  
                         debug("%08x:  ", (int)dumpaddr);  
1541          }          }
1542    
1543          /*          /*
# Line 430  int x86_cpu_disassemble_instr(struct cpu Line 1551  int x86_cpu_disassemble_instr(struct cpu
1551          /*  Any prefix?  */          /*  Any prefix?  */
1552          for (;;) {          for (;;) {
1553                  if (instr[0] == 0x66) {                  if (instr[0] == 0x66) {
1554                          if (mode == 32)                          if (mode == 16)
1555                                    mode = 32;
1556                            else
1557                                  mode = 16;                                  mode = 16;
1558                    } else if (instr[0] == 0x67) {
1559                            if (mode67 == 16)
1560                                    mode67 = 32;
1561                          else                          else
1562                                  mode = 32;                                  mode67 = 16;
1563                    } else if (instr[0] == 0xf2) {
1564                            rep = REP_REPNE;
1565                  } else if (instr[0] == 0xf3) {                  } else if (instr[0] == 0xf3) {
1566                          rep = 1;                          rep = REP_REP;
1567                    } else if (instr[0] == 0x26) {
1568                            prefix = "es:";
1569                    } else if (instr[0] == 0x2e) {
1570                            prefix = "cs:";
1571                    } else if (instr[0] == 0x36) {
1572                            prefix = "ss:";
1573                    } else if (instr[0] == 0x3e) {
1574                            prefix = "ds:";
1575                    } else if (instr[0] == 0x64) {
1576                            prefix = "fs:";
1577                    } else if (instr[0] == 0x65) {
1578                            prefix = "gs:";
1579                    } else if (instr[0] == 0xf0) {
1580                            lock = 1;
1581                  } else                  } else
1582                          break;                          break;
1583    
# Line 473  int x86_cpu_disassemble_instr(struct cpu Line 1615  int x86_cpu_disassemble_instr(struct cpu
1615                  case 5: imm = read_imm_and_print(&instr, &ilen, mode);                  case 5: imm = read_imm_and_print(&instr, &ilen, mode);
1616                          SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);                          SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
1617                          break;                          break;
1618                  default:                  default:modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
1619                          read_modrm(mode, &instr, &ilen);                              MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
1620                          SPACES; debug("%s\t%s,%s", mnem, modrm_dst, modrm_src);                          SPACES; debug("%s\t", mnem);
1621                            if (op & 2)
1622                                    debug("%s,%s", modrm_r, modrm_rm);
1623                            else
1624                                    debug("%s,%s", modrm_rm, modrm_r);
1625                  }                  }
1626          } else if (op == 0xf) {          } else if (op == 0xf) {
1627                  /*  "pop cs" on 8086  */                  /*  "pop cs" on 8086  */
1628                  if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {                  if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
1629                          SPACES; debug("pop\tcs");                          SPACES; debug("pop\tcs");
1630                  } else {                  } else {
1631                          SPACES; debug("UNIMPLEMENTED 0x0f");                          imm = read_imm_and_print(&instr, &ilen, 8);
1632                            if (imm == 0x00) {
1633                                    int subop = (*instr >> 3) & 0x7;
1634                                    switch (subop) {
1635                                    case 0: modrm(cpu, MODRM_READ, mode, mode67,
1636                                                0, &instr, &ilen, NULL, NULL);
1637                                            SPACES; debug("sldt\t%s", modrm_rm);
1638                                            break;
1639                                    case 1: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1640                                                mode67, 0, &instr, &ilen,
1641                                                NULL, NULL);
1642                                            SPACES; debug("str\t%s", modrm_rm);
1643                                            break;
1644                                    case 2: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1645                                                mode67, 0, &instr, &ilen,
1646                                                NULL, NULL);
1647                                            SPACES; debug("lldt\t%s", modrm_rm);
1648                                            break;
1649                                    case 3: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1650                                                mode67, 0, &instr, &ilen,
1651                                                NULL, NULL);
1652                                            SPACES; debug("ltr\t%s", modrm_rm);
1653                                            break;
1654                                    case 4: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1655                                                mode67, 0, &instr, &ilen,
1656                                                NULL, NULL);
1657                                            SPACES; debug("verr\t%s", modrm_rm);
1658                                            break;
1659                                    case 5: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1660                                                mode67, 0, &instr, &ilen,
1661                                                NULL, NULL);
1662                                            SPACES; debug("verw\t%s", modrm_rm);
1663                                            break;
1664                                    default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1665                                                "%02x,0x%02x", op, imm, *instr);
1666                                    }
1667                            } else if (imm == 0x01) {
1668                                    int subop = (*instr >> 3) & 0x7;
1669                                    switch (subop) {
1670                                    case 0:
1671                                    case 1:
1672                                    case 2:
1673                                    case 3: modrm(cpu, MODRM_READ, mode, mode67,
1674                                                0, &instr, &ilen, NULL, NULL);
1675                                            SPACES; debug("%s%s\t%s",
1676                                                subop < 2? "s" : "l",
1677                                                subop&1? "idt" : "gdt", modrm_rm);
1678                                            break;
1679                                    case 4:
1680                                    case 6: if (((*instr >> 3) & 0x7) == 4)
1681                                                    mnem = "smsw";
1682                                            else
1683                                                    mnem = "lmsw";
1684                                            modrm(cpu, MODRM_READ, 16, mode67,
1685                                                0, &instr, &ilen, NULL, NULL);
1686                                            SPACES; debug("%s\t%s", mnem, modrm_rm);
1687                                            break;
1688                                    case 7: modrm(cpu, MODRM_READ, mode,
1689                                                mode67, 0, &instr, &ilen,
1690                                                NULL, NULL);
1691                                            SPACES; debug("invlpg\t%s", modrm_rm);
1692                                            break;
1693                                    default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1694                                                "%02x,0x%02x", op, imm, *instr);
1695                                    }
1696                            } else if (imm == 0x02) {
1697                                    modrm(cpu, MODRM_READ, mode, mode67,
1698                                        0, &instr, &ilen, NULL, NULL);
1699                                    SPACES; debug("lar\t%s,%s", modrm_r, modrm_rm);
1700                            } else if (imm == 0x03) {
1701                                    modrm(cpu, MODRM_READ, mode, mode67,
1702                                        0, &instr, &ilen, NULL, NULL);
1703                                    SPACES; debug("lsl\t%s,%s", modrm_r, modrm_rm);
1704                            } else if (imm == 0x05) {
1705                                    SPACES;         /* TODO: exactly which models?*/
1706                                    if (cpu->cd.x86.model.model_number >
1707                                        X86_MODEL_80486)
1708                                            debug("syscall");
1709                                    else
1710                                            debug("loadall286");
1711                            } else if (imm == 0x06) {
1712                                    SPACES; debug("clts");
1713                            } else if (imm == 0x07) {
1714                                    SPACES;         /* TODO: exactly which models?*/
1715                                    if (cpu->cd.x86.model.model_number >
1716                                        X86_MODEL_80486)
1717                                            debug("sysret");
1718                                    else
1719                                            debug("loadall");
1720                            } else if (imm == 0x08) {
1721                                    SPACES; debug("invd");
1722                            } else if (imm == 0x09) {
1723                                    SPACES; debug("wbinvd");
1724                            } else if (imm == 0x0b) {
1725                                    SPACES; debug("reserved_0b");
1726                            } else if (imm == 0x20 || imm == 0x21) {
1727                                    modrm(cpu, MODRM_READ, 32 /* note: 32  */,
1728                                        mode67, imm == 0x20? MODRM_CR : MODRM_DR,
1729                                        &instr, &ilen, NULL, NULL);
1730                                    SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1731                            } else if (imm == 0x22 || imm == 0x23) {
1732                                    modrm(cpu, MODRM_READ, 32 /* note: 32  */,
1733                                        mode67, imm == 0x22? MODRM_CR : MODRM_DR,
1734                                        &instr, &ilen, NULL, NULL);
1735                                    SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1736                            } else if (imm == 0x30) {
1737                                    SPACES; debug("wrmsr");
1738                            } else if (imm == 0x31) {
1739                                    SPACES; debug("rdtsc");
1740                            } else if (imm == 0x32) {
1741                                    SPACES; debug("rdmsr");
1742                            } else if (imm == 0x33) {
1743                                    SPACES; debug("rdpmc");         /*  http://www
1744                                        .x86.org/secrets/opcodes/rdpmc.htm  */
1745                            } else if (imm == 0x34) {
1746                                    SPACES; debug("sysenter");
1747                            } else if (imm == 0x36) {
1748                                    SPACES; debug("sysexit");
1749                            } else if (imm >= 0x40 && imm <= 0x4f) {
1750                                    modrm(cpu, MODRM_READ, mode, mode67, 0,
1751                                        &instr, &ilen, NULL, NULL);
1752                                    op = imm & 0xf;
1753                                    SPACES; debug("cmov%s%s\t%s,%s", op&1? "n"
1754                                        : "", cond_names[(op/2) & 0x7],
1755                                        modrm_r, modrm_rm);
1756                            } else if (imm >= 0x80 && imm <= 0x8f) {
1757                                    op = imm & 0xf;
1758                                    imm = read_imm_and_print(&instr, &ilen, mode);
1759                                    imm = dumpaddr + 2 + mode/8 + imm;
1760                                    SPACES; debug("j%s%s\tnear 0x%x", op&1? "n"
1761                                        : "", cond_names[(op/2) & 0x7], imm);
1762                            } else if (imm >= 0x90 && imm <= 0x9f) {
1763                                    op = imm;
1764                                    modrm(cpu, MODRM_READ, mode,
1765                                        mode67, MODRM_EIGHTBIT, &instr, &ilen,
1766                                        NULL, NULL);
1767                                    SPACES; debug("set%s%s\t%s", op&1? "n"
1768                                        : "", cond_names[(op/2) & 0x7], modrm_rm);
1769                            } else if (imm == 0xa0) {
1770                                    SPACES; debug("push\tfs");
1771                            } else if (imm == 0xa1) {
1772                                    SPACES; debug("pop\tfs");
1773                            } else if (imm == 0xa2) {
1774                                    SPACES; debug("cpuid");
1775                            } else if (imm == 0xa3 || imm == 0xab
1776                                || imm == 0xb3 || imm == 0xbb) {
1777                                    modrm(cpu, MODRM_READ, mode, mode67,
1778                                        0, &instr, &ilen, NULL, NULL);
1779                                    switch (imm) {
1780                                    case 0xa3: mnem = "bt"; break;
1781                                    case 0xab: mnem = "bts"; break;
1782                                    case 0xb3: mnem = "btr"; break;
1783                                    case 0xbb: mnem = "btc"; break;
1784                                    }
1785                                    SPACES; debug("%s\t%s,%s",
1786                                        mnem, modrm_rm, modrm_r);
1787                            } else if (imm == 0xa4 || imm == 0xa5 ||
1788                                imm == 0xac || imm == 0xad) {
1789                                    modrm(cpu, MODRM_READ, mode, mode67,
1790                                        0, &instr, &ilen, NULL, NULL);
1791                                    if (!(imm & 1))
1792                                            imm2 = read_imm_and_print(&instr,
1793                                                &ilen, 8);
1794                                    else
1795                                            imm2 = 0;
1796                                    SPACES; debug("sh%sd\t%s,%s,",
1797                                        imm <= 0xa5? "l" : "r",
1798                                        modrm_rm, modrm_r);
1799                                    if (imm & 1)
1800                                            debug("cl");
1801                                    else
1802                                            debug("%i", imm2);
1803                            } else if (imm == 0xa8) {
1804                                    SPACES; debug("push\tgs");
1805                            } else if (imm == 0xa9) {
1806                                    SPACES; debug("pop\tgs");
1807                            } else if (imm == 0xaa) {
1808                                    SPACES; debug("rsm");
1809                            } else if (imm == 0xaf) {
1810                                    modrm(cpu, MODRM_READ, mode, mode67,
1811                                        0, &instr, &ilen, NULL, NULL);
1812                                    SPACES; debug("imul\t%s,%s", modrm_r, modrm_rm);
1813                            } else if (imm == 0xb0 || imm == 0xb1) {
1814                                    modrm(cpu, MODRM_READ, mode, mode67,
1815                                        imm == 0xb0? MODRM_EIGHTBIT : 0,
1816                                        &instr, &ilen, NULL, NULL);
1817                                    SPACES; debug("cmpxchg\t%s,%s",
1818                                        modrm_rm, modrm_r);
1819                            } else if (imm == 0xb2 || imm == 0xb4 || imm == 0xb5) {
1820                                    modrm(cpu, MODRM_READ, mode, mode67, 0,
1821                                        &instr, &ilen, NULL, NULL);
1822                                    switch (imm) {
1823                                    case 0xb2: mnem = "lss"; break;
1824                                    case 0xb4: mnem = "lfs"; break;
1825                                    case 0xb5: mnem = "lgs"; break;
1826                                    }
1827                                    SPACES; debug("%s\t%s,%s", mnem,
1828                                        modrm_r, modrm_rm);
1829                            } else if (imm == 0xb6 || imm == 0xb7 ||
1830                                imm == 0xbe || imm == 0xbf) {
1831                                    modrm(cpu, MODRM_READ, mode, mode67,
1832                                        (imm&1)==0? (MODRM_EIGHTBIT |
1833                                        MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
1834                                        &instr, &ilen, NULL, NULL);
1835                                    mnem = "movsx";
1836                                    if (imm <= 0xb7)
1837                                            mnem = "movzx";
1838                                    SPACES; debug("%s\t%s,%s", mnem,
1839                                        modrm_r, modrm_rm);
1840                            } else if (imm == 0xba) {
1841                                    int subop = (*instr >> 3) & 0x7;
1842                                    switch (subop) {
1843                                    case 4: modrm(cpu, MODRM_READ, mode, mode67,
1844                                                0, &instr, &ilen, NULL, NULL);
1845                                            imm2 = read_imm_and_print(&instr,
1846                                                &ilen, 8);
1847                                            SPACES; debug("bt\t%s,%i",
1848                                                modrm_rm, imm2);
1849                                            break;
1850                                    case 5: modrm(cpu, MODRM_READ, mode, mode67,
1851                                                0, &instr, &ilen, NULL, NULL);
1852                                            imm2 = read_imm_and_print(&instr,
1853                                                &ilen, 8);
1854                                            SPACES; debug("bts\t%s,%i",
1855                                                modrm_rm, imm2);
1856                                            break;
1857                                    case 6: modrm(cpu, MODRM_READ, mode, mode67,
1858                                                0, &instr, &ilen, NULL, NULL);
1859                                            imm2 = read_imm_and_print(&instr,
1860                                                &ilen, 8);
1861                                            SPACES; debug("btr\t%s,%i",
1862                                                modrm_rm, imm2);
1863                                            break;
1864                                    case 7: modrm(cpu, MODRM_READ, mode, mode67,
1865                                                0, &instr, &ilen, NULL, NULL);
1866                                            imm2 = read_imm_and_print(&instr,
1867                                                &ilen, 8);
1868                                            SPACES; debug("btc\t%s,%i",
1869                                                modrm_rm, imm2);
1870                                            break;
1871                                    default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1872                                                "%02x,0x%02x", op, imm, *instr);
1873                                    }
1874                            } else if (imm == 0xbc || imm == 0xbd) {
1875                                    modrm(cpu, MODRM_READ, mode, mode67,
1876                                        0, &instr, &ilen, NULL, NULL);
1877                                    if (imm == 0xbc)
1878                                            mnem = "bsf";
1879                                    else
1880                                            mnem = "bsr";
1881                                    SPACES; debug("%s\t%s,%s", mnem, modrm_r,
1882                                        modrm_rm);
1883                            } else if (imm == 0xc0 || imm == 0xc1) {
1884                                    modrm(cpu, MODRM_READ, mode, mode67,
1885                                        imm&1? 0 : MODRM_EIGHTBIT,
1886                                        &instr, &ilen, NULL, NULL);
1887                                    SPACES; debug("xadd\t%s,%s", modrm_rm, modrm_r);
1888                            } else if (imm == 0xc7) {
1889                                    int subop = (*instr >> 3) & 0x7;
1890                                    switch (subop) {
1891                                    case 1: modrm(cpu, MODRM_READ, 64, mode67,
1892                                                0, &instr, &ilen, NULL, NULL);
1893                                            SPACES; debug("cmpxchg8b\t%s",modrm_rm);
1894                                            break;
1895                                    default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1896                                                "%02x,0x%02x", op, imm, *instr);
1897                                    }
1898                            } else if (imm >= 0xc8 && imm <= 0xcf) {
1899                                    SPACES; debug("bswap\te%s", reg_names[imm & 7]);
1900                            } else {
1901                                    SPACES; debug("UNIMPLEMENTED 0x0f,0x%02x", imm);
1902                            }
1903                  }                  }
1904          } else if (op < 0x20 && (op & 7) == 6) {          } else if (op < 0x20 && (op & 7) == 6) {
1905                  SPACES; debug("push\t%s", seg_names[op/8]);                  SPACES; debug("push\t%s", seg_names[op/8]);
# Line 500  int x86_cpu_disassemble_instr(struct cpu Line 1917  int x86_cpu_disassemble_instr(struct cpu
1917                  }                  }
1918                  SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);                  SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
1919          } else if (op == 0x60) {          } else if (op == 0x60) {
1920                  SPACES; debug("pusha");                  SPACES; debug("pusha%s", mode==16? "" : (mode==32? "d" : "q"));
1921          } else if (op == 0x61) {          } else if (op == 0x61) {
1922                  SPACES; debug("popa");                  SPACES; debug("popa%s", mode==16? "" : (mode==32? "d" : "q"));
1923            } else if (op == 0x62) {
1924                    modrm(cpu, MODRM_READ, mode, mode67,
1925                        0, &instr, &ilen, NULL, NULL);
1926                    SPACES; debug("bound\t%s,%s", modrm_r, modrm_rm);
1927            } else if (op == 0x63) {
1928                    modrm(cpu, MODRM_READ, 16, mode67,
1929                        0, &instr, &ilen, NULL, NULL);
1930                    SPACES; debug("arpl\t%s,%s", modrm_rm, modrm_r);
1931            } else if (op == 0x68) {
1932                    imm = read_imm_and_print(&instr, &ilen, mode);
1933                    SPACES; debug("push\t%sword 0x%x", mode==32?"d":"", imm);
1934            } else if (op == 0x69 || op == 0x6b) {
1935                    modrm(cpu, MODRM_READ, mode, mode67,
1936                        0, &instr, &ilen, NULL, NULL);
1937                    if (op == 0x69)
1938                            imm = read_imm_and_print(&instr, &ilen, mode);
1939                    else
1940                            imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1941                    SPACES; debug("imul\t%s,%s,%i", modrm_r, modrm_rm, imm);
1942            } else if (op == 0x6a) {
1943                    imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1944                    SPACES; debug("push\tbyte 0x%x", imm);
1945            } else if (op == 0x6c) {
1946                    SPACES; debug("insb");
1947            } else if (op == 0x6d) {
1948                    SPACES; debug("ins%s", mode==16? "w" : (mode==32? "d" : "q"));
1949            } else if (op == 0x6e) {
1950                    SPACES; debug("outsb");
1951            } else if (op == 0x6f) {
1952                    SPACES; debug("outs%s", mode==16? "w" : (mode==32? "d" : "q"));
1953          } else if ((op & 0xf0) == 0x70) {          } else if ((op & 0xf0) == 0x70) {
1954                  imm = (signed char)read_imm_and_print(&instr, &ilen, 8);                  imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1955                  imm = dumpaddr + 2 + imm;                  imm = dumpaddr + 2 + imm;
1956                  SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",                  SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
1957                      cond_names[(op/2) & 0x7], imm);                      cond_names[(op/2) & 0x7], imm);
1958            } else if (op == 0x80 || op == 0x81) {
1959                    switch ((*instr >> 3) & 0x7) {
1960                    case 0: mnem = "add"; break;
1961                    case 1: mnem = "or"; break;
1962                    case 2: mnem = "adc"; break;
1963                    case 3: mnem = "sbb"; break;
1964                    case 4: mnem = "and"; break;
1965                    case 5: mnem = "sub"; break;
1966                    case 6: mnem = "xor"; break;
1967                    case 7: mnem = "cmp"; break;
1968                    default:
1969                            SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1970                    }
1971                    modrm(cpu, MODRM_READ, mode, mode67,
1972                        op == 0x80? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1973                    imm = read_imm_and_print(&instr, &ilen, op==0x80? 8 : mode);
1974                    SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1975            } else if (op == 0x83) {
1976                    switch ((*instr >> 3) & 0x7) {
1977                    case 0: mnem = "add"; break;
1978                    case 1: mnem = "or"; break;
1979                    case 2: mnem = "adc"; break;
1980                    case 3: mnem = "sbb"; break;
1981                    case 4: mnem = "and"; break;
1982                    case 5: mnem = "sub"; break;
1983                    case 6: mnem = "xor"; break;
1984                    case 7: mnem = "cmp"; break;
1985                    default:
1986                            SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1987                    }
1988                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
1989                        NULL, NULL);
1990                    imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1991                    SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1992            } else if (op == 0x84 || op == 0x85) {
1993                    modrm(cpu, MODRM_READ, mode, mode67,
1994                        op == 0x84? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1995                    SPACES; debug("test\t%s,%s", modrm_rm, modrm_r);
1996            } else if (op == 0x86 || op == 0x87) {
1997                    modrm(cpu, MODRM_READ, mode, mode67, op == 0x86?
1998                        MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1999                    SPACES; debug("xchg\t%s,%s", modrm_rm, modrm_r);
2000            } else if (op == 0x88 || op == 0x89) {
2001                    modrm(cpu, MODRM_READ, mode, mode67, op == 0x88?
2002                        MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2003                    SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
2004            } else if (op == 0x8a || op == 0x8b) {
2005                    modrm(cpu, MODRM_READ, mode, mode67, op == 0x8a?
2006                        MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2007                    SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
2008            } else if (op == 0x8c || op == 0x8e) {
2009                    modrm(cpu, MODRM_READ, mode, mode67, MODRM_SEG, &instr, &ilen,
2010                        NULL, NULL);
2011                    SPACES; debug("mov\t");
2012                    if (op == 0x8c)
2013                            debug("%s,%s", modrm_rm, modrm_r);
2014                    else
2015                            debug("%s,%s", modrm_r, modrm_rm);
2016            } else if (op == 0x8d) {
2017                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2018                        NULL, NULL);
2019                    SPACES; debug("lea\t%s,%s", modrm_r, modrm_rm);
2020            } else if (op == 0x8f) {
2021                    switch ((*instr >> 3) & 0x7) {
2022                    case 0: /*  POP m16/m32  */
2023                            modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2024                                &ilen, NULL, NULL);
2025                            SPACES; debug("pop\t%sword %s", mode == 32? "d" : "",
2026                                modrm_rm);
2027                            break;
2028                    default:
2029                            SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2030                    }
2031          } else if (op == 0x90) {          } else if (op == 0x90) {
2032                  SPACES; debug("nop");                  SPACES; debug("nop");
2033          } else if (op >= 0x91 && op <= 0x97) {          } else if (op >= 0x91 && op <= 0x97) {
# Line 516  int x86_cpu_disassemble_instr(struct cpu Line 2036  int x86_cpu_disassemble_instr(struct cpu
2036                  SPACES; debug("cbw");                  SPACES; debug("cbw");
2037          } else if (op == 0x99) {          } else if (op == 0x99) {
2038                  SPACES; debug("cwd");                  SPACES; debug("cwd");
2039            } else if (op == 0x9a) {
2040                    imm = read_imm_and_print(&instr, &ilen, mode);
2041                    imm2 = read_imm_and_print(&instr, &ilen, 16);
2042                    SPACES; debug("call\t0x%04x:", imm2);
2043                    if (mode == 16)
2044                            debug("0x%04x", imm);
2045                    else
2046                            debug("0x%08x", imm);
2047          } else if (op == 0x9b) {          } else if (op == 0x9b) {
2048                  SPACES; debug("wait");                  SPACES; debug("wait");
2049          } else if (op == 0x9c) {          } else if (op == 0x9c) {
2050                  SPACES; debug("pushf");                  SPACES; debug("pushf%s", mode==16? "" : (mode==32? "d" : "q"));
2051          } else if (op == 0x9d) {          } else if (op == 0x9d) {
2052                  SPACES; debug("popf");                  SPACES; debug("popf%s", mode==16? "" : (mode==32? "d" : "q"));
2053          } else if (op == 0x9e) {          } else if (op == 0x9e) {
2054                  SPACES; debug("sahf");                  SPACES; debug("sahf");
2055          } else if (op == 0x9f) {          } else if (op == 0x9f) {
2056                  SPACES; debug("lahf");                  SPACES; debug("lahf");
2057            } else if (op == 0xa0) {
2058                    imm = read_imm_and_print(&instr, &ilen, mode67);
2059                    SPACES; debug("mov\tal,[0x%x]", imm);
2060            } else if (op == 0xa1) {
2061                    imm = read_imm_and_print(&instr, &ilen, mode67);
2062                    SPACES; debug("mov\t%sax,[0x%x]", e, imm);
2063            } else if (op == 0xa2) {
2064                    imm = read_imm_and_print(&instr, &ilen, mode67);
2065                    SPACES; debug("mov\t[0x%x],al", imm);
2066            } else if (op == 0xa3) {
2067                    imm = read_imm_and_print(&instr, &ilen, mode67);
2068                    SPACES; debug("mov\t[0x%x],%sax", imm, e);
2069            } else if (op == 0xa4) {
2070                    SPACES; debug("movsb");
2071            } else if (op == 0xa5) {
2072                    SPACES; debug("movs%s", mode==16? "w" : (mode==32? "d" : "q"));
2073            } else if (op == 0xa6) {
2074                    SPACES; debug("cmpsb");
2075            } else if (op == 0xa7) {
2076                    SPACES; debug("cmps%s", mode==16? "w" : (mode==32? "d" : "q"));
2077            } else if (op == 0xa8 || op == 0xa9) {
2078                    imm = read_imm_and_print(&instr, &ilen, op == 0xa8? 8 : mode);
2079                    if (op == 0xa8)
2080                            mnem = "al";
2081                    else if (mode == 16)
2082                            mnem = "ax";
2083                    else
2084                            mnem = "eax";
2085                    SPACES; debug("test\t%s,0x%x", mnem, imm);
2086            } else if (op == 0xaa) {
2087                    SPACES; debug("stosb");
2088            } else if (op == 0xab) {
2089                    SPACES; debug("stos%s", mode==16? "w" : (mode==32? "d" : "q"));
2090            } else if (op == 0xac) {
2091                    SPACES; debug("lodsb");
2092            } else if (op == 0xad) {
2093                    SPACES; debug("lods%s", mode==16? "w" : (mode==32? "d" : "q"));
2094            } else if (op == 0xae) {
2095                    SPACES; debug("scasb");
2096            } else if (op == 0xaf) {
2097                    SPACES; debug("scas%s", mode==16? "w" : (mode==32? "d" : "q"));
2098          } else if (op >= 0xb0 && op <= 0xb7) {          } else if (op >= 0xb0 && op <= 0xb7) {
2099                  imm = read_imm_and_print(&instr, &ilen, 8);                  imm = read_imm_and_print(&instr, &ilen, 8);
2100                  switch (op & 7) {                  SPACES; debug("mov\t%s,0x%x", reg_names_bytes[op&7], imm);
                 case 0: tmp = "al"; break;  
                 case 1: tmp = "cl"; break;  
                 case 2: tmp = "dl"; break;  
                 case 3: tmp = "bl"; break;  
                 case 4: tmp = "ah"; break;  
                 case 5: tmp = "ch"; break;  
                 case 6: tmp = "dh"; break;  
                 case 7: tmp = "bh"; break;  
                 }  
                 SPACES; debug("mov\t%s,0x%x", tmp, imm);  
2101          } else if (op >= 0xb8 && op <= 0xbf) {          } else if (op >= 0xb8 && op <= 0xbf) {
2102                  imm = read_imm_and_print(&instr, &ilen, mode);                  imm = read_imm_and_print(&instr, &ilen, mode);
2103                  SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);                  SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
2104            } else if (op == 0xc0 || op == 0xc1) {
2105                    switch ((*instr >> 3) & 0x7) {
2106                    case 0: mnem = "rol"; break;
2107                    case 1: mnem = "ror"; break;
2108                    case 2: mnem = "rcl"; break;
2109                    case 3: mnem = "rcr"; break;
2110                    case 4: mnem = "shl"; break;
2111                    case 5: mnem = "shr"; break;
2112                    case 6: mnem = "sal"; break;
2113                    case 7: mnem = "sar"; break;
2114                    }
2115                    modrm(cpu, MODRM_READ, mode, mode67, op == 0xc0?
2116                        MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2117                    imm = read_imm_and_print(&instr, &ilen, 8);
2118                    SPACES; debug("%s\t%s,%i", mnem, modrm_rm, imm);
2119            } else if (op == 0xc2) {
2120                    imm = read_imm_and_print(&instr, &ilen, 16);
2121                    SPACES; debug("ret\t0x%x", imm);
2122            } else if (op == 0xc3) {
2123                    SPACES; debug("ret");
2124            } else if (op == 0xc4 || op == 0xc5) {
2125                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2126                        NULL, NULL);
2127                    switch (op) {
2128                    case 0xc4: mnem = "les"; break;
2129                    case 0xc5: mnem = "lds"; break;
2130                    }
2131                    SPACES; debug("%s\t%s,%s", mnem, modrm_r, modrm_rm);
2132            } else if (op == 0xc6 || op == 0xc7) {
2133                    switch ((*instr >> 3) & 0x7) {
2134                    case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xc6?
2135                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2136                            imm = read_imm_and_print(&instr, &ilen,
2137                                op == 0xc6? 8 : mode);
2138                            SPACES; debug("mov\t%s,0x%x", modrm_rm, imm);
2139                            break;
2140                    default:
2141                            SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2142                    }
2143            } else if (op == 0xc8) {
2144                    imm = read_imm_and_print(&instr, &ilen, 16);
2145                    imm2 = read_imm_and_print(&instr, &ilen, 8);
2146                    SPACES; debug("enter\t0x%x,%i", imm, imm2);
2147          } else if (op == 0xc9) {          } else if (op == 0xc9) {
2148                  SPACES; debug("leave");                  SPACES; debug("leave");
2149            } else if (op == 0xca) {
2150                    imm = read_imm_and_print(&instr, &ilen, 16);
2151                    SPACES; debug("retf\t0x%x", imm);
2152            } else if (op == 0xcb) {
2153                    SPACES; debug("retf");
2154          } else if (op == 0xcc) {          } else if (op == 0xcc) {
2155                  SPACES; debug("int3");                  SPACES; debug("int3");
2156          } else if (op == 0xcd) {          } else if (op == 0xcd) {
# Line 553  int x86_cpu_disassemble_instr(struct cpu Line 2160  int x86_cpu_disassemble_instr(struct cpu
2160                  SPACES; debug("into");                  SPACES; debug("into");
2161          } else if (op == 0xcf) {          } else if (op == 0xcf) {
2162                  SPACES; debug("iret");                  SPACES; debug("iret");
2163            } else if (op >= 0xd0 && op <= 0xd3) {
2164                    int subop = (*instr >> 3) & 0x7;
2165                    modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
2166                        MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
2167                    switch (subop) {
2168                    case 0: mnem = "rol"; break;
2169                    case 1: mnem = "ror"; break;
2170                    case 2: mnem = "rcl"; break;
2171                    case 3: mnem = "rcr"; break;
2172                    case 4: mnem = "shl"; break;
2173                    case 5: mnem = "shr"; break;
2174                    case 6: mnem = "sal"; break;
2175                    case 7: mnem = "sar"; break;
2176                    }
2177                    SPACES; debug("%s\t%s,", mnem, modrm_rm);
2178                    if (op <= 0xd1)
2179                            debug("1");
2180                    else
2181                            debug("cl");
2182          } else if (op == 0xd4) {          } else if (op == 0xd4) {
2183                    imm = read_imm_and_print(&instr, &ilen, 8);
2184                  SPACES; debug("aam");                  SPACES; debug("aam");
2185                    if (imm != 10)
2186                            debug("\t%i", imm);
2187          } else if (op == 0xd5) {          } else if (op == 0xd5) {
2188                    imm = read_imm_and_print(&instr, &ilen, 8);
2189                  SPACES; debug("aad");                  SPACES; debug("aad");
2190                    if (imm != 10)
2191                            debug("\t%i", imm);
2192            } else if (op == 0xd6) {
2193                    SPACES; debug("salc");          /*  undocumented?  */
2194          } else if (op == 0xd7) {          } else if (op == 0xd7) {
2195                  SPACES; debug("xlat");                  SPACES; debug("xlat");
2196            } else if (op == 0xd9) {
2197                    int subop = (*instr >> 3) & 7;
2198                    imm = *instr;
2199                    if (subop == 5) {
2200                            modrm(cpu, MODRM_READ, 16, mode67, 0,
2201                                &instr, &ilen, NULL, NULL);
2202                            SPACES; debug("fldcw\t%s", modrm_rm);
2203                    } else if (subop == 7) {
2204                            modrm(cpu, MODRM_READ, 16, mode67, 0,
2205                                &instr, &ilen, NULL, NULL);
2206                            SPACES; debug("fstcw\t%s", modrm_rm);
2207                    } else {
2208                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2209                    }
2210            } else if (op == 0xdb) {
2211                    imm = *instr;
2212                    if (imm == 0xe2) {
2213                            read_imm_and_print(&instr, &ilen, 8);
2214                            SPACES; debug("fclex");
2215                    } else if (imm == 0xe3) {
2216                            read_imm_and_print(&instr, &ilen, 8);
2217                            SPACES; debug("finit");
2218                    } else if (imm == 0xe4) {
2219                            read_imm_and_print(&instr, &ilen, 8);
2220                            SPACES; debug("fsetpm");
2221                    } else {
2222                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2223                    }
2224            } else if (op == 0xdd) {
2225                    int subop = (*instr >> 3) & 7;
2226                    imm = *instr;
2227                    if (subop == 7) {
2228                            modrm(cpu, MODRM_READ, 16, mode67, 0,
2229                                &instr, &ilen, NULL, NULL);
2230                            SPACES; debug("fstsw\t%s", modrm_rm);
2231                    } else {
2232                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2233                    }
2234            } else if (op == 0xdf) {
2235                    imm = *instr;
2236                    if (imm == 0xe0) {
2237                            read_imm_and_print(&instr, &ilen, 8);
2238                            SPACES; debug("fstsw\tax");
2239                    } else {
2240                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2241                    }
2242            } else if (op == 0xe3) {
2243                    imm = read_imm_and_print(&instr, &ilen, 8);
2244                    imm = dumpaddr + ilen + (signed char)imm;
2245                    if (mode == 16)
2246                            mnem = "jcxz";
2247                    else
2248                            mnem = "jecxz";
2249                    SPACES; debug("%s\t0x%x", mnem, imm);
2250            } else if (op == 0xe4) {
2251                    imm = read_imm_and_print(&instr, &ilen, 8);
2252                    SPACES; debug("in\tal,0x%x", imm);
2253            } else if (op == 0xe5) {
2254                    imm = read_imm_and_print(&instr, &ilen, 8);
2255                    SPACES; debug("in\t%sax,0x%x", e, imm);
2256            } else if (op == 0xe6) {
2257                    imm = read_imm_and_print(&instr, &ilen, 8);
2258                    SPACES; debug("out\t0x%x,al", imm);
2259            } else if (op == 0xe7) {
2260                    imm = read_imm_and_print(&instr, &ilen, 8);
2261                    SPACES; debug("out\t0x%x,%sax", imm, e);
2262            } else if (op == 0xe8 || op == 0xe9) {
2263                    imm = read_imm_and_print(&instr, &ilen, mode);
2264                    if (mode == 16)
2265                            imm = (int16_t)imm;
2266                    imm = dumpaddr + ilen + imm;
2267                    switch (op) {
2268                    case 0xe8: mnem = "call"; break;
2269                    case 0xe9: mnem = "jmp"; break;
2270                    }
2271                    SPACES; debug("%s\t0x%x", mnem, imm);
2272          } else if (op == 0xea) {          } else if (op == 0xea) {
2273                  imm = read_imm_and_print(&instr, &ilen, mode);                  imm = read_imm_and_print(&instr, &ilen, mode);
2274                  imm2 = read_imm_and_print(&instr, &ilen, 16);                  imm2 = read_imm_and_print(&instr, &ilen, 16);
# Line 567  int x86_cpu_disassemble_instr(struct cpu Line 2277  int x86_cpu_disassemble_instr(struct cpu
2277                          debug("0x%04x", imm);                          debug("0x%04x", imm);
2278                  else                  else
2279                          debug("0x%08x", imm);                          debug("0x%08x", imm);
2280          } else if (op == 0xeb) {          } else if ((op >= 0xe0 && op <= 0xe2) || op == 0xeb) {
2281                  imm = read_imm_and_print(&instr, &ilen, 8);                  imm = read_imm_and_print(&instr, &ilen, 8);
2282                  imm = dumpaddr + ilen + (signed char)imm;                  imm = dumpaddr + ilen + (signed char)imm;
2283                  SPACES; debug("jmp\t0x%x", imm);                  switch (op) {
2284                    case 0xe0: mnem = "loopnz"; break;
2285                    case 0xe1: mnem = "loopz"; break;
2286                    case 0xe2: mnem = "loop"; break;
2287                    case 0xeb: mnem = "jmp"; break;
2288                    }
2289                    SPACES; debug("%s\t0x%x", mnem, imm);
2290            } else if (op == 0xec) {
2291                    SPACES; debug("in\tal,dx");
2292            } else if (op == 0xed) {
2293                    SPACES; debug("in\t%sax,dx", e);
2294            } else if (op == 0xee) {
2295                    SPACES; debug("out\tdx,al");
2296            } else if (op == 0xef) {
2297                    SPACES; debug("out\tdx,%sax", e);
2298            } else if (op == 0xf1) {
2299                    SPACES; debug("icebp");         /*  undocumented?  */
2300                    /*  http://www.x86.org/secrets/opcodes/icebp.htm  */
2301          } else if (op == 0xf4) {          } else if (op == 0xf4) {
2302                  SPACES; debug("hlt");                  SPACES; debug("hlt");
2303            } else if (op == 0xf5) {
2304                    SPACES; debug("cmc");
2305          } else if (op == 0xf8) {          } else if (op == 0xf8) {
2306                  SPACES; debug("clc");                  SPACES; debug("clc");
2307          } else if (op == 0xf9) {          } else if (op == 0xf9) {
# Line 585  int x86_cpu_disassemble_instr(struct cpu Line 2314  int x86_cpu_disassemble_instr(struct cpu
2314                  SPACES; debug("cld");                  SPACES; debug("cld");
2315          } else if (op == 0xfd) {          } else if (op == 0xfd) {
2316                  SPACES; debug("std");                  SPACES; debug("std");
2317            } else if (op == 0xf6 || op == 0xf7) {
2318                    switch ((*instr >> 3) & 0x7) {
2319                    case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2320                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2321                            imm = read_imm_and_print(&instr, &ilen,
2322                                op == 0xf6? 8 : mode);
2323                            SPACES; debug("test\t%s,0x%x", modrm_rm, imm);
2324                            break;
2325                    case 2: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2326                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2327                            SPACES; debug("not\t%s", modrm_rm);
2328                            break;
2329                    case 3: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2330                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2331                            SPACES; debug("neg\t%s", modrm_rm);
2332                            break;
2333                    case 4: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2334                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2335                            SPACES; debug("mul\t%s", modrm_rm);
2336                            break;
2337                    case 5: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2338                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2339                            SPACES; debug("imul\t%s", modrm_rm);
2340                            break;
2341                    case 6: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2342                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2343                            SPACES; debug("div\t%s", modrm_rm);
2344                            break;
2345                    case 7: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2346                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2347                            SPACES; debug("idiv\t%s", modrm_rm);
2348                            break;
2349                    default:
2350                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2351                    }
2352            } else if (op == 0xfe || op == 0xff) {
2353                    /*  FE /0 = inc r/m8 */
2354                    /*  FE /1 = dec r/m8 */
2355                    /*  FF /2 = call near rm16/32  */
2356                    /*  FF /3 = call far m16:32  */
2357                    /*  FF /6 = push r/m16/32 */
2358                    switch ((*instr >> 3) & 0x7) {
2359                    case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2360                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2361                            SPACES; debug("inc\t%s", modrm_rm);
2362                            break;
2363                    case 1: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2364                                MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2365                            SPACES; debug("dec\t%s", modrm_rm);
2366                            break;
2367                    case 2: if (op == 0xfe) {
2368                                    SPACES; debug("UNIMPLEMENTED "
2369                                        "0x%02x,0x%02x", op,*instr);
2370                            } else {
2371                                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2372                                        &ilen, NULL, NULL);
2373                                    SPACES; debug("call\t%s", modrm_rm);
2374                            }
2375                            break;
2376                    case 3: if (op == 0xfe) {
2377                                    SPACES; debug("UNIMPLEMENTED "
2378                                        "0x%02x,0x%02x", op,*instr);
2379                            } else {
2380                                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2381                                        &ilen, NULL, NULL);
2382                                    SPACES; debug("call\tfar %s", modrm_rm);
2383                            }
2384                            break;
2385                    case 4: if (op == 0xfe) {
2386                                    SPACES; debug("UNIMPLEMENTED "
2387                                        "0x%02x,0x%02x", op,*instr);
2388                            } else {
2389                                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2390                                        &ilen, NULL, NULL);
2391                                    SPACES; debug("jmp\t%s", modrm_rm);
2392                            }
2393                            break;
2394                    case 5: if (op == 0xfe) {
2395                                    SPACES; debug("UNIMPLEMENTED "
2396                                        "0x%02x,0x%02x", op,*instr);
2397                            } else {
2398                                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2399                                        &ilen, NULL, NULL);
2400                                    SPACES; debug("jmp\tfar %s", modrm_rm);
2401                            }
2402                            break;
2403                    case 6: if (op == 0xfe) {
2404                                    SPACES; debug("UNIMPLEMENTED "
2405                                        "0x%02x,0x%02x", op,*instr);
2406                            } else {
2407                                    modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2408                                        &ilen, NULL, NULL);
2409                                    SPACES; debug("push\t%sword %s",
2410                                        mode == 32? "d" : "", modrm_rm);
2411                            }
2412                            break;
2413                    default:
2414                            SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2415                    }
2416          } else {          } else {
2417                  SPACES; debug("UNIMPLEMENTED 0x%02x", op);                  SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2418          }          }
2419    
2420          if (rep)          switch (rep) {
2421                  debug(" (rep)");          case REP_REP:    debug(" (rep)"); break;
2422            case REP_REPNE:  debug(" (repne)"); break;
2423            }
2424          if (prefix != NULL)          if (prefix != NULL)
2425                  debug(" (%s)", prefix);                  debug(" (%s)", prefix);
2426            if (lock)
2427                    debug(" (lock)");
2428    
2429          debug("\n");          debug("\n");
2430          return ilen;          return ilen;
2431  }  }
2432    
2433    
2434    /*
2435     *  x86_cpuid():
2436     *
2437     *  TODO: Level 1 and 2 info.
2438     */
2439    static void x86_cpuid(struct cpu *cpu)
2440    {
2441            switch (cpu->cd.x86.r[X86_R_AX]) {
2442            /*  Normal CPU id:  */
2443            case 0: cpu->cd.x86.r[X86_R_AX] = 2;
2444                    /*  Intel...  */
2445                    cpu->cd.x86.r[X86_R_BX] = 0x756e6547;  /*  "Genu"  */
2446                    cpu->cd.x86.r[X86_R_DX] = 0x49656e69;  /*  "ineI"  */
2447                    cpu->cd.x86.r[X86_R_CX] = 0x6c65746e;  /*  "ntel"  */
2448                    /*  ... or AMD:  */
2449                    cpu->cd.x86.r[X86_R_BX] = 0x68747541;  /*  "Auth"  */
2450                    cpu->cd.x86.r[X86_R_DX] = 0x69746E65;  /*  "enti"  */
2451                    cpu->cd.x86.r[X86_R_CX] = 0x444D4163;  /*  "cAMD"  */
2452                    break;
2453            case 1: /*  TODO  */
2454                    cpu->cd.x86.r[X86_R_AX] = 0x0623;
2455                    cpu->cd.x86.r[X86_R_BX] = (cpu->cpu_id << 24);
2456                    /*  TODO: are bits 8..15 the _total_ nr of cpus, or the
2457                        cpu id of this one?  */
2458                    cpu->cd.x86.r[X86_R_CX] = X86_CPUID_ECX_CX16;
2459                    cpu->cd.x86.r[X86_R_DX] = X86_CPUID_EDX_CX8 | X86_CPUID_EDX_FPU
2460                        | X86_CPUID_EDX_MSR | X86_CPUID_EDX_TSC | X86_CPUID_EDX_MTRR
2461                        | X86_CPUID_EDX_CMOV | X86_CPUID_EDX_PSE |
2462                        X86_CPUID_EDX_SEP | X86_CPUID_EDX_PGE |
2463                        X86_CPUID_EDX_MMX | X86_CPUID_EDX_FXSR;
2464                    break;
2465            case 2: /*  TODO: actual Cache info  */
2466                    /*  This is just bogus  */
2467                    cpu->cd.x86.r[X86_R_AX] = 0x03020101;
2468                    cpu->cd.x86.r[X86_R_BX] = 0x00000000;
2469                    cpu->cd.x86.r[X86_R_CX] = 0x00000000;
2470                    cpu->cd.x86.r[X86_R_DX] = 0x06040a42;
2471                    break;
2472    
2473            /*  Extended CPU id:  */
2474            case 0x80000000:
2475                    cpu->cd.x86.r[X86_R_AX] = 0x80000008;
2476                    /*  AMD...  */
2477                    cpu->cd.x86.r[X86_R_BX] = 0x68747541;
2478                    cpu->cd.x86.r[X86_R_DX] = 0x444D4163;
2479                    cpu->cd.x86.r[X86_R_CX] = 0x69746E65;
2480                    break;
2481            case 0x80000001:
2482                    cpu->cd.x86.r[X86_R_AX] = 0;
2483                    cpu->cd.x86.r[X86_R_BX] = 0;
2484                    cpu->cd.x86.r[X86_R_CX] = 0;
2485                    cpu->cd.x86.r[X86_R_DX] = (cpu->cd.x86.model.model_number
2486                        >= X86_MODEL_AMD64)? X86_CPUID_EXT_EDX_LM : 0;
2487                    break;
2488            case 0x80000002:
2489            case 0x80000003:
2490            case 0x80000004:
2491            case 0x80000005:
2492            case 0x80000006:
2493            case 0x80000007:
2494                    fatal("[ CPUID 0x%08x ]\n", (int)cpu->cd.x86.r[X86_R_AX]);
2495                    cpu->cd.x86.r[X86_R_AX] = 0;
2496                    cpu->cd.x86.r[X86_R_BX] = 0;
2497                    cpu->cd.x86.r[X86_R_CX] = 0;
2498                    cpu->cd.x86.r[X86_R_DX] = 0;
2499                    break;
2500            case 0x80000008:
2501                    cpu->cd.x86.r[X86_R_AX] = 0x00003028;
2502                    cpu->cd.x86.r[X86_R_BX] = 0;
2503                    cpu->cd.x86.r[X86_R_CX] = 0;
2504                    cpu->cd.x86.r[X86_R_DX] = 0;
2505                    break;
2506            default:fatal("x86_cpuid(): unimplemented eax = 0x%x\n",
2507                        (int)cpu->cd.x86.r[X86_R_AX]);
2508                    cpu->running = 0;
2509            }
2510    }
2511    
2512    
2513    #define TRANSLATE_ADDRESS       translate_address_x86
2514    #include "memory_x86.c"
2515    #undef TRANSLATE_ADDRESS
2516    
2517    
2518  #define MEMORY_RW       x86_memory_rw  #define MEMORY_RW       x86_memory_rw
2519  #define MEM_X86  #define MEM_X86
2520  #include "memory_rw.c"  #include "memory_rw.c"
# Line 607  int x86_cpu_disassemble_instr(struct cpu Line 2523  int x86_cpu_disassemble_instr(struct cpu
2523    
2524    
2525  /*  /*
2526   *  x86_load():   *  x86_push():
  *  
  *  Returns same error code as memory_rw().  
2527   */   */
2528  static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)  static int x86_push(struct cpu *cpu, uint64_t value, int mode)
2529  {  {
2530          unsigned char databuf[8];          int res = 1, oldseg;
2531          int res;          int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2532          uint64_t d;          uint64_t new_esp;
2533            uint64_t old_esp = cpu->cd.x86.r[X86_R_SP];
2534            uint16_t old_ss = cpu->cd.x86.s[X86_S_SS];
2535            uint64_t old_eip = cpu->pc;
2536            uint16_t old_cs = cpu->cd.x86.s[X86_S_CS];
2537    
2538            /*  TODO: up/down?  */
2539            /*  TODO: stacksize?  */
2540    ssize = mode;
2541    
2542            oldseg = cpu->cd.x86.cursegment;
2543            cpu->cd.x86.cursegment = X86_S_SS;
2544            if (ssize == 16)
2545                    new_esp = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
2546                        | ((cpu->cd.x86.r[X86_R_SP] - (ssize / 8)) & 0xffff);
2547            else
2548                    new_esp = (cpu->cd.x86.r[X86_R_SP] -
2549                        (ssize / 8)) & 0xffffffff;
2550            res = x86_store(cpu, new_esp, value, ssize / 8);
2551            if (!res) {
2552                    fatal("WARNING: x86_push store failed: cs:eip=0x%04x:0x%08x"
2553                        " ss:esp=0x%04x:0x%08x\n", (int)old_cs,
2554                        (int)old_eip, (int)old_ss, (int)old_esp);
2555                    if ((old_cs & X86_PL_MASK) != X86_RING3)
2556                            cpu->running = 0;
2557            } else {
2558                    cpu->cd.x86.r[X86_R_SP] = new_esp;
2559            }
2560            cpu->cd.x86.cursegment = oldseg;
2561            return res;
2562    }
2563    
         res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,  
             MEM_READ, CACHE_DATA);  
2564    
2565          d = databuf[0];  /*
2566          if (len > 1) {   *  x86_pop():
2567                  d += ((uint64_t)databuf[1] << 8);   */
2568                  if (len > 2) {  static int x86_pop(struct cpu *cpu, uint64_t *valuep, int mode)
2569                          d += ((uint64_t)databuf[2] << 16);  {
2570                          d += ((uint64_t)databuf[3] << 24);          int res = 1, oldseg;
2571                          if (len > 4) {          int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
                                 d += ((uint64_t)databuf[4] << 32);  
                                 d += ((uint64_t)databuf[5] << 40);  
                                 d += ((uint64_t)databuf[6] << 48);  
                                 d += ((uint64_t)databuf[7] << 56);  
                         }  
                 }  
         }  
2572    
2573          *data = d;          /*  TODO: up/down?  */
2574            /*  TODO: stacksize?  */
2575    ssize = mode;
2576    
2577            oldseg = cpu->cd.x86.cursegment;
2578            cpu->cd.x86.cursegment = X86_S_SS;
2579            res = x86_load(cpu, cpu->cd.x86.r[X86_R_SP], valuep, ssize / 8);
2580            if (!res) {
2581                    fatal("WARNING: x86_pop load failed\n");
2582            } else {
2583                    if (ssize == 16)
2584                            cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
2585                                ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] + (ssize / 8))
2586                                & 0xffff);
2587                    else
2588                            cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] +
2589                                (ssize / 8)) & 0xffffffff;
2590            }
2591            cpu->cd.x86.cursegment = oldseg;
2592          return res;          return res;
2593  }  }
2594    
2595    
2596    #define INT_TYPE_CALLGATE               1
2597    #define INT_TYPE_INTGATE                2
2598    #define INT_TYPE_TRAPGATE               3
2599  /*  /*
2600   *  x86_store():   *  x86_interrupt():
2601   *   *
2602   *  Returns same error code as memory_rw().   *  Read the interrupt descriptor table (or, in real mode, the interrupt
2603     *  vector table), push flags/cs/eip, and jump to the interrupt handler.
2604   */   */
2605  static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)  int x86_interrupt(struct cpu *cpu, int nr, int errcode)
2606  {  {
2607          unsigned char databuf[8];          uint16_t seg, old_cs;
2608            uint32_t ofs;
2609            int res, mode;
2610            unsigned char buf[8];
2611    
2612          /*  x86 is always little-endian:  */          old_cs = cpu->cd.x86.s[X86_S_CS];
2613          databuf[0] = data;  
2614          if (len > 1) {          debug("{ x86_interrupt %i }\n", nr);
2615                  databuf[1] = data >> 8;  
2616                  if (len > 2) {          if (PROTECTED_MODE) {
2617                          databuf[2] = data >> 16;                  int i, int_type = 0;
2618                          databuf[3] = data >> 24;  
2619                          if (len > 4) {                  if (nr * 8 > cpu->cd.x86.idtr_limit) {
2620                                  databuf[4] = data >> 32;                          fatal("TODO: protected mode int 0x%02x outside idtr"
2621                                  databuf[5] = data >> 40;                              " limit (%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2622                                  databuf[6] = data >> 48;                          cpu->running = 0;
2623                                  databuf[7] = data >> 56;                          return 0;
2624                    }
2625    
2626                    /*  Read the interrupt descriptor:  */
2627                    res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*8,
2628                        buf, 8, MEM_READ, NO_SEGMENTATION);
2629                    if (!res) {
2630                            fatal("x86_interrupt(): could not read the"
2631                                " interrupt descriptor table (prot. mode)\n");
2632                            cpu->running = 0;
2633                            return 0;
2634                    }
2635    
2636                    if ((buf[5] & 0x17) == 0x04)
2637                            int_type = INT_TYPE_CALLGATE;
2638                    if ((buf[5] & 0x17) == 0x06)
2639                            int_type = INT_TYPE_INTGATE;
2640                    if ((buf[5] & 0x17) == 0x07)
2641                            int_type = INT_TYPE_TRAPGATE;
2642    
2643                    if (!int_type) {
2644                            fatal("x86_interrupt(): TODO:\n");
2645                            for (i=0; i<8; i++)
2646                                    fatal("  %02x", buf[i]);
2647                            fatal("\n");
2648                            cpu->running = 0;
2649                            return 0;
2650                    }
2651    
2652                    seg = buf[2] + (buf[3] << 8);
2653                    ofs = buf[0] + (buf[1] << 8) + (buf[6] << 16) + (buf[7] << 24);
2654    
2655                    switch (int_type) {
2656                    case INT_TYPE_INTGATE:
2657                    case INT_TYPE_TRAPGATE:
2658                            break;
2659                    default:
2660                            fatal("INT type: %i, cs:eip = 0x%04x:0x%08x\n",
2661                                int_type, (int)seg, (int)ofs);
2662                            cpu->running = 0;
2663                            return 0;
2664                    }
2665    
2666                    reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2667    
2668                    /*
2669                     *  If we're changing privilege level, the we should change
2670                     *  stack here, and push the old SS:ESP.
2671                     */
2672                    if ((seg & X86_PL_MASK) < (old_cs & X86_PL_MASK)) {
2673                            unsigned char buf[16];
2674                            uint16_t new_ss, old_ss;
2675                            uint32_t new_esp, old_esp;
2676                            int pl;
2677    
2678                            pl = seg & X86_PL_MASK;
2679    
2680                            /*  Load SSx:ESPx from the Task State Segment:  */
2681                            if (cpu->cd.x86.tr < 4)
2682                                    fatal("WARNING: interrupt with stack switch"
2683                                        ", but task register = 0?\n");
2684    
2685                            /*  fatal("::: old SS:ESP=0x%04x:0x%08x\n",
2686                                (int)cpu->cd.x86.s[X86_S_SS],
2687                                (int)cpu->cd.x86.r[X86_R_SP]);  */
2688    
2689                            if (!cpu->memory_rw(cpu, cpu->mem, 4 + pl*8 +
2690                                cpu->cd.x86.tr_base, buf, sizeof(buf), MEM_READ,
2691                                NO_SEGMENTATION)) {
2692                                    fatal("ERROR: couldn't read tss blah blah\n");
2693                                    cpu->running = 0;
2694                                    return 0;
2695                            }
2696    
2697                            new_esp = buf[0] + (buf[1] << 8) +
2698                                (buf[2] << 16) + (buf[3] << 24);
2699                            new_ss = buf[4] + (buf[5] << 8);
2700    
2701                            old_ss = cpu->cd.x86.s[X86_S_SS];
2702                            old_esp = cpu->cd.x86.r[X86_R_SP];
2703    
2704                            reload_segment_descriptor(cpu, X86_S_SS, new_ss, NULL);
2705                            cpu->cd.x86.r[X86_R_SP] = new_esp;
2706    
2707                            fatal("::: Switching Stack: new SS:ESP=0x%04x:0x%08x\n",
2708                                (int)new_ss, (int)new_esp);
2709    
2710                            mode = cpu->cd.x86.descr_cache[X86_S_CS].
2711                                default_op_size;
2712    
2713                            if (!x86_push(cpu, old_ss, mode)) {
2714                                    fatal("TODO: problem adgsadg 1\n");
2715                                    cpu->running = 0;
2716                            }
2717                            if (!x86_push(cpu, old_esp, mode)) {
2718                                    fatal("TODO: problem adgsadg 2\n");
2719                                    cpu->running = 0;
2720                            }
2721                    }
2722    
2723                    /*  Push flags, cs, and ip (pc):  */
2724                    mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2725                    if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2726                            fatal("TODO: how to handle this 1 asdf\n");
2727                            cpu->running = 0;
2728                    }
2729                    if (!x86_push(cpu, old_cs, mode)) {
2730                            fatal("TODO: how to handle this 2 sdghser\n");
2731                            cpu->running = 0;
2732                    }
2733                    if (!x86_push(cpu, cpu->pc, mode)) {
2734                            fatal("TODO: how to handle this 3 we\n");
2735                            cpu->running = 0;
2736                    }
2737    
2738                    /*  Push error code for some exceptions:  */
2739                    if ((nr >= 8 && nr <=14) || nr == 17) {
2740                            if (!x86_push(cpu, errcode, mode)) {
2741                                    fatal("x86_interrupt(): TODO: asdgblah\n");
2742                                    cpu->running = 0;
2743                          }                          }
2744                  }                  }
2745    
2746                    /*  Only turn off interrupts for Interrupt Gates:  */
2747                    if (int_type == INT_TYPE_INTGATE)
2748                            cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
2749    
2750                    /*  Turn off TF for Interrupt and Trap Gates:  */
2751                    if (int_type == INT_TYPE_INTGATE ||
2752                        int_type == INT_TYPE_TRAPGATE)
2753                            cpu->cd.x86.rflags &= ~X86_FLAGS_TF;
2754    
2755                    goto int_jump;
2756          }          }
2757    
2758          return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,          /*
2759              MEM_WRITE, CACHE_DATA);           *  Real mode:
2760             */
2761            if (nr * 4 > cpu->cd.x86.idtr_limit) {
2762                    fatal("TODO: real mode int 0x%02x outside idtr limit ("
2763                        "%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2764                    cpu->running = 0;
2765                    return 0;
2766            }
2767            /*  Read the interrupt vector:  */
2768            res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*4, buf, 4,
2769                MEM_READ, NO_SEGMENTATION);
2770            if (!res) {
2771                    fatal("x86_interrupt(): could not read the"
2772                        " interrupt descriptor table\n");
2773                    cpu->running = 0;
2774                    return 0;
2775            }
2776            ofs = buf[0] + (buf[1] << 8);  seg = buf[2] + (buf[3] << 8);
2777    
2778            reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2779    
2780            /*  Push old flags, old cs, and old ip (pc):  */
2781            mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2782    
2783            if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2784                    fatal("x86_interrupt(): TODO: how to handle this 4\n");
2785                    cpu->running = 0;
2786            }
2787            if (!x86_push(cpu, old_cs, mode)) {
2788                    fatal("x86_interrupt(): TODO: how to handle this 5\n");
2789                    cpu->running = 0;
2790            }
2791            if (!x86_push(cpu, cpu->pc, mode)) {
2792                    fatal("x86_interrupt(): TODO: how to handle this 6\n");
2793                    cpu->running = 0;
2794            }
2795    
2796            /*  Turn off interrupts and the Trap Flag, and jump to the interrupt
2797                handler:  */
2798            cpu->cd.x86.rflags &= ~(X86_FLAGS_IF | X86_FLAGS_TF);
2799    
2800    int_jump:
2801            cpu->pc = ofs;
2802    
2803            return 1;
2804  }  }
2805    
2806    
2807    #define CALCFLAGS_OP_ADD        1
2808    #define CALCFLAGS_OP_SUB        2
2809    #define CALCFLAGS_OP_XOR        3
2810  /*  /*
2811   *  x86_interrupt():   *  x86_calc_flags():
  *  
  *  NOTE/TODO: Only for 16-bit mode so far.  
2812   */   */
2813  static int x86_interrupt(struct cpu *cpu, int nr)  static void x86_calc_flags(struct cpu *cpu, uint64_t a, uint64_t b, int mode,
2814            int op)
2815  {  {
2816          uint64_t seg, ofs;          uint64_t c=0, mask;
2817          const int len = sizeof(uint16_t);          int i, count;
2818    
2819          if (cpu->cd.x86.mode != 16) {          if (mode == 8)
2820                  fatal("x86 'int' only implemented for 16-bit so far\n");                  mask = 0xff;
2821                  exit(1);          else if (mode == 16)
2822                    mask = 0xffff;
2823            else if (mode == 32)
2824                    mask = 0xffffffffULL;
2825            else if (mode == 64)
2826                    mask = 0xffffffffffffffffULL;
2827            else {
2828                    fatal("x86_calc_flags(): Bad mode (%i)\n", mode);
2829                    return;
2830          }          }
2831    
2832          /*  Read the interrupt vector from beginning of RAM:  */          a &= mask;
2833          cpu->cd.x86.cursegment = 0;          b &= mask;
2834          x86_load(cpu, nr * 4 + 0, &ofs, sizeof(uint16_t));  
2835          x86_load(cpu, nr * 4 + 2, &seg, sizeof(uint16_t));          /*  CF:  */
2836            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2837          /*  Push flags, cs, and ip (pc):  */          switch (op) {
2838          cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_SS];          case CALCFLAGS_OP_ADD:
2839          if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 1,                  if (((a + b)&mask) < a && ((a + b)&mask) < b)
2840              cpu->cd.x86.rflags, len) != MEMORY_ACCESS_OK)                          cpu->cd.x86.rflags |= X86_FLAGS_CF;
2841                  fatal("x86_interrupt(): TODO: how to handle this\n");                  break;
2842          if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 2,          case CALCFLAGS_OP_SUB:
2843              cpu->cd.x86.s[X86_S_CS], len) != MEMORY_ACCESS_OK)                  if (a < b)
2844                  fatal("x86_interrupt(): TODO: how to handle this\n");                          cpu->cd.x86.rflags |= X86_FLAGS_CF;
2845          if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 3, cpu->pc,                  break;
2846              len) != MEMORY_ACCESS_OK)          case CALCFLAGS_OP_XOR:
2847                  fatal("x86_interrupt(): TODO: how to handle this\n");                  break;
2848            }
2849    
2850          cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)          switch (op) {
2851              | ((cpu->cd.x86.r[X86_R_SP] - len*3) & 0xffff);          case CALCFLAGS_OP_ADD:
2852                    c = (a + b) & mask;
2853                    break;
2854            case CALCFLAGS_OP_SUB:
2855                    c = (a - b) & mask;
2856                    break;
2857            case CALCFLAGS_OP_XOR:
2858                    c = a;
2859            }
2860    
2861          /*  TODO: clear the Interrupt Flag?  */          /*  ZF:  */
2862            cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
2863            if (c == 0)
2864                    cpu->cd.x86.rflags |= X86_FLAGS_ZF;
2865    
2866          cpu->cd.x86.s[X86_S_CS] = seg;          /*  SF:  */
2867          cpu->pc = ofs;          cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
2868            if ((mode == 8 && (c & 0x80)) ||
2869                (mode == 16 && (c & 0x8000)) ||
2870                (mode == 32 && (c & 0x80000000ULL)) ||
2871                (mode == 64 && (c & 0x8000000000000000ULL))) {
2872                    cpu->cd.x86.rflags |= X86_FLAGS_SF;
2873            }
2874    
2875          return 1;          /*  OF:  */
2876            cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
2877            switch (op) {
2878            case CALCFLAGS_OP_ADD:
2879                    /*  TODO  */
2880                    break;
2881            case CALCFLAGS_OP_SUB:
2882                    if (cpu->cd.x86.rflags & X86_FLAGS_SF)
2883                            cpu->cd.x86.rflags |= X86_FLAGS_OF;
2884                    if (mode == 8 && (int8_t)a < (int8_t)b)
2885                            cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2886                    if (mode == 16 && (int16_t)a < (int16_t)b)
2887                            cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2888                    if (mode == 32 && (int32_t)a < (int32_t)b)
2889                            cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2890                    break;
2891            case CALCFLAGS_OP_XOR:
2892                    ;
2893            }
2894    
2895            /*  AF:  */
2896            switch (op) {
2897            case CALCFLAGS_OP_ADD:
2898                    if ((a & 0xf) + (b & 0xf) > 15)
2899                            cpu->cd.x86.rflags |= X86_FLAGS_AF;
2900                    else
2901                            cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2902                    break;
2903            case CALCFLAGS_OP_SUB:
2904                    if ((b & 0xf) > (a & 0xf))
2905                            cpu->cd.x86.rflags |= X86_FLAGS_AF;
2906                    else
2907                            cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2908                    break;
2909            case CALCFLAGS_OP_XOR:
2910                    ;
2911            }
2912    
2913            /*  PF:  (NOTE: Only the lowest 8 bits)  */
2914            cpu->cd.x86.rflags &= ~X86_FLAGS_PF;
2915            count = 0;
2916            for (i=0; i<8; i++) {
2917                    if (c & 1)
2918                            count ++;
2919                    c >>= 1;
2920            }
2921            if (!(count&1))
2922                    cpu->cd.x86.rflags |= X86_FLAGS_PF;
2923  }  }
2924    
2925    
2926  /*  /*
2927   *  x86_cmp():   *  x86_condition():
2928     *
2929     *  Returns 0 or 1 (false or true) depending on flag bits.
2930   */   */
2931  static void x86_cmp(struct cpu *cpu, uint64_t a, uint64_t b)  static int x86_condition(struct cpu *cpu, int op)
2932  {  {
2933          if (a == b)          int success = 0;
                 cpu->cd.x86.rflags |= X86_FLAGS_ZF;  
         else  
                 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;  
2934    
2935          if (a < b)          switch (op & 0xe) {
2936                  cpu->cd.x86.rflags |= X86_FLAGS_CF;          case 0x00:      /*  o  */
2937          else                  success = cpu->cd.x86.rflags & X86_FLAGS_OF;
2938                    break;
2939            case 0x02:      /*  c  */
2940                    success = cpu->cd.x86.rflags & X86_FLAGS_CF;
2941                    break;
2942            case 0x04:      /*  z  */
2943                    success = cpu->cd.x86.rflags & X86_FLAGS_ZF;
2944                    break;
2945            case 0x06:      /*  be  */
2946                    success = (cpu->cd.x86.rflags & X86_FLAGS_ZF) ||
2947                        (cpu->cd.x86.rflags & X86_FLAGS_CF);
2948                    break;
2949            case 0x08:      /*  s  */
2950                    success = cpu->cd.x86.rflags & X86_FLAGS_SF;
2951                    break;
2952            case 0x0a:      /*  p  */
2953                    success = cpu->cd.x86.rflags & X86_FLAGS_PF;
2954                    break;
2955            case 0x0c:      /*  nge  */
2956                    success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2957                        != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2958                    break;
2959            case 0x0e:      /*  ng  */
2960                    success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2961                        != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2962                    success |= (cpu->cd.x86.rflags & X86_FLAGS_ZF ? 1 : 0);
2963                    break;
2964            }
2965    
2966            if (op & 1)
2967                    success = !success;
2968    
2969            return success? 1 : 0;
2970    }
2971    
2972    
2973    /*
2974     *  x86_shiftrotate():
2975     */
2976    static void x86_shiftrotate(struct cpu *cpu, uint64_t *op1p, int op,
2977            int n, int mode)
2978    {
2979            uint64_t op1 = *op1p;
2980            int cf = -1, oldcf = 0;
2981    
2982            n &= 31;
2983            if (mode != 64)
2984                    op1 &= (((uint64_t)1 << mode) - 1);
2985    
2986            oldcf = cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0;
2987    
2988            while (n-- > 0) {
2989                    cf = 0;
2990    
2991                    if (op & 1) {   /*  right  */
2992                            if (op1 & 1)
2993                                    cf = 1;
2994                    } else {        /*  left  */
2995                            cf = (op1 & ((uint64_t)1 << (mode-1)))? 1 : 0;
2996                    }
2997    
2998                    switch (op) {
2999                    case 0: /*  rol  */
3000                            op1 = (op1 << 1) | cf;
3001                            break;
3002                    case 1: /*  ror  */
3003                            op1 >>= 1;
3004                            op1 |= ((uint64_t)cf << (mode - 1));
3005                            break;
3006                    case 2: /*  rcl  */
3007                            op1 = (op1 << 1) | oldcf;
3008                            oldcf = cf;
3009                            break;
3010                    case 3: /*  rcr  */
3011                            op1 >>= 1;
3012                            op1 |= ((uint64_t)oldcf << (mode - 1));
3013                            oldcf = cf;
3014                            break;
3015                    case 4: /*  shl  */
3016                    case 6: /*  sal  */
3017                            op1 <<= 1;
3018                            break;
3019                    case 5: /*  shr  */
3020                            op1 >>= 1;
3021                            break;
3022                    case 7: /*  sar  */
3023                            op1 >>= 1;
3024                            if (mode == 8 && op1 & 0x40)
3025                                    op1 |= 0x80;
3026                            if (mode == 16 && op1 & 0x4000)
3027                                    op1 |= 0x8000;
3028                            if (mode == 32 && op1 & 0x40000000ULL)
3029                                    op1 |= 0x80000000ULL;
3030                            break;
3031                    default:
3032                            fatal("x86_shiftrotate(): unimplemented op %i\n", op);
3033                            cpu->running = 0;
3034                    }
3035                    if (mode != 64)
3036                            op1 &= (((uint64_t)1 << mode) - 1);
3037                    x86_calc_flags(cpu, op1, 0, mode, CALCFLAGS_OP_XOR);
3038                  cpu->cd.x86.rflags &= ~X86_FLAGS_CF;                  cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3039                    if (cf)
3040                            cpu->cd.x86.rflags |= X86_FLAGS_CF;
3041            }
3042    
3043            /*  TODO: OF flag  */
3044    
3045          /*  TODO: other bits?  */          *op1p = op1;
3046  }  }
3047    
3048    
3049  /*  /*
3050   *  x86_test():   *  x86_msr():
3051     *
3052     *  This function reads or writes the MSRs (Model Specific Registers).
3053   */   */
3054  static void x86_test(struct cpu *cpu, uint64_t a, uint64_t b)  static void x86_msr(struct cpu *cpu, int writeflag)
3055  {  {
3056          a &= b;          uint32_t regnr = cpu->cd.x86.r[X86_R_CX] & 0xffffffff;
3057            uint64_t odata=0, idata = (cpu->cd.x86.r[X86_R_AX] & 0xffffffff) +
3058                ((cpu->cd.x86.r[X86_R_DX] & 0xffffffff) << 32);
3059    
3060          if (a == 0)          switch (regnr) {
3061                  cpu->cd.x86.rflags |= X86_FLAGS_ZF;          case 0xc0000080:        /*  AMD64 EFER  */
3062          else                  if (writeflag) {
3063                  cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;                          if (cpu->cd.x86.efer & X86_EFER_LME &&
3064                                !(idata & X86_EFER_LME))
3065                                    debug("[ switching FROM 64-bit mode ]\n");
3066                            if (!(cpu->cd.x86.efer & X86_EFER_LME) &&
3067                                idata & X86_EFER_LME)
3068                                    debug("[ switching to 64-bit mode ]\n");
3069                            cpu->cd.x86.efer = idata;
3070                    } else
3071                            odata = cpu->cd.x86.efer;
3072                    break;
3073            default:fatal("x86_msr: unimplemented MSR 0x%08x\n", (int)regnr);
3074                    cpu->running = 0;
3075            }
3076    
3077          if ((int32_t)a < 0)          if (!writeflag) {