/[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 5 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) {
3078                  cpu->cd.x86.rflags |= X86_FLAGS_SF;                  cpu->cd.x86.r[X86_R_AX] = odata & 0xffffffff;
3079          else                  cpu->cd.x86.r[X86_R_DX] = (odata >> 32) & 0xffffffff;
3080                  cpu->cd.x86.rflags &= ~X86_FLAGS_SF;          }
3081    }
3082    
3083          cpu->cd.x86.rflags &= ~X86_FLAGS_CF;  
3084          cpu->cd.x86.rflags &= ~X86_FLAGS_OF;  /*
3085          /*  TODO: PF  */   *  cause_interrupt():
3086     *
3087     *  Read the registers of PIC1 (and possibly PIC2) to find out which interrupt
3088     *  has occured.
3089     *
3090     *  Returns 1 if an interrupt happened, 0 otherwise (for example if the
3091     *  in-service bit of an interrupt was already set).
3092     */
3093    static int cause_interrupt(struct cpu *cpu)
3094    {
3095            int i, irq_nr = -1;
3096    
3097            for (i=0; i<8; i++) {
3098                    if (cpu->machine->md.pc.pic1->irr &
3099                        (~cpu->machine->md.pc.pic1->ier) & (1 << i))
3100                            irq_nr = i;
3101            }
3102    
3103            if (irq_nr == 2) {
3104                    for (i=0; i<8; i++) {
3105                            if (cpu->machine->md.pc.pic2->irr &
3106                                (~cpu->machine->md.pc.pic2->ier) & (1 << i))
3107                                    irq_nr = 8+i;
3108                    }
3109            }
3110    
3111            if (irq_nr == 2) {
3112                    fatal("cause_interrupt(): Huh? irq 2 but no secondary irq\n");
3113                    cpu->running = 0;
3114            }
3115    
3116            /*
3117             *  TODO: How about multiple interrupt levels?
3118             */
3119    
3120    #if 0
3121    printf("cause1: %i (irr1=%02x ier1=%02x, irr2=%02x ier2=%02x\n", irq_nr,
3122    cpu->machine->md.pc.pic1->irr, cpu->machine->md.pc.pic1->ier,
3123    cpu->machine->md.pc.pic2->irr, cpu->machine->md.pc.pic2->ier);
3124    #endif
3125    
3126            /*  Set the in-service bit, and calculate actual INT nr:  */
3127            if (irq_nr < 8) {
3128                    if (cpu->machine->md.pc.pic1->isr & (1 << irq_nr))
3129                            return 0;
3130                    cpu->machine->md.pc.pic1->isr |= (1 << irq_nr);
3131                    irq_nr = cpu->machine->md.pc.pic1->irq_base + irq_nr;
3132            } else {
3133                    if (cpu->machine->md.pc.pic2->isr & (1 << (irq_nr & 7)))
3134                            return 0;
3135                    cpu->machine->md.pc.pic2->isr |= (1 << (irq_nr&7));
3136                    irq_nr = cpu->machine->md.pc.pic2->irq_base + (irq_nr & 7);
3137            }
3138    
3139    /*  printf("cause2: %i\n", irq_nr);  */
3140    
3141            x86_interrupt(cpu, irq_nr, 0);
3142            cpu->cd.x86.halted = 0;
3143            return 1;
3144  }  }
3145    
3146    
# Line 766  static void x86_test(struct cpu *cpu, ui Line 3154  static void x86_test(struct cpu *cpu, ui
3154   */   */
3155  int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu)  int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu)
3156  {  {
3157          int i, r, rep = 0, op, len, diff, mode = cpu->cd.x86.mode;          int i, r, rep = 0, op, len, mode, omode, mode67;
3158          int mode_addr = mode, nprefixbytes = 0;          int nprefixbytes = 0, success, longmode;
3159          uint32_t imm, imm2, value;          uint32_t imm, imm2;
3160          unsigned char buf[16];          unsigned char buf[16];
3161          unsigned char *instr = buf;          unsigned char *instr = buf, *instr_orig, *really_orig_instr;
3162          uint64_t newpc = cpu->pc;          uint64_t newpc = cpu->pc;
3163          unsigned char databuf[8];          uint64_t tmp, op1, op2;
3164          uint64_t tmp;          int trap_flag_was_set = cpu->cd.x86.rflags & X86_FLAGS_TF;
3165    
3166          /*  Check PC against breakpoints:  */          /*  Check PC against breakpoints:  */
3167          if (!single_step)          if (!single_step)
3168                  for (i=0; i<cpu->machine->n_breakpoints; i++)                  for (i=0; i<cpu->machine->n_breakpoints; i++)
3169                          if (cpu->pc == cpu->machine->breakpoint_addr[i]) {                          if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
3170                                  fatal("Breakpoint reached, pc=0x%llx",                                  fatal("Breakpoint reached, 0x%04x:0x%llx\n",
3171                                      (long long)cpu->pc);                                      cpu->cd.x86.s[X86_S_CS],
3172                                       (long long)cpu->pc);
3173                                  single_step = 1;                                  single_step = 1;
3174                                  return 0;                                  return 0;
3175                          }                          }
3176    
3177            if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) {
3178                    fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n");
3179                    cpu->running = 0;
3180                    return 0;
3181            }
3182    
3183            longmode = cpu->cd.x86.efer & X86_EFER_LME;
3184            mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
3185            omode = mode;
3186            if (mode != 16 && mode != 32) {
3187                    fatal("x86_cpu_run_instr(): Invalid CS default op size, %i\n",
3188                        mode);
3189                    cpu->running = 0;
3190                    return 0;
3191            }
3192    
3193            if (cpu->cd.x86.interrupt_asserted &&
3194                cpu->cd.x86.rflags & X86_FLAGS_IF) {
3195                    if (cause_interrupt(cpu))
3196                            return 0;
3197            }
3198    
3199          /*  16-bit BIOS emulation:  */          /*  16-bit BIOS emulation:  */
3200          if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000)          if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000)
3201              == 0xf8000 && cpu->machine->prom_emulation) {              == 0xf8000 && cpu->machine->prom_emulation) {
3202                    int addr = (newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xfff;
3203                    if (cpu->machine->instruction_trace)
3204                            debug("(PC BIOS emulation, int 0x%02x)\n",
3205                                addr >> 4);
3206                  pc_bios_emul(cpu);                  pc_bios_emul(cpu);
3207                  return 1;                  /*  Approximately equivalent to 500 instructions.  */
3208                    return 500;
3209            }
3210    
3211            if (cpu->cd.x86.halted) {
3212                    if (!(cpu->cd.x86.rflags & X86_FLAGS_IF)) {
3213                            fatal("[ Halting with interrupts disabled. ]\n");
3214                            cpu->running = 0;
3215                    }
3216                    /*  Treating this as more than one instruction makes us
3217                        wait less for devices.  */
3218                    return 1000;
3219          }          }
3220    
3221          /*  Read an instruction from memory:  */          /*  Read an instruction from memory:  */
3222          cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_CS];          cpu->cd.x86.cursegment = X86_S_CS;
3223            cpu->cd.x86.seg_override = 0;
3224    
3225          r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf),          r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf),
3226              MEM_READ, CACHE_INSTRUCTION);              MEM_READ, CACHE_INSTRUCTION);
3227          if (!r)          if (!r) {
3228                    /*  This could happen if, for example, there was an
3229                        exception while we tried to read the instruction.  */
3230                  return 0;                  return 0;
3231            }
3232    
3233            really_orig_instr = instr;      /*  Used to display an error message
3234                                                for unimplemented instructions.  */
3235    
3236          if (cpu->machine->instruction_trace)          if (cpu->machine->instruction_trace)
3237                  x86_cpu_disassemble_instr(cpu, instr, 1, 0, 0);                  x86_cpu_disassemble_instr(cpu, instr, 1 | omode, 0, 0);
3238    
3239            /*  For debugging:  */
3240            if (instr[0] == 0 && instr[1] == 0 && instr[2] == 0 && instr[3] == 0) {
3241                    fatal("WARNING: Running in nothingness?\n");
3242                    cpu->running = 0;
3243                    return 0;
3244            }
3245    
3246          /*  All instructions are at least one byte long :-)  */          /*  All instructions are at least one byte long :-)  */
3247          newpc ++;          newpc ++;
3248    
3249          /*  Default is to use the data segment, or the stack segment:  */          /*  Default is to use the data segment, or the stack segment:  */
3250          cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_DS];          cpu->cd.x86.cursegment = X86_S_DS;
3251            mode67 = mode;
3252    
3253          /*  Any prefix?  */          /*  Any prefix?  */
3254          for (;;) {          for (;;) {
3255                  if (instr[0] == 0x66) {                  if (longmode && (instr[0] & 0xf0) == 0x40) {
3256                            fatal("TODO: REX byte 0x%02x\n", instr[0]);
3257                            cpu->running = 0;
3258                    } else if (instr[0] == 0x66) {
3259                          if (mode == 16)                          if (mode == 16)
3260                                  mode = 32;                                  mode = 32;
3261                          else                          else
3262                                  mode = 16;                                  mode = 16;
3263                  } else if (instr[0] == 0x67) {                  } else if (instr[0] == 0x67) {
3264                          if (mode_addr == 16)                          if (mode67 == 16)
3265                                  mode_addr = 32;                                  mode67 = 32;
3266                          else                          else
3267                                  mode_addr = 16;                                  mode67 = 16;
3268                  } else if (instr[0] == 0xf3)                  } else if (instr[0] == 0x26) {
3269                          rep = 1;                          cpu->cd.x86.cursegment = X86_S_ES;
3270                  else                          cpu->cd.x86.seg_override = 1;
3271                    } else if (instr[0] == 0x2e) {
3272                            cpu->cd.x86.cursegment = X86_S_CS;
3273                            cpu->cd.x86.seg_override = 1;
3274                    } else if (instr[0] == 0x36) {
3275                            cpu->cd.x86.cursegment = X86_S_SS;
3276                            cpu->cd.x86.seg_override = 1;
3277                    } else if (instr[0] == 0x3e) {
3278                            cpu->cd.x86.cursegment = X86_S_DS;
3279                            cpu->cd.x86.seg_override = 1;
3280                    } else if (instr[0] == 0x64) {
3281                            cpu->cd.x86.cursegment = X86_S_FS;
3282                            cpu->cd.x86.seg_override = 1;
3283                    } else if (instr[0] == 0x65) {
3284                            cpu->cd.x86.cursegment = X86_S_GS;
3285                            cpu->cd.x86.seg_override = 1;
3286                    } else if (instr[0] == 0xf0) {
3287                            /*  lock  */
3288                    } else if (instr[0] == 0xf2) {
3289                            rep = REP_REPNE;
3290                    } else if (instr[0] == 0xf3) {
3291                            rep = REP_REP;
3292                    } else
3293                          break;                          break;
                 /*  TODO: repnz, lock etc  */  
3294                  instr ++;                  instr ++;
3295                  newpc ++;                  newpc ++;
3296                  if (++nprefixbytes > 4) {                  if (++nprefixbytes > 4) {
# Line 839  int x86_cpu_run_instr(struct emul *emul, Line 3304  int x86_cpu_run_instr(struct emul *emul,
3304          op = instr[0];          op = instr[0];
3305          instr ++;          instr ++;
3306    
3307          if (op >= 0x40 && op <= 0x4f) {          if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
3308                  if (op < 0x48)                  success = 1;
3309                    instr_orig = instr;
3310                    switch (op & 7) {
3311                    case 4: imm = read_imm(&instr, &newpc, 8);
3312                            op1 = cpu->cd.x86.r[X86_R_AX] & 0xff;
3313                            op2 = (signed char)imm;
3314                            mode = 8;
3315                            break;
3316                    case 5: imm = read_imm(&instr, &newpc, mode);
3317                            op1 = cpu->cd.x86.r[X86_R_AX]; op2 = imm;
3318                            break;
3319                    default:success = modrm(cpu, MODRM_READ, mode, mode67,
3320                                op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc,&op1,&op2);
3321                            if (!success)
3322                                    return 0;
3323                    }
3324    
3325                    if ((op & 6) == 2) {
3326                            uint64_t tmp = op1; op1 = op2; op2 = tmp;
3327                    }
3328    
3329                    /*  printf("op1=0x%x op2=0x%x => ", (int)op1, (int)op2);  */
3330    
3331                    switch (mode) {
3332                    case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3333                    case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3334                    }
3335    
3336                    switch (op & 0x38) {
3337                    case 0x00:      x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3338                                        mode, CALCFLAGS_OP_ADD);
3339                                    op1 = op1 + op2;
3340                                    break;
3341                    case 0x08:      op1 = op1 | op2; break;
3342                    case 0x10:      tmp = op2;
3343                                    if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3344                                            tmp ++;
3345                                    x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3346                                        mode, CALCFLAGS_OP_ADD);
3347                                    op1 = op1 + tmp;
3348                                    break;
3349                    case 0x18:      tmp = op2;
3350                                    if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3351                                            tmp ++;
3352                                    x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3353                                        mode, CALCFLAGS_OP_SUB);
3354                                    op1 = op1 - tmp;
3355                                    break;
3356                    case 0x20:      op1 = op1 & op2; break;
3357                    case 0x28:      x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3358                                        mode, CALCFLAGS_OP_SUB);
3359                                    op1 = op1 - op2; break;
3360                    case 0x30:      op1 = op1 ^ op2; break;
3361                    case 0x38:      x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3362                                        mode, CALCFLAGS_OP_SUB);
3363                                    break;
3364                    default:
3365                            fatal("not yet\n");
3366                            exit(1);
3367                    }
3368    
3369                    switch (mode) {
3370                    case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3371                    case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3372                    }
3373    
3374                    /*  NOTE: Manual cmp for "sbb, "sub" and "cmp" instructions.  */
3375                    if ((op & 0x38) != 0x38 && (op & 0x38) != 0x28 &&
3376                        (op & 0x38) != 0x18 && (op & 0x38) != 0x00 &&
3377                        (op & 0x38) != 0x10)
3378                            x86_calc_flags(cpu, op1, 0, !(op & 1)? 8 : mode,
3379                                CALCFLAGS_OP_XOR);
3380    
3381                    /*  "and","or","xor" always clears CF and OF:  */
3382                    if ((op & 0x38) == 0x08 || (op & 0x38) == 0x20 ||
3383                        (op & 0x38) == 0x30) {
3384                            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3385                            cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
3386                    }
3387    
3388                    /*  printf("op1=0x%x op2=0x%x\n", (int)op1, (int)op2);  */
3389    
3390                    if ((op & 6) == 2) {
3391                            uint64_t tmp = op1; op1 = op2; op2 = tmp;
3392                    }
3393    
3394                    /*  Write back the result: (for all cases except CMP)  */
3395                    if ((op & 0x38) != 0x38) {
3396                            switch (op & 7) {
3397                            case 4: cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
3398                                        X86_R_AX] & ~0xff) | (op1 & 0xff);
3399                                    break;
3400                            case 5: cpu->cd.x86.r[X86_R_AX] = modify(cpu->
3401                                        cd.x86.r[X86_R_AX], op1);
3402                                    break;
3403                            default:success = modrm(cpu, (op & 6) == 2?
3404                                        MODRM_WRITE_R : MODRM_WRITE_RM, mode,
3405                                        mode67, op&1? 0 : MODRM_EIGHTBIT,
3406                                        &instr_orig, NULL, &op1, &op2);
3407                                    if (!success)
3408                                            return 0;
3409                            }
3410                    }
3411            } else if ((op & 0xf0) < 0x20 && (op & 7) == 6) {
3412                    success = x86_push(cpu, cpu->cd.x86.s[op / 8], mode);
3413                    if (!success)
3414                            return 0;
3415            } else if (op == 0x0f && cpu->cd.x86.model.model_number ==
3416                X86_MODEL_8086) {
3417                    uint64_t tmp;
3418                    fatal("WARNING: pop cs\n");
3419                    if (!x86_pop(cpu, &tmp, mode))
3420                            return 0;
3421                    reload_segment_descriptor(cpu, X86_S_CS, tmp, &newpc);
3422            } else if (op == 0x0f) {
3423                    uint64_t tmp;
3424                    unsigned char *instr_orig_2;
3425                    int signflag, i;
3426                    imm = read_imm(&instr, &newpc, 8);
3427                    if (imm >= 0x40 && imm <= 0x4f) {       /*  CMOVxx  */
3428                            op = imm & 0xf;
3429                            if (!modrm(cpu, MODRM_READ, mode, mode67,
3430                                0, &instr, &newpc, &op1, &op2))
3431                                    return 0;
3432                            success = x86_condition(cpu, op);
3433                            if (success) {
3434                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3435                                        MODRM_EIGHTBIT, &instr_orig, NULL,
3436                                        &op2, &op1))
3437                                            return 0;
3438                            }
3439                    } else if (imm >= 0x80 && imm <= 0x8f) {
3440                            /*  conditional near jump  */
3441                            op = imm & 0xf;
3442                            imm = read_imm(&instr, &newpc, mode);
3443                            success = x86_condition(cpu, op);
3444                            if (success)
3445                                    newpc += imm;
3446                    } else if (imm >= 0x90 && imm <= 0x9f) {
3447                            instr_orig = instr;
3448                            if (!modrm(cpu, MODRM_READ, mode, mode67,
3449                                MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2))
3450                                    return 0;
3451                            op1 = x86_condition(cpu, imm & 0xf);
3452                            if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3453                                MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2))
3454                                    return 0;
3455                    } else {
3456                            int subop;
3457                            switch (imm) {
3458                            case 0x00:
3459                                    subop = (*instr >> 3) & 0x7;
3460                                    switch (subop) {
3461                                    case 1: /*  str  */
3462                                            /*  TODO: Check Prot.mode?  */
3463                                            op1 = cpu->cd.x86.tr;
3464                                            if (!modrm(cpu, MODRM_WRITE_RM, 16,
3465                                                mode67, 0, &instr, &newpc, &op1,
3466                                                &op2))
3467                                                    return 0;
3468                                            break;
3469                                    case 2: /*  lldt  */
3470                                            /*  TODO: Check cpl? and Prot.mode  */
3471                                            if (!modrm(cpu, MODRM_READ, 16, mode67,
3472                                                0, &instr, &newpc, &op1, &op2))
3473                                                    return 0;
3474                                            reload_segment_descriptor(cpu,
3475                                                RELOAD_LDTR, op1, &newpc);
3476                                            break;
3477                                    case 3: /*  ltr  */
3478                                            /*  TODO: Check cpl=0 and Prot.mode  */
3479                                            if (!modrm(cpu, MODRM_READ, 16, mode67,
3480                                                0, &instr, &newpc, &op1, &op2))
3481                                                    return 0;
3482                                            reload_segment_descriptor(cpu,
3483                                                RELOAD_TR, op1, &newpc);
3484                                            break;
3485                                    default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3486                                                ",0x%02x\n", op, imm, *instr);
3487                                            quiet_mode = 0;
3488                                            x86_cpu_disassemble_instr(cpu,
3489                                                really_orig_instr, 1 | omode, 0, 0);
3490                                            cpu->running = 0;
3491                                    }
3492                                    break;
3493                            case 0x01:
3494                                    subop = (*instr >> 3) & 0x7;
3495                                    switch (subop) {
3496                                    case 0: /*  sgdt  */
3497                                    case 1: /*  sidt  */
3498                                    case 2: /*  lgdt  */
3499                                    case 3: /*  lidt  */
3500                                            instr_orig = instr;
3501                                            if (!modrm(cpu, MODRM_READ, mode,
3502                                                mode67, MODRM_JUST_GET_ADDR, &instr,
3503                                                &newpc, &op1, &op2))
3504                                                    return 0;
3505                                            /*  TODO/NOTE: how about errors?  */
3506                                            if (subop >= 2) {
3507                                                    x86_load(cpu, op1, &tmp, 2);
3508                                                    x86_load(cpu, op1 + 2, &op2, 4);
3509                                                    if (mode == 16)
3510                                                            op2 &= 0x00ffffffULL;
3511                                            }
3512                                            switch (subop) {
3513                                            case 0: tmp = cpu->cd.x86.gdtr_limit;
3514                                                    op2 = cpu->cd.x86.gdtr;
3515                                                    break;
3516                                            case 1: tmp = cpu->cd.x86.idtr_limit;
3517                                                    op2 = cpu->cd.x86.idtr;
3518                                                    break;
3519                                            case 2: cpu->cd.x86.gdtr_limit =
3520                                                        tmp & 0xffff;
3521                                                    cpu->cd.x86.gdtr = op2;
3522                                                    break;
3523                                            case 3: cpu->cd.x86.idtr_limit =
3524                                                        tmp & 0xffff;
3525                                                    cpu->cd.x86.idtr = op2;
3526                                                    break;
3527                                            }
3528                                            if (subop < 2) {
3529                                                    if (mode == 16)
3530                                                            op2 &= 0x00ffffffULL;
3531                                                    x86_store(cpu, op1, tmp, 2);
3532                                                    x86_store(cpu, op1+2, op2, 4);
3533                                            }
3534                                            break;
3535                                    case 4: /*  smsw  */
3536                                    case 6: /*  lmsw  */
3537                                            instr_orig = instr;
3538                                            if (!modrm(cpu, MODRM_READ, 16, mode67,
3539                                                0, &instr, &newpc, &op1, &op2))
3540                                                    return 0;
3541                                            if (((*instr_orig >> 3) & 0x7) == 4) {
3542                                                    op1 = cpu->cd.x86.cr[0] &0xffff;
3543                                                    if (!modrm(cpu, MODRM_WRITE_RM,
3544                                                        16, mode67, 0, &instr_orig,
3545                                                        NULL, &op1, &op2))
3546                                                            return 0;
3547                                            } else {
3548                                                    /*  lmsw cannot be used to
3549                                                        clear bit 0:  */
3550                                                    op1 |= (cpu->cd.x86.cr[0] &
3551                                                        X86_CR0_PE);
3552                                                    x86_write_cr(cpu, 0,
3553                                                        (cpu->cd.x86.cr[0] & ~0xf)
3554                                                        | (op1 & 0xf));
3555                                            }
3556                                            break;
3557                                    case 7: /*  invlpg  */
3558                                            modrm(cpu, MODRM_READ, mode,
3559                                                mode67, MODRM_JUST_GET_ADDR, &instr,
3560                                                &newpc, &op1, &op2);
3561                                            /*  TODO  */
3562                                            break;
3563                                    default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3564                                                ",0x%02x\n", op, imm, *instr);
3565                                            quiet_mode = 0;
3566                                            x86_cpu_disassemble_instr(cpu,
3567                                                really_orig_instr, 1 | omode, 0, 0);
3568                                            cpu->running = 0;
3569                                    }
3570                                    break;
3571                            case 0x06:      /*  CLTS  */
3572                                    cpu->cd.x86.cr[0] &= ~X86_CR0_TS;
3573                                    break;
3574                            case 0x08:      /*  INVD  */
3575                                    /*  TODO  */
3576                                    break;
3577                            case 0x09:      /*  WBINVD  */
3578                                    /*  TODO  */
3579                                    break;
3580                            case 0x0b:      /*  Reserved  */
3581                                    x86_interrupt(cpu, 6, 0);
3582                                    return 1;
3583                            case 0x20:      /*  MOV r/m,CRx  */
3584                            case 0x21:      /*  MOV r/m,DRx: TODO: is this right? */
3585                                    instr_orig = instr;
3586                                    if (!modrm(cpu, MODRM_READ, 32, mode67,
3587                                        imm==0x20? MODRM_CR : MODRM_DR, &instr,
3588                                        &newpc, &op1, &op2))
3589                                            return 0;
3590                                    op1 = op2;
3591                                    if (!modrm(cpu, MODRM_WRITE_RM, 32, mode67,
3592                                        imm==0x20? MODRM_CR : MODRM_DR, &instr_orig,
3593                                        NULL, &op1, &op2))
3594                                            return 0;
3595                                    break;
3596                            case 0x22:      /*  MOV CRx,r/m  */
3597                            case 0x23:      /*  MOV DRx,r/m  */
3598                                    instr_orig = instr;
3599                                    if (!modrm(cpu, MODRM_READ, 32, mode67,
3600                                        imm==0x22? MODRM_CR : MODRM_DR, &instr,
3601                                        &newpc, &op1, &op2))
3602                                            return 0;
3603                                    op2 = op1;
3604                                    if (!modrm(cpu, MODRM_WRITE_R, 32, mode67,
3605                                        imm==0x22? MODRM_CR : MODRM_DR, &instr_orig,
3606                                        NULL, &op1, &op2))
3607                                            return 0;
3608                                    break;
3609                            case 0x30:      /*  WRMSR  */
3610                            case 0x32:      /*  RDMSR  */
3611                                    x86_msr(cpu, imm==0x30? 1 : 0);
3612                                    break;
3613                            case 0x31:      /*  RDTSC  */
3614                                    if (cpu->cd.x86.model.model_number <
3615                                        X86_MODEL_PENTIUM)
3616                                            fatal("WARNING: rdtsc usually requires"
3617                                                " a Pentium. continuing anyway\n");
3618                                    if (cpu->cd.x86.cr[4] & X86_CR4_TSD)
3619                                            fatal("WARNING: time stamp disable:"
3620                                                " TODO\n");
3621                                    cpu->cd.x86.r[X86_R_DX] = cpu->cd.x86.tsc >> 32;
3622                                    cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.tsc
3623                                        & 0xffffffff;
3624                                    /*  TODO: make this better  */
3625                                    cpu->cd.x86.tsc += 1000;
3626                                    break;
3627                            case 0xa0:
3628                                    if (!x86_push(cpu, cpu->cd.x86.s[X86_S_FS],
3629                                        mode))
3630                                            return 0;
3631                                    break;
3632                            case 0xa1:
3633                                    if (!x86_pop(cpu, &tmp, mode))
3634                                            return 0;
3635                                    reload_segment_descriptor(cpu, X86_S_FS,
3636                                        tmp, &newpc);
3637                                    break;
3638                            case 0xa2:
3639                                    if (!(cpu->cd.x86.rflags & X86_FLAGS_ID))
3640                                            fatal("TODO: ID bit off in flags,"
3641                                                " but CPUID attempted?\n");
3642                                    x86_cpuid(cpu);
3643                                    break;
3644                            case 0xa4:
3645                            case 0xa5:
3646                            case 0xac:
3647                            case 0xad:
3648                                    instr_orig = instr;
3649                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3650                                        0, &instr, &newpc, &op1, &op2))
3651                                            return 0;
3652                                    if (imm & 1)
3653                                            imm2 = cpu->cd.x86.r[X86_R_CX];
3654                                    else
3655                                            imm2 = read_imm(&instr, &newpc, 8);
3656                                    imm2 &= 31;
3657                                    if (imm <= 0xa5) {      /*  SHLD  */
3658                                            if (mode == 16) {
3659                                                    op1 <<= 16;
3660                                                    op1 |= (op2 & 0xffff);
3661                                            } else {
3662                                                    op1 <<= 32;
3663                                                    op1 |= (op2 & 0xffffffff);
3664                                            }
3665                                            x86_shiftrotate(cpu, &op1, 4, imm2,
3666                                                mode == 64? 64 : (mode * 2));
3667                                            op1 >>= (mode==16? 16 : 32);
3668                                    } else {                /*  SHRD  */
3669                                            if (mode == 16) {
3670                                                    op2 <<= 16;
3671                                                    op1 = (op1 & 0xffff) | op2;
3672                                            } else {
3673                                                    op2 <<= 32;
3674                                                    op1 = (op1 & 0xffffffff) | op2;
3675                                            }
3676                                            x86_shiftrotate(cpu, &op1, 5, imm2,
3677                                                mode == 64? 64 : (mode * 2));
3678                                            op1 &= (mode==16? 0xffff : 0xffffffff);
3679                                    }
3680                                    if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3681                                        0, &instr_orig, NULL, &op1, &op2))
3682                                            return 0;
3683                                    break;
3684                            case 0xa8:
3685                                    if (!x86_push(cpu, cpu->cd.x86.s[X86_S_GS],
3686                                        mode))
3687                                            return 0;
3688                                    break;
3689                            case 0xa9:
3690                                    if (!x86_pop(cpu, &tmp, mode))
3691                                            return 0;
3692                                    reload_segment_descriptor(cpu, X86_S_GS,
3693                                        tmp, &newpc);
3694                                    break;
3695                            case 0xa3:              /*  BT  */
3696                            case 0xab:              /*  BTS  */
3697                            case 0xb3:              /*  BTR  */
3698                            case 0xbb:              /*  BTC  */
3699                                    instr_orig = instr;
3700                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3701                                        0, &instr, &newpc, &op1, &op2))
3702                                            return 0;
3703                                    imm2 = op2 & 31;
3704                                    if (mode == 16)
3705                                            imm2 &= 15;
3706                                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3707                                    if (op1 & ((uint64_t)1 << imm2))
3708                                            cpu->cd.x86.rflags |=
3709                                                X86_FLAGS_CF;
3710                                    switch (imm) {
3711                                    case 0xab:
3712                                            op1 |= ((uint64_t)1 << imm2);
3713                                            break;
3714                                    case 0xb3:
3715                                            op1 &= ~((uint64_t)1 << imm2);
3716                                            break;
3717                                    case 0xbb:
3718                                            op1 ^= ((uint64_t)1 << imm2);
3719                                            break;
3720                                    }
3721                                    if (imm != 0xa3) {
3722                                            if (!modrm(cpu, MODRM_WRITE_RM, mode,
3723                                                mode67, 0, &instr_orig, NULL,
3724                                                &op1, &op2))
3725                                                    return 0;
3726                                    }
3727                                    break;
3728                            case 0xaf:      /*  imul r16/32, rm16/32  */
3729                                    instr_orig = instr;
3730                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3731                                        0, &instr, &newpc, &op1, &op2))
3732                                            return 0;
3733                                    cpu->cd.x86.rflags &= X86_FLAGS_CF;
3734                                    cpu->cd.x86.rflags &= X86_FLAGS_OF;
3735                                    if (mode == 16) {
3736                                            op2 = (int16_t)op1 * (int16_t)op2;
3737                                            if (op2 >= 0x10000)
3738                                                    cpu->cd.x86.rflags |=
3739                                                        X86_FLAGS_CF | X86_FLAGS_OF;
3740                                    } else {
3741                                            op2 = (int32_t)op1 * (int32_t)op2;
3742                                            if (op2 >= 0x100000000ULL)
3743                                                    cpu->cd.x86.rflags |=
3744                                                        X86_FLAGS_CF | X86_FLAGS_OF;
3745                                    }
3746                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3747                                        0, &instr_orig, NULL, &op1, &op2))
3748                                            return 0;
3749                                    break;
3750                            case 0xb0:
3751                            case 0xb1:      /*  CMPXCHG  */
3752                                    instr_orig = instr;
3753                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3754                                        imm == 0xb0? MODRM_EIGHTBIT : 0,
3755                                        &instr, &newpc, &op1, &op2))
3756                                            return 0;
3757                                    x86_calc_flags(cpu, op1, cpu->cd.x86.r[
3758                                        X86_R_AX], imm == 0xb0? 8 : mode,
3759                                        CALCFLAGS_OP_SUB);
3760                                    if (cpu->cd.x86.rflags & X86_FLAGS_ZF) {
3761                                            if (!modrm(cpu, MODRM_WRITE_RM, mode,
3762                                                mode67, imm == 0xb0?
3763                                                MODRM_EIGHTBIT : 0,
3764                                                &instr_orig, NULL, &op2, &op1))
3765                                                    return 0;
3766                                    } else {
3767                                            if (imm == 0xb0)
3768                                                    cpu->cd.x86.r[X86_R_AX] =
3769                                                        (cpu->cd.x86.r[X86_R_AX] &
3770                                                        ~0xff) | (op1 & 0xff);
3771                                            else if (mode == 16)
3772                                                    cpu->cd.x86.r[X86_R_AX] =
3773                                                        (cpu->cd.x86.r[X86_R_AX] &
3774                                                        ~0xffff) | (op1 & 0xffff);
3775                                            else    /*  32 bit  */
3776                                                    cpu->cd.x86.r[X86_R_AX] = op1;
3777                                    }
3778                                    break;
3779                            case 0xb2:      /*  LSS  */
3780                            case 0xb4:      /*  LFS  */
3781                            case 0xb5:      /*  LGS  */
3782                                    instr_orig = instr;
3783                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3784                                        MODRM_JUST_GET_ADDR, &instr, &newpc,
3785                                        &op1, &op2))
3786                                            return 0;
3787                                    /*  op1 is the address to load from  */
3788                                    if (!x86_load(cpu, op1, &tmp, mode/8))
3789                                            return 0;
3790                                    op2 = tmp;
3791                                    if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
3792                                            return 0;
3793                                    reload_segment_descriptor(cpu, imm==0xb2?
3794                                        X86_S_SS:(imm==0xb4?X86_S_FS:X86_S_GS),
3795                                        tmp, &newpc);
3796                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3797                                        0, &instr_orig, NULL, &op1, &op2))
3798                                            return 0;
3799                                    break;
3800                            case 0xb6:
3801                            case 0xb7:      /*  movzx  */
3802                            case 0xbe:
3803                            case 0xbf:      /*  movsx  */
3804                                    instr_orig = instr;
3805                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3806                                        (imm&1)==0? (MODRM_EIGHTBIT |
3807                                        MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3808                                        &instr, &newpc, &op1, &op2))
3809                                            return 0;
3810                                    signflag = 0;
3811                                    if (imm >= 0xbe)
3812                                            signflag = 1;
3813                                    op2 = op1;
3814                                    if (imm & 1) {          /*  r32 = r16  */
3815                                            op2 &= 0xffff;
3816                                            if (signflag && op2 & 0x8000)
3817                                                    op2 |= 0xffff0000ULL;
3818                                    } else {                /*  r(mode) = r8  */
3819                                            op2 &= 0xff;
3820                                            if (signflag && op2 & 0x80)
3821                                                    op2 |= 0xffffff00ULL;
3822                                    }
3823                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3824                                        (imm&1)==0? (MODRM_EIGHTBIT |
3825                                        MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3826                                        &instr_orig, NULL, &op1, &op2))
3827                                            return 0;
3828                                    break;
3829                            case 0xba:
3830                                    subop = (*instr >> 3) & 0x7;
3831                                    switch (subop) {
3832                                    case 4: /*  BT  */
3833                                    case 5: /*  BTS  */
3834                                    case 6: /*  BTR  */
3835                                    case 7: /*  BTC  */
3836                                            instr_orig = instr;
3837                                            if (!modrm(cpu, MODRM_READ, mode,
3838                                                mode67, 0, &instr, &newpc, &op1,
3839                                                &op2))
3840                                                    return 0;
3841                                            imm = read_imm(&instr, &newpc, 8);
3842                                            imm &= 31;
3843                                            if (mode == 16)
3844                                                    imm &= 15;
3845                                            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3846                                            if (op1 & ((uint64_t)1 << imm))
3847                                                    cpu->cd.x86.rflags |=
3848                                                        X86_FLAGS_CF;
3849                                            switch (subop) {
3850                                            case 5: op1 |= ((uint64_t)1 << imm);
3851                                                    break;
3852                                            case 6: op1 &= ~((uint64_t)1 << imm);
3853                                                    break;
3854                                            case 7: op1 ^= ((uint64_t)1 << imm);
3855                                                    break;
3856                                            }
3857                                            if (subop != 4) {
3858                                                    if (!modrm(cpu, MODRM_WRITE_RM,
3859                                                        mode, mode67, 0,
3860                                                        &instr_orig, NULL,
3861                                                        &op1, &op2))
3862                                                            return 0;
3863                                            }
3864                                            break;
3865                                    default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3866                                                ",0x%02x\n", op, imm, *instr);
3867                                            quiet_mode = 0;
3868                                            x86_cpu_disassemble_instr(cpu,
3869                                                really_orig_instr, 1|omode, 0, 0);
3870                                            cpu->running = 0;
3871                                    }
3872                                    break;
3873                            case 0xbc:      /*  bsf  */
3874                            case 0xbd:      /*  bsr  */
3875                                    instr_orig = instr;
3876                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3877                                        0, &instr, &newpc, &op1, &op2))
3878                                            return 0;
3879                                    cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3880                                    if (op1 == 0)
3881                                            cpu->cd.x86.rflags |= X86_FLAGS_ZF;
3882                                    i = mode - 1;
3883                                    if (imm == 0xbc)
3884                                            i = 0;
3885                                    for (;;) {
3886                                            if (op1 & ((uint64_t)1<<i)) {
3887                                                    op2 = i;
3888                                                    break;
3889                                            }
3890                                            if (imm == 0xbc) {
3891                                                    if (++i >= mode)
3892                                                            break;
3893                                            } else {
3894                                                    if (--i < 0)
3895                                                            break;
3896                                            }
3897                                    }
3898                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3899                                        0, &instr_orig, NULL, &op1, &op2))
3900                                            return 0;
3901                                    break;
3902                            case 0xc0:      /*  xadd  */
3903                            case 0xc1:
3904                                    instr_orig = instr_orig_2 = instr;
3905                                    if (!modrm(cpu, MODRM_READ, mode, mode67,
3906                                        imm == 0xc0? MODRM_EIGHTBIT : 0,
3907                                        &instr, &newpc, &op1, &op2))
3908                                            return 0;
3909                                    tmp = op1; op1 = op2; op2 = tmp;
3910                                    x86_calc_flags(cpu, op1, op2, imm==0xc0?
3911                                        8 : mode, CALCFLAGS_OP_ADD);
3912                                    op1 += op2;
3913                                    if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3914                                        imm == 0xc0? MODRM_EIGHTBIT : 0,
3915                                        &instr_orig, NULL, &op1, &op2))
3916                                            return 0;
3917                                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3918                                        imm == 0xc0? MODRM_EIGHTBIT : 0,
3919                                        &instr_orig_2, NULL, &op1, &op2))
3920                                            return 0;
3921                                    break;
3922                            case 0xc7:
3923                                    subop = (*instr >> 3) & 0x7;
3924                                    switch (subop) {
3925                                    case 1: /*  CMPXCHG8B  */
3926                                            if (!modrm(cpu, MODRM_READ, mode,
3927                                                mode67, MODRM_JUST_GET_ADDR, &instr,
3928                                                &newpc, &op1, &op2))
3929                                                    return 0;
3930                                            if (!x86_load(cpu, op1, &tmp, 8))
3931                                                    return 0;
3932                                            cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3933                                            if ((tmp >> 32) == (0xffffffffULL &
3934                                                cpu->cd.x86.r[X86_R_DX]) && (tmp
3935                                                & 0xffffffffULL) == (0xffffffffULL &
3936                                                cpu->cd.x86.r[X86_R_AX])) {
3937                                                    cpu->cd.x86.rflags |=
3938                                                        X86_FLAGS_ZF;
3939                                                    tmp = ((cpu->cd.x86.r[X86_R_CX]
3940                                                        & 0xffffffffULL) << 32) |
3941                                                        (cpu->cd.x86.r[X86_R_BX] &
3942                                                        0xffffffffULL);
3943                                                    if (!x86_store(cpu, op1, tmp,8))
3944                                                            return 0;
3945                                            } else {
3946                                                    cpu->cd.x86.r[X86_R_DX] =
3947                                                        tmp >> 32;
3948                                                    cpu->cd.x86.r[X86_R_AX] =
3949                                                        tmp & 0xffffffffULL;
3950                                            }
3951                                            break;
3952                                    default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3953                                                ",0x%02x\n", op, imm, *instr);
3954                                            quiet_mode = 0;
3955                                            x86_cpu_disassemble_instr(cpu,
3956                                                really_orig_instr, 1|omode, 0, 0);
3957                                            cpu->running = 0;
3958                                    }
3959                                    break;
3960                            default:fatal("TODO: 0x0f,0x%02x\n", imm);
3961                                    quiet_mode = 0;
3962                                    x86_cpu_disassemble_instr(cpu,
3963                                        really_orig_instr, 1|omode, 0, 0);
3964                                    cpu->running = 0;
3965                            }
3966                    }
3967            } else if ((op & 0xf0) < 0x20 && (op & 7) == 7) {
3968                    uint64_t tmp;
3969                    success = x86_pop(cpu, &tmp, mode);
3970                    if (!success)
3971                            return 0;
3972                    reload_segment_descriptor(cpu, op/8, tmp, &newpc);
3973            } else if (op == 0x27) {                        /*  DAA  */
3974                    int a = (cpu->cd.x86.r[X86_R_AX] >> 4) & 0xf;
3975                    int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
3976                    if (b > 9) {
3977                            b -= 10;
3978                            a ++;
3979                    } else if (cpu->cd.x86.rflags & X86_FLAGS_AF)
3980                            b += 6;
3981                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3982                    cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3983                    if (a*10 + b >= 100) {
3984                            cpu->cd.x86.rflags |= X86_FLAGS_CF;
3985                            cpu->cd.x86.rflags |= X86_FLAGS_AF;
3986                            a %= 10;
3987                    }
3988                    cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3989                    cpu->cd.x86.r[X86_R_AX] |= ((a*16 + b) & 0xff);
3990            } else if (op == 0x2f) {                        /*  DAS  */
3991                    int tmp_al = cpu->cd.x86.r[X86_R_AX] & 0xff;
3992                    if ((tmp_al & 0xf) > 9 || cpu->cd.x86.rflags & X86_FLAGS_AF) {
3993                            cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3994                            cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 6) & 0xff);
3995                            cpu->cd.x86.rflags |= X86_FLAGS_AF;
3996                    } else
3997                            cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3998                    if (tmp_al > 0x9f || cpu->cd.x86.rflags & X86_FLAGS_CF) {
3999                            cpu->cd.x86.r[X86_R_AX] &= ~0xff;
4000                            cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 0x60) & 0xff);
4001                            cpu->cd.x86.rflags |= X86_FLAGS_CF;
4002                    } else
4003                            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4004                    x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX] & 0xff,
4005                        0, 8, CALCFLAGS_OP_XOR);
4006            } else if (op == 0x37) {                        /*  AAA  */
4007                    int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
4008                    if (b > 9) {
4009                            cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX]
4010                                & ~0xff00) | ((cpu->cd.x86.r[X86_R_AX] &
4011                                0xff00) + 0x100);
4012                            cpu->cd.x86.rflags |= X86_FLAGS_CF | X86_FLAGS_AF;
4013                    } else {
4014                            cpu->cd.x86.rflags &= ~(X86_FLAGS_CF | X86_FLAGS_AF);
4015                    }
4016                    cpu->cd.x86.r[X86_R_AX] &= ~0xf0;
4017            } else if (op >= 0x40 && op <= 0x4f) {
4018                    int old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
4019                    if (op < 0x48) {
4020                            x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4021                                CALCFLAGS_OP_ADD);
4022                          cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],                          cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],
4023                              cpu->cd.x86.r[op & 7] + 1);                              cpu->cd.x86.r[op & 7] + 1);
4024                    } else {
4025                            x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4026                                CALCFLAGS_OP_SUB);
4027                            if (mode == 16)
4028                                    cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op
4029                                        & 7], (cpu->cd.x86.r[op & 7] & 0xffff) - 1);
4030                            else {
4031                                    cpu->cd.x86.r[op & 7] --;
4032                                    cpu->cd.x86.r[op & 7] &= 0xffffffffULL;
4033                            }
4034                    }
4035                    /*  preserve CF:  */
4036                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4037                    cpu->cd.x86.rflags |= old_cf;
4038            } else if (op >= 0x50 && op <= 0x57) {
4039                    if (!x86_push(cpu, cpu->cd.x86.r[op & 7], mode))
4040                            return 0;
4041            } else if (op >= 0x58 && op <= 0x5f) {
4042                    if (!x86_pop(cpu, &tmp, mode))
4043                            return 0;
4044                    if (mode == 16)
4045                            cpu->cd.x86.r[op & 7] = (cpu->cd.x86.r[op & 7] &
4046                                ~0xffff) | (tmp & 0xffff);
4047                  else                  else
4048                          cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],                          cpu->cd.x86.r[op & 7] = tmp;
4049                              cpu->cd.x86.r[op & 7] - 1);          } else if (op == 0x60) {                /*  PUSHA/PUSHAD  */
4050                  /*  TODO: flags etc  */                  uint64_t r[8];
4051                    int i;
4052                    for (i=0; i<8; i++)
4053                            r[i] = cpu->cd.x86.r[i];
4054                    for (i=0; i<8; i++)
4055                            if (!x86_push(cpu, r[i], mode)) {
4056                                    fatal("TODO: failed pusha\n");
4057                                    cpu->running = 0;
4058                                    return 0;
4059                            }
4060            } else if (op == 0x61) {                /*  POPA/POPAD  */
4061                    uint64_t r[8];
4062                    int i;
4063                    for (i=7; i>=0; i--)
4064                            if (!x86_pop(cpu, &r[i], mode)) {
4065                                    fatal("TODO: failed popa\n");
4066                                    cpu->running = 0;
4067                                    return 0;
4068                            }
4069                    for (i=0; i<8; i++)
4070                            if (i != X86_R_SP) {
4071                                    if (mode == 16)
4072                                            cpu->cd.x86.r[i] = (cpu->cd.x86.r[i]
4073                                                & ~0xffff) | (r[i] & 0xffff);
4074                                    else
4075                                            cpu->cd.x86.r[i] = r[i];
4076                            }
4077            } else if (op == 0x68) {                /*  PUSH imm16/32  */
4078                    uint64_t imm = read_imm(&instr, &newpc, mode);
4079                    if (!x86_push(cpu, imm, mode))
4080                            return 0;
4081            } else if (op == 0x69 || op == 0x6b) {
4082                    instr_orig = instr;
4083                    if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4084                        &newpc, &op1, &op2))
4085                            return 0;
4086                    if (op == 0x69)
4087                            imm = read_imm(&instr, &newpc, mode);
4088                    else
4089                            imm = (signed char)read_imm(&instr, &newpc, 8);
4090                    op2 = op1 * imm;
4091                    /*  TODO: overflow!  */
4092                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, 0,
4093                        &instr_orig, NULL, &op1, &op2))
4094                            return 0;
4095            } else if (op == 0x6a) {                /*  PUSH imm8  */
4096                    uint64_t imm = (signed char)read_imm(&instr, &newpc, 8);
4097                    if (!x86_push(cpu, imm, mode))
4098                            return 0;
4099            } else if ((op & 0xf0) == 0x70) {
4100                    imm = read_imm(&instr, &newpc, 8);
4101                    success = x86_condition(cpu, op);
4102                    if (success)
4103                            newpc = modify(newpc, newpc + (signed char)imm);
4104            } else if (op == 0x80 || op == 0x81) {  /*  add/and r/m, imm  */
4105                    instr_orig = instr;
4106                    if (!modrm(cpu, MODRM_READ, mode, mode67, op == 0x80?
4107                        MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2))
4108                            return 0;
4109                    imm = read_imm(&instr, &newpc, op==0x80? 8 : mode);
4110                    switch ((*instr_orig >> 3) & 0x7) {
4111                    case 0: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4112                                CALCFLAGS_OP_ADD);
4113                            op1 += imm;
4114                            break;
4115                    case 1: op1 |= imm; break;
4116                    case 2: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4117                            x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4118                                CALCFLAGS_OP_ADD);
4119                            op1 += tmp;
4120                            break;
4121                    case 3: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4122                            x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4123                                CALCFLAGS_OP_SUB);
4124                            op1 -= tmp;
4125                            break;
4126                    case 4: op1 &= imm; break;
4127                    case 5: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4128                                CALCFLAGS_OP_SUB);
4129                            op1 -= imm; break;
4130                    case 6: op1 ^= imm; break;
4131                    case 7: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4132                                CALCFLAGS_OP_SUB); /* cmp */
4133                            break;
4134                    }
4135    
4136                    if (((*instr_orig >> 3) & 0x7) != 7) {
4137                            if (((*instr_orig >> 3) & 0x7) != 0 &&
4138                                ((*instr_orig >> 3) & 0x7) != 2 &&
4139                                ((*instr_orig >> 3) & 0x7) != 3 &&
4140                                ((*instr_orig >> 3) & 0x7) != 5)
4141                                    x86_calc_flags(cpu, op1, 0, op==0x80? 8 : mode,
4142                                        CALCFLAGS_OP_XOR);
4143    
4144                            /*  "and","or","xor" always clears CF and OF:  */
4145                            if (((*instr_orig >> 3) & 0x7) == 1 ||
4146                                ((*instr_orig >> 3) & 0x7) == 4 ||
4147                                ((*instr_orig >> 3) & 0x7) == 6) {
4148                                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4149                                    cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4150                            }
4151    
4152                            if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4153                                op == 0x80? MODRM_EIGHTBIT : 0, &instr_orig,
4154                                NULL, &op1, &op2))
4155                                    return 0;
4156                    }
4157            } else if (op == 0x83) {        /*  add/and r/m1632, imm8  */
4158                    instr_orig = instr;
4159                    if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4160                        &newpc, &op1, &op2))
4161                            return 0;
4162                    imm = read_imm(&instr, &newpc, 8);
4163                    switch ((*instr_orig >> 3) & 0x7) {
4164                    case 0: x86_calc_flags(cpu, op1, (signed char)imm,
4165                                mode, CALCFLAGS_OP_ADD);
4166                            op1 += (signed char)imm;
4167                            break;
4168                    case 1: op1 |= (signed char)imm; break;
4169                    case 2: tmp = (signed char)imm +
4170                                (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4171                            x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_ADD);
4172                            op1 += tmp;
4173                            break;
4174                    case 3: tmp = (signed char)imm +
4175                                (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4176                            x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_SUB);
4177                            op1 -= tmp;
4178                            break;
4179                    case 4: op1 &= (signed char)imm; break;
4180                    case 5: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4181                                CALCFLAGS_OP_SUB);
4182                            op1 -= (signed char)imm; break;
4183                    case 6: op1 ^= (signed char)imm; break;
4184                    case 7: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4185                                CALCFLAGS_OP_SUB);
4186                            break;
4187                    }
4188                    if (((*instr_orig >> 3) & 0x7) != 7) {
4189                            if (((*instr_orig >> 3) & 0x7) != 0 &&
4190                                ((*instr_orig >> 3) & 0x7) != 2 &&
4191                                ((*instr_orig >> 3) & 0x7) != 3 &&
4192                                ((*instr_orig >> 3) & 0x7) != 5)
4193                                    x86_calc_flags(cpu, op1, 0, mode,
4194                                        CALCFLAGS_OP_XOR);
4195    
4196                            /*  "and","or","xor" always clears CF and OF:  */
4197                            if (((*instr_orig >> 3) & 0x7) == 1 ||
4198                                ((*instr_orig >> 3) & 0x7) == 4 ||
4199                                ((*instr_orig >> 3) & 0x7) == 6) {
4200                                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4201                                    cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4202                            }
4203                            if (!modrm(cpu, MODRM_WRITE_RM, mode,
4204                                mode67, 0, &instr_orig, NULL, &op1, &op2))
4205                                    return 0;
4206                    }
4207            } else if (op == 0x84 || op == 0x85) {          /*  TEST  */
4208                    success = modrm(cpu, MODRM_READ, mode, mode67, op == 0x84?
4209                        MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4210                    if (!success)
4211                            return 0;
4212                    op1 &= op2;
4213                    x86_calc_flags(cpu, op1, 0, op==0x84? 8 : mode,
4214                        CALCFLAGS_OP_XOR);
4215                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4216                    cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4217            } else if (op >= 0x86 && op <= 0x87) {          /*  XCHG  */
4218                    void *orig2 = instr_orig = instr;
4219                    success = modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
4220                        MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4221                    if (!success)
4222                            return 0;
4223                    /*  Note: Update the r/m first, because it may be dependant
4224                        on original register values :-)  */
4225                    success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4226                        op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4227                        NULL, &op2, &op1);
4228                    instr_orig = orig2;
4229                    success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4230                        op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4231                        NULL, &op2, &op1);
4232                    if (!success)
4233                            return 0;
4234            } else if (op >= 0x88 && op <= 0x8b) {          /*  MOV  */
4235                    instr_orig = instr;
4236                    success = modrm(cpu, MODRM_READ, mode, mode67, (op & 1) == 0?
4237                        MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4238                    if (!success)
4239                            return 0;
4240                    if (op < 0x8a) {
4241                            success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4242                                op == 0x88? MODRM_EIGHTBIT : 0, &instr_orig,
4243                                NULL, &op2, &op1);
4244                    } else {
4245                            success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4246                                op == 0x8a? MODRM_EIGHTBIT : 0, &instr_orig,
4247                                NULL, &op2, &op1);
4248                    }
4249                    if (!success)
4250                            return 0;
4251            } else if (op == 0x8c || op == 0x8e) {          /*  MOV seg  */
4252                    instr_orig = instr;
4253                    if (!modrm(cpu, MODRM_READ, 16, mode67, MODRM_SEG,
4254                        &instr, &newpc, &op1, &op2))
4255                            return 0;
4256                    if (op == 0x8c) {
4257                            if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, MODRM_SEG,
4258                                &instr_orig, NULL, &op2, &op1))
4259                                    return 0;
4260                    } else {
4261                            reload_segment_descriptor(cpu, (*instr_orig >> 3) & 7,
4262                                op1 & 0xffff, &newpc);
4263                    }
4264            } else if (op == 0x8d) {                        /*  LEA  */
4265                    instr_orig = instr;
4266                    if (!modrm(cpu, MODRM_READ, mode, mode67,
4267                        MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4268                            return 0;
4269                    op2 = op1;
4270                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4271                        0, &instr_orig, NULL, &op1, &op2))
4272                            return 0;
4273            } else if (op == 0x8f) {
4274                    switch ((*instr >> 3) & 0x7) {
4275                    case 0: /*  POP m16/m32  */
4276                            if (!x86_pop(cpu, &op1, mode))
4277                                    return 0;
4278                            if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4279                                0, &instr, &newpc, &op1, &op2))
4280                                    return 0;
4281                            break;
4282                    default:
4283                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4284                            quiet_mode = 0;
4285                            x86_cpu_disassemble_instr(cpu,
4286                                really_orig_instr, 1|omode, 0, 0);
4287                            cpu->running = 0;
4288                    }
4289          } else if (op == 0x90) {                /*  NOP  */          } else if (op == 0x90) {                /*  NOP  */
4290          } else if (op >= 0xb8 && op <= 0xbf) {          } else if (op >= 0x91 && op <= 0x97) {  /*  XCHG  */
4291                    uint64_t tmp;
4292                    if (mode == 16) {
4293                            tmp = cpu->cd.x86.r[X86_R_AX];
4294                            cpu->cd.x86.r[X86_R_AX] = modify(
4295                                cpu->cd.x86.r[X86_R_AX], cpu->cd.x86.r[op & 7]);
4296                            cpu->cd.x86.r[op & 7] = modify(
4297                                cpu->cd.x86.r[op & 7], tmp);
4298                    } else {
4299                            tmp = cpu->cd.x86.r[X86_R_AX];
4300                            cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.r[op & 7];
4301                            cpu->cd.x86.r[op & 7] = tmp;
4302                    }
4303            } else if (op == 0x98) {                /*  CBW/CWDE  */
4304                    if (mode == 16) {
4305                            cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4306                            if (cpu->cd.x86.r[X86_R_AX] & 0x80)
4307                                    cpu->cd.x86.r[X86_R_AX] |= 0xff00;
4308                    } else {
4309                            cpu->cd.x86.r[X86_R_AX] &= 0xffff;
4310                            if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4311                                    cpu->cd.x86.r[X86_R_AX] |= 0xffff0000ULL;
4312                    }
4313            } else if (op == 0x99) {                /*  CWD/CDQ  */
4314                    if (mode == 16) {
4315                            cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
4316                            if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4317                                    cpu->cd.x86.r[X86_R_DX] |= 0xffff;
4318                    } else {
4319                            cpu->cd.x86.r[X86_R_DX] = 0;
4320                            if (cpu->cd.x86.r[X86_R_AX] & 0x80000000ULL)
4321                                    cpu->cd.x86.r[X86_R_DX] = 0xffffffff;
4322                    }
4323            } else if (op == 0x9a) {        /*  CALL seg:ofs  */
4324                    uint16_t old_tr = cpu->cd.x86.tr;
4325                  imm = read_imm(&instr, &newpc, mode);                  imm = read_imm(&instr, &newpc, mode);
4326                  cpu->cd.x86.r[op & 7] = imm;                  imm2 = read_imm(&instr, &newpc, 16);
4327                    if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS], mode))
4328                            return 0;
4329                    if (!x86_push(cpu, newpc, mode)) {
4330                            fatal("TODO: push failed in CALL seg:ofs\n");
4331                            cpu->running = 0;
4332                            return 0;
4333                    }
4334                    reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
4335                    if (cpu->cd.x86.tr == old_tr)
4336                            newpc = imm;
4337            } else if (op == 0x9b) {                /*  WAIT  */
4338            } else if (op == 0x9c) {                /*  PUSHF  */
4339                    if (!x86_push(cpu, cpu->cd.x86.rflags, mode))
4340                            return 0;
4341            } else if (op == 0x9d) {                /*  POPF  */
4342                    if (!x86_pop(cpu, &tmp, mode))
4343                            return 0;
4344                    if (mode == 16)
4345                            cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4346                                | (tmp & 0xffff);
4347                    else if (mode == 32)
4348                            cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffffffff)
4349                                | (tmp & 0xffffffff);
4350                    else
4351                            cpu->cd.x86.rflags = tmp;
4352                    /*  TODO: only affect some bits?  */
4353                    cpu->cd.x86.rflags |= 0x0002;
4354                    if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
4355                            cpu->cd.x86.rflags |= 0xf000;
4356                    /*  TODO: all these bits aren't really cleared on a 286:  */
4357                    if (cpu->cd.x86.model.model_number == X86_MODEL_80286)
4358                            cpu->cd.x86.rflags &= ~0xf000;
4359                    if (cpu->cd.x86.model.model_number == X86_MODEL_80386)
4360                            cpu->cd.x86.rflags &= ~X86_FLAGS_AC;
4361                    if (cpu->cd.x86.model.model_number == X86_MODEL_80486)
4362                            cpu->cd.x86.rflags &= ~X86_FLAGS_ID;
4363            } else if (op == 0x9e) {                /*  SAHF  */
4364                    int mask = (X86_FLAGS_SF | X86_FLAGS_ZF
4365                        | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4366                    cpu->cd.x86.rflags &= ~mask;
4367                    mask &= ((cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff);
4368                    cpu->cd.x86.rflags |= mask;
4369            } else if (op == 0x9f) {                /*  LAHF  */
4370                    int b = cpu->cd.x86.rflags & (X86_FLAGS_SF | X86_FLAGS_ZF
4371                        | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4372                    b |= 2;
4373                    cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4374                    cpu->cd.x86.r[X86_R_AX] |= (b << 8);
4375            } else if (op == 0xa0) {                /*  MOV AL,[addr]  */
4376                    imm = read_imm(&instr, &newpc, mode67);
4377                    if (!x86_load(cpu, imm, &tmp, 1))
4378                            return 0;
4379                    cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4380                        | (tmp & 0xff);
4381            } else if (op == 0xa1) {                /*  MOV AX,[addr]  */
4382                    imm = read_imm(&instr, &newpc, mode67);
4383                    if (!x86_load(cpu, imm, &tmp, mode/8))
4384                            return 0;
4385                    cpu->cd.x86.r[X86_R_AX] = modify(cpu->cd.x86.r[X86_R_AX], tmp);
4386            } else if (op == 0xa2) {                /*  MOV [addr],AL  */
4387                    imm = read_imm(&instr, &newpc, mode67);
4388                    if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], 1))
4389                            return 0;
4390            } else if (op == 0xa3) {                /*  MOV [addr],AX  */
4391                    imm = read_imm(&instr, &newpc, mode67);
4392                    if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], mode/8))
4393                            return 0;
4394            } else if (op == 0xa4 || op == 0xa5 ||          /*  MOVS  */
4395                op == 0xa6 || op == 0xa7 ||                 /*  CMPS  */
4396                op == 0xaa || op == 0xab ||                 /*  STOS  */
4397                op == 0xac || op == 0xad ||                 /*  LODS  */
4398                op == 0xae || op == 0xaf) {                 /*  SCAS  */
4399                    int dir = 1, movs = 0, lods = 0, cmps = 0, stos = 0, scas = 0;
4400                    int origcursegment = cpu->cd.x86.cursegment;
4401    
4402                    len = 1;
4403                    if (op & 1)
4404                            len = mode / 8;
4405                    if (op >= 0xa4 && op <= 0xa5)
4406                            movs = 1;
4407                    if (op >= 0xa6 && op <= 0xa7)
4408                            cmps = 1;
4409                    if (op >= 0xaa && op <= 0xab)
4410                            stos = 1;
4411                    if (op >= 0xac && op <= 0xad)
4412                            lods = 1;
4413                    if (op >= 0xae && op <= 0xaf)
4414                            scas = 1;
4415                    if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4416                            dir = -1;
4417    
4418                    do {
4419                            uint64_t value;
4420    
4421                            if (rep) {
4422                                    /*  Abort if [e]cx already 0:  */
4423                                    if (mode == 16 && (cpu->cd.x86.r[X86_R_CX] &
4424                                        0xffff) == 0)
4425                                            break;
4426                                    if (mode != 16 && cpu->cd.x86.r[X86_R_CX] == 0)
4427                                            break;
4428                            }
4429    
4430                            if (!stos && !scas) {
4431                                    uint64_t addr = cpu->cd.x86.r[X86_R_SI];
4432                                    if (mode67 == 16)
4433                                            addr &= 0xffff;
4434                                    if (mode67 == 32)
4435                                            addr &= 0xffffffff;
4436                                    cpu->cd.x86.cursegment = origcursegment;
4437                                    if (!x86_load(cpu, addr, &value, len))
4438                                            return 0;
4439                            } else
4440                                    value = cpu->cd.x86.r[X86_R_AX];
4441                            if (lods) {
4442                                    if (op == 0xac)
4443                                            cpu->cd.x86.r[X86_R_AX] =
4444                                                (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4445                                                | (value & 0xff);
4446                                    else if (mode == 16)
4447                                            cpu->cd.x86.r[X86_R_AX] =
4448                                                (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4449                                                | (value & 0xffff);
4450                                    else
4451                                            cpu->cd.x86.r[X86_R_AX] = value;
4452                            }
4453    
4454                            if (stos || movs) {
4455                                    uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4456                                    if (mode67 == 16)
4457                                            addr &= 0xffff;
4458                                    if (mode67 == 32)
4459                                            addr &= 0xffffffff;
4460                                    cpu->cd.x86.cursegment = X86_S_ES;
4461                                    if (!x86_store(cpu, addr, value, len))
4462                                            return 0;
4463                            }
4464                            if (cmps || scas) {
4465                                    uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4466                                    if (mode67 == 16)
4467                                            addr &= 0xffff;
4468                                    if (mode67 == 32)
4469                                            addr &= 0xffffffff;
4470                                    cpu->cd.x86.cursegment = X86_S_ES;
4471                                    if (!x86_load(cpu, addr, &tmp, len))
4472                                            return 0;
4473    
4474                                    x86_calc_flags(cpu, value, tmp, len*8,
4475                                        CALCFLAGS_OP_SUB);
4476                            }
4477    
4478                            if (movs || lods || cmps) {
4479                                    /*  Modify esi:  */
4480                                    if (mode67 == 16)
4481                                            cpu->cd.x86.r[X86_R_SI] =
4482                                                (cpu->cd.x86.r[X86_R_SI] & ~0xffff)
4483                                                | ((cpu->cd.x86.r[X86_R_SI]+len*dir)
4484                                                & 0xffff);
4485                                    else {
4486                                            cpu->cd.x86.r[X86_R_SI] += len*dir;
4487                                            if (mode67 == 32)
4488                                                    cpu->cd.x86.r[X86_R_SI] &=
4489                                                        0xffffffff;
4490                                    }
4491                            }
4492    
4493                            if (!lods) {
4494                                    /*  Modify edi:  */
4495                                    if (mode67 == 16)
4496                                            cpu->cd.x86.r[X86_R_DI] =
4497                                                (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4498                                                | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4499                                                & 0xffff);
4500                                    else {
4501                                            cpu->cd.x86.r[X86_R_DI] += len*dir;
4502                                            if (mode67 == 32)
4503                                                    cpu->cd.x86.r[X86_R_DI] &=
4504                                                        0xffffffff;
4505                                    }
4506                            }
4507    
4508                            if (rep) {
4509                                    /*  Decrement ecx:  */
4510                                    if (mode67 == 16)
4511                                            cpu->cd.x86.r[X86_R_CX] =
4512                                                (cpu->cd.x86.r[X86_R_CX] & ~0xffff)
4513                                                | ((cpu->cd.x86.r[X86_R_CX] - 1)
4514                                                & 0xffff);
4515                                    else {
4516                                            cpu->cd.x86.r[X86_R_CX] --;
4517                                            cpu->cd.x86.r[X86_R_CX] &= 0xffffffff;
4518                                    }
4519                                    if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
4520                                        0xffff) == 0)
4521                                            rep = 0;
4522                                    if (mode67 != 16 &&
4523                                        cpu->cd.x86.r[X86_R_CX] == 0)
4524                                            rep = 0;
4525    
4526                                    if (cmps || scas) {
4527                                            if (rep == REP_REP && !(
4528                                                cpu->cd.x86.rflags & X86_FLAGS_ZF))
4529                                                    rep = 0;
4530                                            if (rep == REP_REPNE &&
4531                                                cpu->cd.x86.rflags & X86_FLAGS_ZF)
4532                                                    rep = 0;
4533                                    }
4534                            }
4535                    } while (rep);
4536            } else if (op >= 0xa8 && op <= 0xa9) {          /* TEST al/[e]ax,imm */
4537                    op1 = cpu->cd.x86.r[X86_R_AX];
4538                    op2 = read_imm(&instr, &newpc, op==0xa8? 8 : mode);
4539                    op1 &= op2;
4540                    x86_calc_flags(cpu, op1, 0, op==0xa8? 8 : mode,
4541                        CALCFLAGS_OP_XOR);
4542                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4543                    cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4544            } else if (op >= 0xb0 && op <= 0xb3) {          /*  MOV Xl,imm  */
4545                    imm = read_imm(&instr, &newpc, 8);
4546                    cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff)
4547                        | (imm & 0xff);
4548            } else if (op >= 0xb4 && op <= 0xb7) {          /*  MOV Xh,imm  */
4549                    imm = read_imm(&instr, &newpc, 8);
4550                    cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff00)
4551                        | ((imm & 0xff) << 8);
4552            } else if (op >= 0xb8 && op <= 0xbf) {          /*  MOV Xx,imm  */
4553                    imm = read_imm(&instr, &newpc, mode);
4554                    cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7], imm);
4555            } else if (op == 0xc0 || op == 0xc1) {          /*  Shift/Rotate  */
4556                    int n = 1;
4557                    instr_orig = instr;
4558                    success = modrm(cpu, MODRM_READ, mode, mode67,
4559                        op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4560                    if (!success)
4561                            return 0;
4562                    n = read_imm(&instr, &newpc, 8);
4563                    x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4564                        n, op&1? mode : 8);
4565                    success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4566                        op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4567                    if (!success)
4568                            return 0;
4569            } else if (op == 0xc2 || op == 0xc3) {  /*  RET near  */
4570                    uint64_t popped_pc;
4571                    if (!x86_pop(cpu, &popped_pc, mode))
4572                            return 0;
4573                    if (op == 0xc2) {
4574                            imm = read_imm(&instr, &newpc, 16);
4575                            cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[
4576                                X86_R_SP], cpu->cd.x86.r[X86_R_SP] + imm);
4577                    }
4578                    newpc = popped_pc;
4579            } else if (op == 0xc4 || op == 0xc5) {          /*  LDS,LES  */
4580                    instr_orig = instr;
4581                    if (!modrm(cpu, MODRM_READ, mode, mode67,
4582                        MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4583                            return 0;
4584                    /*  op1 is the address to load from  */
4585                    if (!x86_load(cpu, op1, &tmp, mode/8))
4586                            return 0;
4587                    op2 = tmp;
4588                    if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
4589                            return 0;
4590                    reload_segment_descriptor(cpu, op==0xc4? X86_S_ES:X86_S_DS,
4591                        tmp, &newpc);
4592                    if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4593                        0, &instr_orig, NULL, &op1, &op2))
4594                            return 0;
4595            } else if (op >= 0xc6 && op <= 0xc7) {
4596                    switch ((*instr >> 3) & 0x7) {
4597                    case 0: instr_orig = instr;             /*  MOV r/m, imm  */
4598                            success = modrm(cpu, MODRM_READ, mode, mode67,
4599                                op == 0xc6? MODRM_EIGHTBIT : 0, &instr,
4600                                &newpc, &op1, &op2);
4601                            if (!success)
4602                                    return 0;
4603                            imm = read_imm(&instr, &newpc, op == 0xc6? 8 : mode);
4604                            op1 = imm;
4605                            success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4606                                op == 0xc6? MODRM_EIGHTBIT : 0, &instr_orig,
4607                                NULL, &op1, &op2);
4608                            if (!success)
4609                                    return 0;
4610                            break;
4611                    default:
4612                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4613                            quiet_mode = 0;
4614                            x86_cpu_disassemble_instr(cpu,
4615                                really_orig_instr, 1|omode, 0, 0);
4616                            cpu->running = 0;
4617                    }
4618            } else if (op == 0xc8) {        /*  ENTER  */
4619                    uint64_t tmp_frame_ptr;
4620                    int level;
4621                    imm = read_imm(&instr, &newpc, 16);
4622                    level = read_imm(&instr, &newpc, 8);
4623                    if (!x86_push(cpu, cpu->cd.x86.r[X86_R_BP], mode))
4624                            return 0;
4625                    tmp_frame_ptr = cpu->cd.x86.r[X86_R_SP];
4626                    if (level > 0) {
4627                            while (level-- > 1) {
4628                                    uint64_t tmpword;
4629                                    cpu->cd.x86.r[X86_R_BP] = modify(
4630                                        cpu->cd.x86.r[X86_R_BP],
4631                                        cpu->cd.x86.r[X86_R_BP] - mode/8);
4632                                    cpu->cd.x86.cursegment = X86_S_SS;
4633                                    if (!x86_load(cpu, cpu->cd.x86.r[X86_R_BP],
4634                                        &tmpword, mode/8)) {
4635                                            fatal("TODO: load error inside"
4636                                                " ENTER\n");
4637                                            cpu->running = 0;
4638                                            return 0;
4639                                    }
4640                                    if (!x86_push(cpu, tmpword, mode)) {
4641                                            fatal("TODO: push error inside"
4642                                                " ENTER\n");
4643                                            cpu->running = 0;
4644                                            return 0;
4645                                    }
4646                            }
4647                            if (!x86_push(cpu, tmp_frame_ptr, mode))
4648                                    return 0;
4649                    }
4650                    cpu->cd.x86.r[X86_R_BP] = modify(cpu->cd.x86.r[X86_R_BP],
4651                        tmp_frame_ptr);
4652                    if (mode == 16)
4653                            cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
4654                                ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] & 0xffff)
4655                                - imm);
4656                    else
4657                            cpu->cd.x86.r[X86_R_SP] -= imm;
4658            } else if (op == 0xc9) {        /*  LEAVE  */
4659                    cpu->cd.x86.r[X86_R_SP] = cpu->cd.x86.r[X86_R_BP];
4660                    if (!x86_pop(cpu, &tmp, mode)) {
4661                            fatal("TODO: pop error inside LEAVE\n");
4662                            cpu->running = 0;
4663                            return 0;
4664                    }
4665                    cpu->cd.x86.r[X86_R_BP] = tmp;
4666            } else if (op == 0xca || op == 0xcb) {  /*  RET far  */
4667                    uint64_t tmp2;
4668                    uint16_t old_tr = cpu->cd.x86.tr;
4669                    if (op == 0xca)
4670                            imm = read_imm(&instr, &newpc, 16);
4671                    else
4672                            imm = 0;
4673                    if (!x86_pop(cpu, &tmp, mode))
4674                            return 0;
4675                    if (!x86_pop(cpu, &tmp2, mode)) {
4676                            fatal("TODO: pop error inside RET\n");
4677                            cpu->running = 0;
4678                            return 0;
4679                    }
4680                    cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[X86_R_SP],
4681                        cpu->cd.x86.r[X86_R_SP] + imm);
4682                    reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4683                    if (cpu->cd.x86.tr == old_tr)
4684                            newpc = tmp;
4685          } else if (op == 0xcc) {        /*  INT3  */          } else if (op == 0xcc) {        /*  INT3  */
4686                  cpu->pc = newpc;                  cpu->pc = newpc;
4687                  return x86_interrupt(cpu, 3);                  return x86_interrupt(cpu, 3, 0);
4688          } else if (op == 0xcd) {        /*  INT  */          } else if (op == 0xcd) {        /*  INT  */
4689                  imm = read_imm(&instr, &newpc, 8);                  imm = read_imm(&instr, &newpc, 8);
4690                  cpu->pc = newpc;                  cpu->pc = newpc;
4691                  return x86_interrupt(cpu, imm);                  return x86_interrupt(cpu, imm, 0);
4692            } else if (op == 0xcf) {        /*  IRET  */
4693                    uint64_t tmp2, tmp3;
4694                    uint16_t old_tr = cpu->cd.x86.tr;
4695                    if (!x86_pop(cpu, &tmp, mode))
4696                            return 0;
4697                    if (!x86_pop(cpu, &tmp2, mode))
4698                            return 0;
4699                    if (!x86_pop(cpu, &tmp3, mode))
4700                            return 0;
4701    debug("{ iret to 0x%04x:0x%08x }\n", (int)tmp2,(int)tmp);
4702                    tmp2 &= 0xffff;
4703                    /*  TODO: only affect some bits?  */
4704                    if (mode == 16)
4705                            cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4706                                | (tmp3 & 0xffff);
4707                    else
4708                            cpu->cd.x86.rflags = tmp3;
4709                    /*
4710                     *  In protected mode, if we're switching back from, say, an
4711                     *  interrupt handler, then we should pop the old ss:esp too:
4712                     */
4713                    if (PROTECTED_MODE && (tmp2 & X86_PL_MASK) >
4714                        (cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK)) {
4715                            uint64_t old_ss, old_esp;
4716                            if (!x86_pop(cpu, &old_esp, mode))
4717                                    return 0;
4718                            if (!x86_pop(cpu, &old_ss, mode))
4719                                    return 0;
4720                            old_ss &= 0xffff;
4721    
4722    printf(": : : BEFORE tmp=%016llx tmp2=%016llx tmp3=%016llx\n",
4723    (long long)tmp, (long long)tmp2, (long long)tmp3);
4724    /* x86_cpu_register_dump(cpu, 1, 1); */
4725    
4726                            reload_segment_descriptor(cpu, X86_S_SS, old_ss,
4727                                &newpc);
4728                            cpu->cd.x86.r[X86_R_SP] = old_esp;
4729    
4730    /* printf(": : : AFTER\n");
4731    x86_cpu_register_dump(cpu, 1, 1); */
4732    
4733                            /*  AFTER popping ss, check that the pl of
4734                                the popped ss is the same as tmp2 (the new
4735                                pl in cs)!  */
4736                            if ((old_ss & X86_PL_MASK) != (tmp2 & X86_PL_MASK))
4737                                    fatal("WARNING: iret: popped ss' pl = %i,"
4738                                        " different from cs' pl = %i\n",
4739                                        (int)(old_ss & X86_PL_MASK),
4740                                        (int)(tmp2 & X86_PL_MASK));
4741                    }
4742                    reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4743                    if (cpu->cd.x86.tr == old_tr)
4744                            newpc = tmp;
4745            } else if (op >= 0xd0 && op <= 0xd3) {
4746                    int n = 1;
4747                    instr_orig = instr;
4748                    success = modrm(cpu, MODRM_READ, mode, mode67,
4749                        op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4750                    if (!success)
4751                            return 0;
4752                    if (op >= 0xd2)
4753                            n = cpu->cd.x86.r[X86_R_CX];
4754                    x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4755                        n, op&1? mode : 8);
4756                    success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4757                        op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4758                    if (!success)
4759                            return 0;
4760            } else if (op == 0xd4) {        /*  AAM  */
4761                    int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4762                    /*  al should be in the range 0..81  */
4763                    int high;
4764                    imm = read_imm(&instr, &newpc, 8);
4765                    if (imm == 0) {
4766                            fatal("[ x86: \"aam 0\" ]\n");
4767                            cpu->running = 0;
4768                    } else {
4769                            high = al / imm;
4770                            al %= imm;
4771                            cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4772                                ~0xffff) | al | ((high & 0xff) << 8);
4773                            x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4774                                0, 8, CALCFLAGS_OP_XOR);
4775                    }
4776            } else if (op == 0xd5) {        /*  AAD  */
4777                    int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4778                    int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
4779                    imm = read_imm(&instr, &newpc, 8);
4780                    cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4781                        | ((al + 10*ah) & 0xff);
4782                    x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4783                        0, 8, CALCFLAGS_OP_XOR);
4784            } else if (op == 0xd7) {                /*  XLAT  */
4785                    uint64_t addr = cpu->cd.x86.r[X86_R_BX];
4786                    if (mode == 16)
4787                            addr &= 0xffff;
4788                    addr += (cpu->cd.x86.r[X86_R_AX] & 0xff);
4789                    if (!x86_load(cpu, addr, &tmp, 1))
4790                            return 0;
4791                    cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4792                        | (tmp & 0xff);
4793            } else if (op == 0xd9) {
4794                    int subop = (*instr >> 3) & 7;
4795                    imm = *instr;
4796                    if (subop == 5) {                       /*  FLDCW mem16  */
4797                            if (!modrm(cpu, MODRM_READ, 16, mode67, 0, &instr,
4798                                &newpc, &op1, &op2))
4799                                    return 0;
4800                            cpu->cd.x86.fpu_cw = op1;
4801                    } else if (subop == 7) {                /*  FSTCW mem16  */
4802                            op1 = cpu->cd.x86.fpu_cw;
4803                            if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4804                                &newpc, &op1, &op2))
4805                                    return 0;
4806                    } else {
4807                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4808                            quiet_mode = 0;
4809                            x86_cpu_disassemble_instr(cpu, really_orig_instr,
4810                                1 | omode, 0, 0);
4811                            cpu->running = 0;
4812                    }
4813            } else if (op == 0xdb) {
4814                    imm = *instr;
4815                    if (imm == 0xe2) {                      /*  FCLEX  */
4816                            read_imm(&instr, &newpc, 8);
4817                            /*  TODO: actually clear exceptions  */
4818                    } else if (imm == 0xe3) {               /*  FINIT  */
4819                            read_imm(&instr, &newpc, 8);
4820                            /*  TODO: actually init?  */
4821                    } else if (imm == 0xe4) {               /*  FSETPM  */
4822                            read_imm(&instr, &newpc, 8);
4823                    } else {
4824                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4825                            quiet_mode = 0;
4826                            x86_cpu_disassemble_instr(cpu, really_orig_instr,
4827                                1 | omode, 0, 0);
4828                            cpu->running = 0;
4829                    }
4830            } else if (op == 0xdd) {
4831                    int subop = (*instr >> 3) & 7;
4832                    imm = *instr;
4833                    if (subop == 7) {               /*  FSTSW mem16  */
4834                            op1 = cpu->cd.x86.fpu_sw;
4835                            if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4836                                &newpc, &op1, &op2))
4837                                    return 0;
4838                    } else {
4839                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4840                            quiet_mode = 0;
4841                            x86_cpu_disassemble_instr(cpu, really_orig_instr,
4842                                1 | omode, 0, 0);
4843                            cpu->running = 0;
4844                    }
4845            } else if (op == 0xdf) {
4846                    imm = *instr;
4847                    if (imm == 0xe0) {              /*  FSTSW  */
4848                            read_imm(&instr, &newpc, 8);
4849                            cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4850                                ~0xffff) | (cpu->cd.x86.fpu_sw & 0xffff);
4851                    } else {
4852                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4853                            quiet_mode = 0;
4854                            x86_cpu_disassemble_instr(cpu, really_orig_instr,
4855                                1 | omode, 0, 0);
4856                            cpu->running = 0;
4857                    }
4858            } else if (op == 0xe4 || op == 0xe5     /*  IN imm,AL or AX/EAX  */
4859                || op == 0x6c || op == 0x6d) {      /*  INSB or INSW/INSD  */
4860                    unsigned char databuf[8];
4861                    int port_nr, ins = 0, len = 1, dir = 1;
4862                    if (op == 0x6c || op == 0x6d) {
4863                            port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4864                            ins = 1;
4865                    } else
4866                            port_nr = read_imm(&instr, &newpc, 8);
4867                    if (op & 1)
4868                            len = mode/8;
4869                    if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4870                            dir = -1;
4871                    do {
4872                            cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
4873                                &databuf[0], len, MEM_READ, CACHE_NONE | PHYSICAL);
4874    
4875                            if (ins) {
4876                                    uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4877                                    uint32_t value = databuf[0] + (databuf[1] << 8)
4878                                        + (databuf[2] << 16) + (databuf[3] << 24);
4879                                    if (mode67 == 16)
4880                                            addr &= 0xffff;
4881                                    if (mode67 == 32)
4882                                            addr &= 0xffffffff;
4883                                    cpu->cd.x86.cursegment = X86_S_ES;
4884                                    if (!x86_store(cpu, addr, value, len))
4885                                            return 0;
4886    
4887                                    /*  Advance (e)di:  */
4888                                    if (mode67 == 16)
4889                                            cpu->cd.x86.r[X86_R_DI] =
4890                                                (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4891                                                | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4892                                                & 0xffff);
4893                                    else {
4894                                            cpu->cd.x86.r[X86_R_DI] += len*dir;
4895                                            if (mode67 == 32)
4896                                                    cpu->cd.x86.r[X86_R_DI] &=
4897                                                        0xffffffff;
4898                                    }
4899    
4900                                    if (rep) {
4901                                            /*  Decrement ecx:  */
4902                                            if (mode67 == 16)
4903                                                    cpu->cd.x86.r[X86_R_CX] =
4904                                                        (cpu->cd.x86.r[X86_R_CX] &
4905                                                        ~0xffff) | ((cpu->cd.x86.r[
4906                                                        X86_R_CX] - 1) & 0xffff);
4907                                            else {
4908                                                    cpu->cd.x86.r[X86_R_CX] --;
4909                                                    cpu->cd.x86.r[X86_R_CX] &=
4910                                                        0xffffffff;
4911                                            }
4912                                            if (mode67 == 16 && (cpu->cd.x86.r[
4913                                                X86_R_CX] & 0xffff) == 0)
4914                                                    rep = 0;
4915                                            if (mode67 != 16 &&
4916                                                cpu->cd.x86.r[X86_R_CX] == 0)
4917                                                    rep = 0;
4918                                    }
4919                            } else {
4920                                    if (len == 1)
4921                                            cpu->cd.x86.r[X86_R_AX] =
4922                                                (cpu->cd.x86.r[X86_R_AX] &
4923                                                ~0xff) | databuf[0];
4924                                    else if (len == 2)
4925                                            cpu->cd.x86.r[X86_R_AX] =
4926                                                (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4927                                                | databuf[0] | (databuf[1] << 8);
4928                                    else if (len == 4)
4929                                            cpu->cd.x86.r[X86_R_AX] = databuf[0] |
4930                                                (databuf[1] << 8) | (databuf[2]
4931                                                << 16) | (databuf[3] << 24);
4932                            }
4933                    } while (rep);
4934            } else if (op == 0xe6 || op == 0xe7     /*  OUT imm,AL or AX/EAX  */
4935                || op == 0x6e || op == 0x6f) {      /*  OUTSB or OUTSW/OUTSD  */
4936                    unsigned char databuf[8];
4937                    int port_nr, outs = 0, len = 1, dir = 1;
4938                    if (op == 0x6e || op == 0x6f) {
4939                            port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4940                            outs = 1;
4941                    } else
4942                            port_nr = read_imm(&instr, &newpc, 8);
4943                    if (op & 1)
4944                            len = mode/8;
4945                    if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4946                            dir = -1;
4947                    do {
4948                            if (outs) {
4949                                    int i;
4950                                    uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4951                                    uint64_t value;
4952                                    if (mode67 == 16)
4953                                            addr &= 0xffff;
4954                                    if (mode67 == 32)
4955                                            addr &= 0xffffffff;
4956                                    cpu->cd.x86.cursegment = X86_S_ES;
4957                                    if (!x86_load(cpu, addr, &value, len))
4958                                            return 0;
4959    
4960                                    /*  Advance (e)di:  */
4961                                    if (mode67 == 16)
4962                                            cpu->cd.x86.r[X86_R_DI] =
4963                                                (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4964                                                | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4965                                                & 0xffff);
4966                                    else {
4967                                            cpu->cd.x86.r[X86_R_DI] += len*dir;
4968                                            if (mode67 == 32)
4969                                                    cpu->cd.x86.r[X86_R_DI] &=
4970                                                        0xffffffff;
4971                                    }
4972    
4973                                    for (i=0; i<8; i++)
4974                                            databuf[i] = value >> (i*8);
4975    
4976                                    if (rep) {
4977                                            /*  Decrement ecx:  */
4978                                            if (mode67 == 16)
4979                                                    cpu->cd.x86.r[X86_R_CX] =
4980                                                        (cpu->cd.x86.r[X86_R_CX] &
4981                                                        ~0xffff) | ((cpu->cd.x86.r[
4982                                                        X86_R_CX] - 1) & 0xffff);
4983                                            else {
4984                                                    cpu->cd.x86.r[X86_R_CX] --;
4985                                                    cpu->cd.x86.r[X86_R_CX] &=
4986                                                        0xffffffff;
4987                                            }
4988                                            if (mode67 == 16 && (cpu->cd.x86.r[
4989                                                X86_R_CX] & 0xffff) == 0)
4990                                                    rep = 0;
4991                                            if (mode67 != 16 &&
4992                                                cpu->cd.x86.r[X86_R_CX] == 0)
4993                                                    rep = 0;
4994                                    }
4995                            } else {
4996                                    int i;
4997                                    for (i=0; i<8; i++)
4998                                            databuf[i] = cpu->cd.x86.r[X86_R_AX]
4999                                                >> (i*8);
5000                            }
5001    
5002                            cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
5003                                &databuf[0], len, MEM_WRITE, CACHE_NONE | PHYSICAL);
5004                    } while (rep);
5005            } else if (op == 0xe8 || op == 0xe9) {  /*  CALL/JMP near  */
5006                    imm = read_imm(&instr, &newpc, mode);
5007                    if (mode == 16)
5008                            imm = (int16_t)imm;
5009                    if (mode == 32)
5010                            imm = (int32_t)imm;
5011                    if (op == 0xe8) {
5012                            if (!x86_push(cpu, newpc, mode))
5013                                    return 0;
5014                    }
5015                    newpc += imm;
5016          } else if (op == 0xea) {        /*  JMP seg:ofs  */          } else if (op == 0xea) {        /*  JMP seg:ofs  */
5017                    uint16_t old_tr = cpu->cd.x86.tr;
5018                  imm = read_imm(&instr, &newpc, mode);                  imm = read_imm(&instr, &newpc, mode);
5019                  imm2 = read_imm(&instr, &newpc, 16);                  imm2 = read_imm(&instr, &newpc, 16);
5020                  cpu->cd.x86.s[X86_S_CS] = imm2;                  reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
5021                  newpc = modify(cpu->pc, imm);                  if (cpu->cd.x86.tr == old_tr)
5022          } else if (op == 0xeb) {        /*  JMP short  */                          newpc = imm;
5023            } else if ((op >= 0xe0 && op <= 0xe3) || op == 0xeb) {  /*  LOOP,JMP */
5024                    int perform_jump = 0;
5025                  imm = read_imm(&instr, &newpc, 8);                  imm = read_imm(&instr, &newpc, 8);
5026                  newpc = modify(newpc, newpc + (signed char)imm);                  switch (op) {
5027                    case 0xe0:      /*  loopnz  */
5028                    case 0xe1:      /*  loopz  */
5029                    case 0xe2:      /*  loop  */
5030                            /*  NOTE: address size attribute, not operand size?  */
5031                            if (mode67 == 16)
5032                                    cpu->cd.x86.r[X86_R_CX] = (~0xffff &
5033                                        cpu->cd.x86.r[X86_R_CX]) |
5034                                        ((cpu->cd.x86.r[X86_R_CX] - 1) & 0xffff);
5035                            else
5036                                    cpu->cd.x86.r[X86_R_CX] --;
5037                            if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
5038                                0xffff) != 0)
5039                                    perform_jump = 1;
5040                            if (mode67 == 32 && cpu->cd.x86.r[X86_R_CX] != 0)
5041                                    perform_jump = 1;
5042                            if (op == 0xe0 && cpu->cd.x86.rflags & X86_FLAGS_ZF)
5043                                    perform_jump = 0;
5044                            if (op == 0xe1 && (!cpu->cd.x86.rflags & X86_FLAGS_ZF))
5045                                    perform_jump = 0;
5046                            break;
5047                    case 0xe3:      /*  jcxz/jecxz  */
5048                            if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & 0xffff)
5049                                == 0)
5050                                    perform_jump = 1;
5051                            if (mode67 != 16 && (cpu->cd.x86.r[X86_R_CX] &
5052                                0xffffffffULL) == 0)
5053                                    perform_jump = 1;
5054                            break;
5055                    case 0xeb:      /*  jmp  */
5056                            perform_jump = 1;
5057                            break;
5058                    }
5059                    if (perform_jump)
5060                            newpc += (signed char)imm;
5061            } else if (op == 0xec || op == 0xed) {  /*  IN DX,AL or AX/EAX  */
5062                    unsigned char databuf[8];
5063                    cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5064                        (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5065                        op == 0xec? 1 : (mode/8), MEM_READ, CACHE_NONE | PHYSICAL);
5066                    if (op == 0xec)
5067                            cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5068                                ~0xff) | databuf[0];
5069                    else if (op == 0xed && mode == 16)
5070                            cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5071                                ~0xffff) | databuf[0] | (databuf[1] << 8);
5072                    else if (op == 0xed && mode == 32)
5073                            cpu->cd.x86.r[X86_R_AX] = databuf[0] |
5074                                (databuf[1] << 8) | (databuf[2] << 16) |
5075                                (databuf[3] << 24);
5076            } else if (op == 0xee || op == 0xef) {  /*  OUT DX,AL or AX/EAX  */
5077                    unsigned char databuf[8];
5078                    databuf[0] = cpu->cd.x86.r[X86_R_AX];
5079                    if (op == 0xef) {
5080                            databuf[1] = cpu->cd.x86.r[X86_R_AX] >> 8;
5081                            if (mode >= 32) {
5082                                    databuf[2] = cpu->cd.x86.r[X86_R_AX] >> 16;
5083                                    databuf[3] = cpu->cd.x86.r[X86_R_AX] >> 24;
5084                            }
5085                    }
5086                    cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5087                        (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5088                        op == 0xee? 1 : (mode/8), MEM_WRITE, CACHE_NONE | PHYSICAL);
5089            } else if (op == 0xf4) {        /*  HLT  */
5090                    cpu->cd.x86.halted = 1;
5091            } else if (op == 0xf5) {        /*  CMC  */
5092                    cpu->cd.x86.rflags ^= X86_FLAGS_CF;
5093          } else if (op == 0xf8) {        /*  CLC  */          } else if (op == 0xf8) {        /*  CLC  */
5094                  cpu->cd.x86.rflags &= ~X86_FLAGS_CF;                  cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5095          } else if (op == 0xf9) {        /*  STC  */          } else if (op == 0xf9) {        /*  STC  */
# Line 878  int x86_cpu_run_instr(struct emul *emul, Line 5102  int x86_cpu_run_instr(struct emul *emul,
5102                  cpu->cd.x86.rflags &= ~X86_FLAGS_DF;                  cpu->cd.x86.rflags &= ~X86_FLAGS_DF;
5103          } else if (op == 0xfd) {        /*  STD  */          } else if (op == 0xfd) {        /*  STD  */
5104                  cpu->cd.x86.rflags |= X86_FLAGS_DF;                  cpu->cd.x86.rflags |= X86_FLAGS_DF;
5105            } else if (op == 0xf6 || op == 0xf7) {          /*  MUL, DIV etc  */
5106                    uint64_t res;
5107                    int unsigned_op = 1;
5108                    switch ((*instr >> 3) & 0x7) {
5109                    case 0: /*  test  */
5110                            success = modrm(cpu, MODRM_READ, mode, mode67,
5111                                op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5112                                &newpc, &op1, &op2);
5113                            if (!success)
5114                                    return 0;
5115                            op2 = read_imm(&instr, &newpc, op==0xf6? 8 : mode);
5116                            op1 &= op2;
5117                            x86_calc_flags(cpu, op1, 0, op==0xf6? 8 : mode,
5118                                CALCFLAGS_OP_XOR);
5119                            break;
5120                    case 2: /*  not  */
5121                    case 3: /*  neg  */
5122                            instr_orig = instr;
5123                            success = modrm(cpu, MODRM_READ, mode, mode67,
5124                                op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5125                                &newpc, &op1, &op2);
5126                            if (!success)
5127                                    return 0;
5128                            switch ((*instr_orig >> 3) & 0x7) {
5129                            case 2: op1 ^= 0xffffffffffffffffULL; break;
5130                            case 3: x86_calc_flags(cpu, 0, op1,
5131                                        op == 0xf6? 8 : mode, CALCFLAGS_OP_SUB);
5132                                    op1 = 0 - op1;
5133                                    cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5134                                    if (op1 != 0)
5135                                            cpu->cd.x86.rflags |= X86_FLAGS_CF;
5136                                    break;
5137                            }
5138                            success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5139                                op == 0xf6? MODRM_EIGHTBIT : 0, &instr_orig,
5140                                NULL, &op1, &op2);
5141                            if (!success)
5142                                    return 0;
5143                            break;
5144                    case 5: /*  imul  */
5145                            unsigned_op = 0;
5146                    case 4: /*  mul  */
5147                            success = modrm(cpu, MODRM_READ, mode, mode67,
5148                                op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5149                                &newpc, &op1, &op2);
5150                            if (!success)
5151                                    return 0;
5152                            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5153                            cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
5154                            if (op == 0xf6) {
5155                                    if (unsigned_op)
5156                                            res = (cpu->cd.x86.r[X86_R_AX] & 0xff)
5157                                                * (op1 & 0xff);
5158                                    else
5159                                            res = (int16_t)(signed char)(cpu->cd.
5160                                                x86.r[X86_R_AX] & 0xff) * (int16_t)
5161                                                (signed char)(op1 & 0xff);
5162                                    cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
5163                                        X86_R_AX] & ~0xffff) | (res & 0xffff);
5164                                    if ((res & 0xffff) >= 0x100)
5165                                            cpu->cd.x86.rflags |= X86_FLAGS_CF
5166                                                | X86_FLAGS_OF;
5167                            } else if (mode == 16) {
5168                                    if (unsigned_op)
5169                                            res = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5170                                                * (op1 & 0xffff);
5171                                    else
5172                                            res = (int32_t)(int16_t)(cpu->cd.x86.r[
5173                                                X86_R_AX] & 0xffff) * (int32_t)
5174                                                (int16_t)(op1 & 0xffff);
5175                                    cpu->cd.x86.r[X86_R_AX] = modify(cpu->
5176                                        cd.x86.r[X86_R_AX], res & 0xffff);
5177                                    cpu->cd.x86.r[X86_R_DX] = modify(cpu->cd.x86
5178                                        .r[X86_R_DX], (res>>16) & 0xffff);
5179                                    if ((res & 0xffffffff) >= 0x10000)
5180                                            cpu->cd.x86.rflags |= X86_FLAGS_CF
5181                                                | X86_FLAGS_OF;
5182                            } else if (mode == 32) {
5183                                    if (unsigned_op)
5184                                            res = (cpu->cd.x86.r[X86_R_AX] &
5185                                                0xffffffff) * (op1 & 0xffffffff);
5186                                    else
5187                                            res = (int64_t)(int32_t)(cpu->cd.x86.r[
5188                                                X86_R_AX] & 0xffffffff) * (int64_t)
5189                                                (int32_t)(op1 & 0xffffffff);
5190                                    cpu->cd.x86.r[X86_R_AX] = res & 0xffffffff;
5191                                    cpu->cd.x86.r[X86_R_DX] = (res >> 32) &
5192                                        0xffffffff;
5193                                    if (res >= 0x100000000ULL)
5194                                            cpu->cd.x86.rflags |= X86_FLAGS_CF
5195                                                | X86_FLAGS_OF;
5196                            }
5197                            break;
5198                    case 7: /*  idiv  */
5199                            unsigned_op = 0;
5200                    case 6: /*  div  */
5201                            success = modrm(cpu, MODRM_READ, mode, mode67,
5202                                op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5203                                &newpc, &op1, &op2);
5204                            if (!success)
5205                                    return 0;
5206                            if (op1 == 0) {
5207                                    fatal("TODO: division by zero\n");
5208                                    cpu->running = 0;
5209                                    break;
5210                            }
5211                            if (op == 0xf6) {
5212                                    int al, ah;
5213                                    if (unsigned_op) {
5214                                            al = (cpu->cd.x86.r[X86_R_AX] &
5215                                                0xffff) / op1;
5216                                            ah = (cpu->cd.x86.r[X86_R_AX] &
5217                                                0xffff) % op1;
5218                                    } else {
5219                                            al = (int16_t)(cpu->cd.x86.r[
5220                                                X86_R_AX] & 0xffff) / (int16_t)op1;
5221                                            ah = (int16_t)(cpu->cd.x86.r[
5222                                                X86_R_AX] & 0xffff) % (int16_t)op1;
5223                                    }
5224                                    cpu->cd.x86.r[X86_R_AX] = modify(
5225                                        cpu->cd.x86.r[X86_R_AX], (ah<<8) + al);
5226                            } else if (mode == 16) {
5227                                    uint64_t a = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5228                                        + ((cpu->cd.x86.r[X86_R_DX] & 0xffff)<<16);
5229                                    uint32_t ax, dx;
5230                                    if (unsigned_op) {
5231                                            ax = a / op1, dx = a % op1;
5232                                    } else {
5233                                            ax = (int32_t)a / (int32_t)op1;
5234                                            dx = (int32_t)a % (int32_t)op1;
5235                                    }
5236                                    cpu->cd.x86.r[X86_R_AX] = modify(
5237                                        cpu->cd.x86.r[X86_R_AX], ax);
5238                                    cpu->cd.x86.r[X86_R_DX] = modify(
5239                                        cpu->cd.x86.r[X86_R_DX], dx);
5240                            } else if (mode == 32) {
5241                                    uint64_t a = (cpu->cd.x86.r[X86_R_AX] &
5242                                        0xffffffffULL) + ((cpu->cd.x86.r[
5243                                        X86_R_DX] & 0xffffffffULL) << 32);
5244                                    uint32_t eax, edx;
5245                                    if (unsigned_op) {
5246                                            eax = (uint64_t)a / (uint32_t)op1;
5247                                            edx = (uint64_t)a % (uint32_t)op1;
5248                                    } else {
5249                                            eax = (int64_t)a / (int32_t)op1;
5250                                            edx = (int64_t)a % (int32_t)op1;
5251                                    }
5252                                    cpu->cd.x86.r[X86_R_AX] = eax;
5253                                    cpu->cd.x86.r[X86_R_DX] = edx;
5254                            }
5255                            break;
5256                    default:
5257                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
5258                            quiet_mode = 0;
5259                            x86_cpu_disassemble_instr(cpu,
5260                                really_orig_instr, 1|omode, 0, 0);
5261                            cpu->running = 0;
5262                    }
5263            } else if (op == 0xfe || op == 0xff) {          /*  INC, DEC etc  */
5264                    int old_cf;
5265                    switch ((*instr >> 3) & 0x7) {
5266                    case 0:
5267                    case 1: instr_orig = instr;
5268                            success = modrm(cpu, MODRM_READ, mode, mode67,
5269                                op == 0xfe? MODRM_EIGHTBIT : 0, &instr,
5270                                &newpc, &op1, &op2);
5271                            if (!success)
5272                                    return 0;
5273                            old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
5274                            switch ((*instr_orig >> 3) & 0x7) {
5275                            case 0: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5276                                        CALCFLAGS_OP_ADD);
5277                                    op1 ++;
5278                                    break; /* inc */
5279                            case 1: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5280                                        CALCFLAGS_OP_SUB);
5281                                    op1 --;
5282                                    break; /* dec */
5283                            }
5284                            success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5285                                op == 0xfe? MODRM_EIGHTBIT : 0, &instr_orig,
5286                                NULL, &op1, &op2);
5287                            if (!success)
5288                                    return 0;
5289                            /*  preserve CF:  */
5290                            cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5291                            cpu->cd.x86.rflags |= old_cf;
5292                            break;
5293                    case 2: if (op == 0xfe) {
5294                                    fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5295                                        *instr);
5296                                    quiet_mode = 0;
5297                                    x86_cpu_disassemble_instr(cpu,
5298                                        really_orig_instr, 1|omode, 0, 0);
5299                                    cpu->running = 0;
5300                            } else {
5301                                    success = modrm(cpu, MODRM_READ, mode, mode67,
5302                                        0, &instr, &newpc, &op1, &op2);
5303                                    if (!success)
5304                                            return 0;
5305                                    /*  Push return [E]IP  */
5306                                    if (!x86_push(cpu, newpc, mode))
5307                                            return 0;
5308                                    newpc = op1;
5309                            }
5310                            break;
5311                    case 3: if (op == 0xfe) {
5312                                    fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5313                                        *instr);
5314                                    quiet_mode = 0;
5315                                    x86_cpu_disassemble_instr(cpu,
5316                                        really_orig_instr, 1|omode, 0, 0);
5317                                    cpu->running = 0;
5318                            } else {
5319                                    uint16_t old_tr = cpu->cd.x86.tr;
5320                                    uint64_t tmp1, tmp2;
5321                                    success = modrm(cpu, MODRM_READ, mode, mode67,
5322                                        MODRM_JUST_GET_ADDR, &instr,
5323                                        &newpc, &op1, &op2);
5324                                    if (!success)
5325                                            return 0;
5326                                    /*  Load a far address from op1:  */
5327                                    if (!x86_load(cpu, op1, &tmp1, mode/8))
5328                                            return 0;
5329                                    if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5330                                            return 0;
5331                                    /*  Push return CS:[E]IP  */
5332                                    if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS],
5333                                        mode))
5334                                            return 0;
5335                                    if (!x86_push(cpu, newpc, mode)) {
5336                                            fatal("TODO: push failed, call "
5337                                                "far indirect?\n");
5338                                            cpu->running = 0;
5339                                            return 0;
5340                                    }
5341                                    reload_segment_descriptor(cpu, X86_S_CS,
5342                                        tmp2, &newpc);
5343                                    if (cpu->cd.x86.tr == old_tr)
5344                                            newpc = tmp1;
5345                            }
5346                            break;
5347                    case 4: if (op == 0xfe) {
5348                                    fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5349                                        *instr);
5350                                    quiet_mode = 0;
5351                                    x86_cpu_disassemble_instr(cpu,
5352                                        really_orig_instr, 1|omode, 0, 0);
5353                                    cpu->running = 0;
5354                            } else {
5355                                    success = modrm(cpu, MODRM_READ, mode, mode67,
5356                                        0, &instr, &newpc, &op1, &op2);
5357                                    if (!success)
5358                                            return 0;
5359                                    newpc = op1;
5360                            }
5361                            break;
5362                    case 5: if (op == 0xfe) {
5363                                    fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5364                                        *instr);
5365                                    quiet_mode = 0;
5366                                    x86_cpu_disassemble_instr(cpu,
5367                                        really_orig_instr, 1|omode, 0, 0);
5368                                    cpu->running = 0;
5369                            } else {
5370                                    uint16_t old_tr = cpu->cd.x86.tr;
5371                                    uint64_t tmp1, tmp2;
5372                                    success = modrm(cpu, MODRM_READ, mode, mode67,
5373                                        MODRM_JUST_GET_ADDR, &instr,
5374                                        &newpc, &op1, &op2);
5375                                    if (!success)
5376                                            return 0;
5377                                    /*  Load a far address from op1:  */
5378                                    if (!x86_load(cpu, op1, &tmp1, mode/8))
5379                                            return 0;
5380                                    if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5381                                            return 0;
5382                                    reload_segment_descriptor(cpu, X86_S_CS,
5383                                        tmp2, &newpc);
5384                                    if (cpu->cd.x86.tr == old_tr)
5385                                            newpc = tmp1;
5386                            }
5387                            break;
5388                    case 6: if (op == 0xfe) {
5389                                    fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5390                                        *instr);
5391                                    quiet_mode = 0;
5392                                    x86_cpu_disassemble_instr(cpu,
5393                                        really_orig_instr, 1|omode, 0, 0);
5394                                    cpu->running = 0;
5395                            } else {
5396                                    instr_orig = instr;
5397                                    success = modrm(cpu, MODRM_READ, mode, mode67,
5398                                        0, &instr, &newpc, &op1, &op2);
5399                                    if (!success)
5400                                            return 0;
5401                                    if (!x86_push(cpu, op1, mode))
5402                                            return 0;
5403                            }
5404                            break;
5405                    default:
5406                            fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
5407                            quiet_mode = 0;
5408                            x86_cpu_disassemble_instr(cpu,
5409                                really_orig_instr, 1|omode, 0, 0);
5410                            cpu->running = 0;
5411                    }
5412          } else {          } else {
5413                  fatal("x86_cpu_run_instr(): unimplemented opcode 0x%02x"                  fatal("x86_cpu_run_instr(): unimplemented opcode 0x%02x"
5414                      " at ", op); print_csip(cpu); fatal("\n");                      " at ", op); print_csip(cpu); fatal("\n");
5415                    quiet_mode = 0;
5416                    x86_cpu_disassemble_instr(cpu,
5417                        really_orig_instr, 1|omode, 0, 0);
5418                  cpu->running = 0;                  cpu->running = 0;
5419                  return 0;                  return 0;
5420          }          }
5421    
5422          cpu->pc = newpc;          /*  Wrap-around and update [E]IP:  */
5423            cpu->pc = newpc & (((uint64_t)1 << (cpu->cd.x86.descr_cache[
5424                X86_S_CS].default_op_size)) - 1);
5425    
5426            if (trap_flag_was_set) {
5427                    if (REAL_MODE) {
5428                            x86_interrupt(cpu, 1, 0);
5429                    } else {
5430                            fatal("TRAP flag in protected mode?\n");
5431                            cpu->running = 0;
5432                    }
5433            }
5434    
5435          return 1;          return 1;
5436  }  }
# Line 917  int x86_cpu_family_init(struct cpu_famil Line 5462  int x86_cpu_family_init(struct cpu_famil
5462          fp->dumpinfo = x86_cpu_dumpinfo;          fp->dumpinfo = x86_cpu_dumpinfo;
5463          /*  fp->show_full_statistics = x86_cpu_show_full_statistics;  */          /*  fp->show_full_statistics = x86_cpu_show_full_statistics;  */
5464          /*  fp->tlbdump = x86_cpu_tlbdump;  */          /*  fp->tlbdump = x86_cpu_tlbdump;  */
5465          /*  fp->interrupt = x86_cpu_interrupt;  */          fp->interrupt = x86_cpu_interrupt;
5466          /*  fp->interrupt_ack = x86_cpu_interrupt_ack;  */          fp->interrupt_ack = x86_cpu_interrupt_ack;
5467          return 1;          return 1;
5468  }  }
5469    

Legend:
Removed from v.5  
changed lines
  Added in v.6

  ViewVC Help
Powered by ViewVC 1.1.26