direct-io.hg

changeset 13109:4fb80f21c77d

[XEN] Emulator extensions to decode ModRM.MOD == 3.
This allows emulation of register-only instructions.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Dec 20 15:16:13 2006 +0000 (2006-12-20)
parents ed815cbdc90e
children f58b0c778b90
files tools/tests/test_x86_emulator.c xen/arch/x86/x86_32/seg_fixup.c xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/tools/tests/test_x86_emulator.c	Wed Dec 20 13:54:04 2006 +0000
     1.2 +++ b/tools/tests/test_x86_emulator.c	Wed Dec 20 15:16:13 2006 +0000
     1.3 @@ -15,8 +15,6 @@ typedef int64_t            s64;
     1.4  #include <asm-x86/x86_emulate.h>
     1.5  #include <sys/mman.h>
     1.6  
     1.7 -#define PFEC_write_access (1U<<1)
     1.8 -
     1.9  static int read(
    1.10      unsigned int seg,
    1.11      unsigned long offset,
    1.12 @@ -119,7 +117,6 @@ int main(int argc, char **argv)
    1.13      regs.eflags = 0x200;
    1.14      regs.eip    = (unsigned long)&instr[0];
    1.15      regs.ecx    = 0x12345678;
    1.16 -    regs.error_code = PFEC_write_access;
    1.17      regs.eax    = (unsigned long)res;
    1.18      *res        = 0x7FFFFFFF;
    1.19      rc = x86_emulate_memop(&ctxt, &emulops);
    1.20 @@ -130,6 +127,21 @@ int main(int argc, char **argv)
    1.21          goto fail;
    1.22      printf("okay\n");
    1.23  
    1.24 +    printf("%-40s", "Testing addl %%ecx,%%eax...");
    1.25 +    instr[0] = 0x01; instr[1] = 0xc8;
    1.26 +    regs.eflags = 0x200;
    1.27 +    regs.eip    = (unsigned long)&instr[0];
    1.28 +    regs.ecx    = 0x12345678;
    1.29 +    regs.eax    = 0x7FFFFFFF;
    1.30 +    rc = x86_emulate_memop(&ctxt, &emulops);
    1.31 +    if ( (rc != 0) || 
    1.32 +         (regs.ecx != 0x12345678) ||
    1.33 +         (regs.eax != 0x92345677) ||
    1.34 +         (regs.eflags != 0xa94) ||
    1.35 +         (regs.eip != (unsigned long)&instr[2]) )
    1.36 +        goto fail;
    1.37 +    printf("okay\n");
    1.38 +
    1.39      printf("%-40s", "Testing xorl (%%eax),%%ecx...");
    1.40      instr[0] = 0x33; instr[1] = 0x08;
    1.41      regs.eflags = 0x200;
    1.42 @@ -140,7 +152,6 @@ int main(int argc, char **argv)
    1.43      regs.ecx    = 0x12345678UL;
    1.44  #endif
    1.45      regs.eax    = (unsigned long)res;
    1.46 -    regs.error_code = 0;
    1.47      rc = x86_emulate_memop(&ctxt, &emulops);
    1.48      if ( (rc != 0) || 
    1.49           (*res != 0x92345677) || 
    1.50 @@ -155,7 +166,6 @@ int main(int argc, char **argv)
    1.51      regs.eip    = (unsigned long)&instr[0];
    1.52      regs.ecx    = ~0UL;
    1.53      regs.eax    = (unsigned long)res;
    1.54 -    regs.error_code = 0;
    1.55      rc = x86_emulate_memop(&ctxt, &emulops);
    1.56      if ( (rc != 0) || 
    1.57           (*res != 0x92345677) || 
    1.58 @@ -171,7 +181,6 @@ int main(int argc, char **argv)
    1.59      regs.eax    = 0x92345677UL;
    1.60      regs.ecx    = 0xAA;
    1.61      regs.ebx    = (unsigned long)res;
    1.62 -    regs.error_code = PFEC_write_access;
    1.63      rc = x86_emulate_memop(&ctxt, &emulops);
    1.64      if ( (rc != 0) || 
    1.65           (*res != 0x923456AA) || 
    1.66 @@ -188,7 +197,6 @@ int main(int argc, char **argv)
    1.67      regs.eax    = 0xAABBCC77UL;
    1.68      regs.ecx    = 0xFF;
    1.69      regs.ebx    = (unsigned long)res;
    1.70 -    regs.error_code = PFEC_write_access;
    1.71      rc = x86_emulate_memop(&ctxt, &emulops);
    1.72      if ( (rc != 0) || 
    1.73           (*res != 0x923456AA) || 
    1.74 @@ -205,7 +213,6 @@ int main(int argc, char **argv)
    1.75      regs.eip    = (unsigned long)&instr[0];
    1.76      regs.ecx    = 0x12345678;
    1.77      regs.eax    = (unsigned long)res;
    1.78 -    regs.error_code = PFEC_write_access;
    1.79      rc = x86_emulate_memop(&ctxt, &emulops);
    1.80      if ( (rc != 0) || 
    1.81           (*res != 0x12345678) || 
    1.82 @@ -223,7 +230,6 @@ int main(int argc, char **argv)
    1.83      regs.eax    = 0x923456AAUL;
    1.84      regs.ecx    = 0xDDEEFF00L;
    1.85      regs.ebx    = (unsigned long)res;
    1.86 -    regs.error_code = PFEC_write_access;
    1.87      rc = x86_emulate_memop(&ctxt, &emulops);
    1.88      if ( (rc != 0) || 
    1.89           (*res != 0xDDEEFF00) || 
    1.90 @@ -241,7 +247,6 @@ int main(int argc, char **argv)
    1.91      regs.eip    = (unsigned long)&instr[0];
    1.92      regs.esi    = (unsigned long)res + 0;
    1.93      regs.edi    = (unsigned long)res + 2;
    1.94 -    regs.error_code = 0; /* read fault */
    1.95      rc = x86_emulate_memop(&ctxt, &emulops);
    1.96      if ( (rc != 0) || 
    1.97           (*res != 0x44554455) ||
    1.98 @@ -259,9 +264,8 @@ int main(int argc, char **argv)
    1.99      regs.eflags = 0x200;
   1.100      regs.eip    = (unsigned long)&instr[0];
   1.101      regs.edi    = (unsigned long)res;
   1.102 -    regs.error_code = PFEC_write_access;
   1.103      rc = x86_emulate_memop(&ctxt, &emulops);
   1.104 -    if ( (rc != 0) || 
   1.105 +    if ( (rc != 0) ||
   1.106           (*res != 0x2233445D) ||
   1.107           ((regs.eflags&0x201) != 0x201) ||
   1.108           (regs.eip != (unsigned long)&instr[4]) )
   1.109 @@ -275,9 +279,8 @@ int main(int argc, char **argv)
   1.110      regs.eip    = (unsigned long)&instr[0];
   1.111      regs.eax    = -32;
   1.112      regs.edi    = (unsigned long)(res+1);
   1.113 -    regs.error_code = PFEC_write_access;
   1.114      rc = x86_emulate_memop(&ctxt, &emulops);
   1.115 -    if ( (rc != 0) || 
   1.116 +    if ( (rc != 0) ||
   1.117           (*res != 0x2233445E) ||
   1.118           ((regs.eflags&0x201) != 0x201) ||
   1.119           (regs.eip != (unsigned long)&instr[3]) )
   1.120 @@ -296,9 +299,8 @@ int main(int argc, char **argv)
   1.121      regs.ecx    = 0xCCCCFFFF;
   1.122      regs.eip    = (unsigned long)&instr[0];
   1.123      regs.edi    = (unsigned long)res;
   1.124 -    regs.error_code = PFEC_write_access;
   1.125      rc = x86_emulate_memop(&ctxt, &emulops);
   1.126 -    if ( (rc != 0) || 
   1.127 +    if ( (rc != 0) ||
   1.128           (res[0] != 0x9999AAAA) ||
   1.129           (res[1] != 0xCCCCFFFF) ||
   1.130           ((regs.eflags&0x240) != 0x240) ||
   1.131 @@ -311,7 +313,6 @@ int main(int argc, char **argv)
   1.132      regs.eflags = 0x200;
   1.133      regs.eip    = (unsigned long)&instr[0];
   1.134      regs.edi    = (unsigned long)res;
   1.135 -    regs.error_code = PFEC_write_access;
   1.136      rc = x86_emulate_memop(&ctxt, &emulops);
   1.137      if ( (rc != 0) || 
   1.138           (res[0] != 0x9999AAAA) ||
   1.139 @@ -330,7 +331,6 @@ int main(int argc, char **argv)
   1.140      regs.ecx    = 0x12345678;
   1.141      regs.eax    = (unsigned long)res;
   1.142      *res        = 0x82;
   1.143 -    regs.error_code = 0;
   1.144      rc = x86_emulate_memop(&ctxt, &emulops);
   1.145      if ( (rc != 0) ||
   1.146           (*res != 0x82) ||
   1.147 @@ -347,7 +347,6 @@ int main(int argc, char **argv)
   1.148      regs.ecx    = 0x12345678;
   1.149      regs.eax    = (unsigned long)res;
   1.150      *res        = 0x1234aa82;
   1.151 -    regs.error_code = 0;
   1.152      rc = x86_emulate_memop(&ctxt, &emulops);
   1.153      if ( (rc != 0) ||
   1.154           (*res != 0x1234aa82) ||
   1.155 @@ -364,7 +363,6 @@ int main(int argc, char **argv)
   1.156      regs.ecx    = (unsigned long)res;
   1.157      regs.eax    = 0x12345678;
   1.158      *res        = 0x11111111;
   1.159 -    regs.error_code = 0;
   1.160      rc = x86_emulate_memop(&ctxt, &emulops);
   1.161      if ( (rc != 0) ||
   1.162           (*res != 0x11116789) ||
     2.1 --- a/xen/arch/x86/x86_32/seg_fixup.c	Wed Dec 20 13:54:04 2006 +0000
     2.2 +++ b/xen/arch/x86/x86_32/seg_fixup.c	Wed Dec 20 15:16:13 2006 +0000
     2.3 @@ -268,7 +268,7 @@ int gpf_emulate_4gb(struct cpu_user_regs
     2.4      struct trap_info   *ti;
     2.5      struct trap_bounce *tb;
     2.6      u8            modrm, mod, reg, rm, decode;
     2.7 -    void         *memreg, *regreg;
     2.8 +    void         *memreg;
     2.9      unsigned long offset;
    2.10      u8            disp8;
    2.11      u32           disp32 = 0;
    2.12 @@ -384,8 +384,7 @@ int gpf_emulate_4gb(struct cpu_user_regs
    2.13          goto fixme;
    2.14      }
    2.15  
    2.16 -    /* Decode Reg and R/M fields. */
    2.17 -    regreg = decode_register(reg, regs, 0);
    2.18 +    /* Decode R/M field. */
    2.19      memreg = decode_register(rm,  regs, 0);
    2.20  
    2.21      /* Decode Mod field. */
     3.1 --- a/xen/arch/x86/x86_emulate.c	Wed Dec 20 13:54:04 2006 +0000
     3.2 +++ b/xen/arch/x86/x86_emulate.c	Wed Dec 20 15:16:13 2006 +0000
     3.3 @@ -192,11 +192,15 @@ struct operand {
     3.4      enum { OP_REG, OP_MEM, OP_IMM } type;
     3.5      unsigned int  bytes;
     3.6      unsigned long val, orig_val;
     3.7 -    /* OP_REG: Pointer to register field. */
     3.8 -    unsigned long *reg;
     3.9 -    /* OP_MEM: Segment and offset. */
    3.10 -    enum x86_segment mem_seg;
    3.11 -    unsigned long    mem_off;
    3.12 +    union {
    3.13 +        /* OP_REG: Pointer to register field. */
    3.14 +        unsigned long *reg;
    3.15 +        /* OP_MEM: Segment and offset. */
    3.16 +        struct {
    3.17 +            enum x86_segment seg;
    3.18 +            unsigned long    off;
    3.19 +        } mem;
    3.20 +    };
    3.21  };
    3.22  
    3.23  /* EFLAGS bit definitions. */
    3.24 @@ -451,8 +455,13 @@ x86_emulate_memop(
    3.25      struct operand src, dst;
    3.26      int mode = ctxt->mode;
    3.27  
    3.28 -    enum x86_segment ea_seg = x86_seg_ds;
    3.29 -    unsigned long    ea_off = 0;
    3.30 +    /* Data operand effective address (usually computed from ModRM). */
    3.31 +    struct operand ea;
    3.32 +
    3.33 +    /* Default is a memory operand relative to segment DS. */
    3.34 +    ea.type    = OP_MEM;
    3.35 +    ea.mem.seg = x86_seg_ds;
    3.36 +    ea.mem.off = 0;
    3.37  
    3.38      switch ( mode )
    3.39      {
    3.40 @@ -488,22 +497,22 @@ x86_emulate_memop(
    3.41                  ad_bytes ^= 6;  /* switch between 2/4 bytes */
    3.42              break;
    3.43          case 0x2e: /* CS override */
    3.44 -            ea_seg = x86_seg_cs;
    3.45 +            ea.mem.seg = x86_seg_cs;
    3.46              break;
    3.47          case 0x3e: /* DS override */
    3.48 -            ea_seg = x86_seg_ds;
    3.49 +            ea.mem.seg = x86_seg_ds;
    3.50              break;
    3.51          case 0x26: /* ES override */
    3.52 -            ea_seg = x86_seg_es;
    3.53 +            ea.mem.seg = x86_seg_es;
    3.54              break;
    3.55          case 0x64: /* FS override */
    3.56 -            ea_seg = x86_seg_fs;
    3.57 +            ea.mem.seg = x86_seg_fs;
    3.58              break;
    3.59          case 0x65: /* GS override */
    3.60 -            ea_seg = x86_seg_gs;
    3.61 +            ea.mem.seg = x86_seg_gs;
    3.62              break;
    3.63          case 0x36: /* SS override */
    3.64 -            ea_seg = x86_seg_ss;
    3.65 +            ea.mem.seg = x86_seg_ss;
    3.66              break;
    3.67          case 0xf0: /* LOCK */
    3.68              lock_prefix = 1;
    3.69 @@ -554,35 +563,39 @@ x86_emulate_memop(
    3.70          modrm_rm  = modrm & 0x07;
    3.71  
    3.72          if ( modrm_mod == 3 )
    3.73 -            goto cannot_emulate;
    3.74 -
    3.75 -        if ( ad_bytes == 2 )
    3.76 +        {
    3.77 +            ea.type = OP_REG;
    3.78 +            ea.reg  = decode_register(
    3.79 +                modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));
    3.80 +        }
    3.81 +        else if ( ad_bytes == 2 )
    3.82          {
    3.83              /* 16-bit ModR/M decode. */
    3.84              switch ( modrm_rm )
    3.85              {
    3.86 -            case 0: ea_off = _regs.ebx + _regs.esi; break;
    3.87 -            case 1: ea_off = _regs.ebx + _regs.edi; break;
    3.88 -            case 2: ea_off = _regs.ebp + _regs.esi; break;
    3.89 -            case 3: ea_off = _regs.ebp + _regs.edi; break;
    3.90 -            case 4: ea_off = _regs.esi; break;
    3.91 -            case 5: ea_off = _regs.edi; break;
    3.92 -            case 6: ea_off = _regs.ebp; break;
    3.93 -            case 7: ea_off = _regs.ebx; break;
    3.94 +            case 0: ea.mem.off = _regs.ebx + _regs.esi; break;
    3.95 +            case 1: ea.mem.off = _regs.ebx + _regs.edi; break;
    3.96 +            case 2: ea.mem.off = _regs.ebp + _regs.esi; break;
    3.97 +            case 3: ea.mem.off = _regs.ebp + _regs.edi; break;
    3.98 +            case 4: ea.mem.off = _regs.esi; break;
    3.99 +            case 5: ea.mem.off = _regs.edi; break;
   3.100 +            case 6: ea.mem.off = _regs.ebp; break;
   3.101 +            case 7: ea.mem.off = _regs.ebx; break;
   3.102              }
   3.103              switch ( modrm_mod )
   3.104              {
   3.105              case 0:
   3.106                  if ( modrm_rm == 6 )
   3.107 -                    ea_off = insn_fetch_type(int16_t);
   3.108 +                    ea.mem.off = insn_fetch_type(int16_t);
   3.109                  break;
   3.110              case 1:
   3.111 -                ea_off += insn_fetch_type(int8_t);
   3.112 +                ea.mem.off += insn_fetch_type(int8_t);
   3.113                  break;
   3.114              case 2:
   3.115 -                ea_off += insn_fetch_type(int16_t);
   3.116 +                ea.mem.off += insn_fetch_type(int16_t);
   3.117                  break;
   3.118              }
   3.119 +            ea.mem.off = truncate_ea(ea.mem.off);
   3.120          }
   3.121          else
   3.122          {
   3.123 @@ -593,49 +606,48 @@ x86_emulate_memop(
   3.124                  sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
   3.125                  sib_base  = (sib & 7) | ((rex_prefix << 3) & 8);
   3.126                  if ( sib_index != 4 )
   3.127 -                    ea_off = *(long *)decode_register(sib_index, &_regs, 0);
   3.128 -                ea_off <<= (sib >> 6) & 3;
   3.129 +                    ea.mem.off = *(long*)decode_register(sib_index, &_regs, 0);
   3.130 +                ea.mem.off <<= (sib >> 6) & 3;
   3.131                  if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
   3.132 -                    ea_off += insn_fetch_type(int32_t);
   3.133 +                    ea.mem.off += insn_fetch_type(int32_t);
   3.134                  else
   3.135 -                    ea_off += *(long *)decode_register(sib_base, &_regs, 0);
   3.136 +                    ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);
   3.137              }
   3.138              else
   3.139              {
   3.140                  modrm_rm |= (rex_prefix & 1) << 3;
   3.141 -                ea_off = *(long *)decode_register(modrm_rm, &_regs, 0);
   3.142 +                ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0);
   3.143              }
   3.144              switch ( modrm_mod )
   3.145              {
   3.146              case 0:
   3.147                  if ( (modrm_rm & 7) != 5 )
   3.148                      break;
   3.149 -                ea_off = insn_fetch_type(int32_t);
   3.150 +                ea.mem.off = insn_fetch_type(int32_t);
   3.151                  if ( mode != X86EMUL_MODE_PROT64 )
   3.152                      break;
   3.153                  /* Relative to RIP of next instruction. Argh! */
   3.154 -                ea_off += _regs.eip;
   3.155 +                ea.mem.off += _regs.eip;
   3.156                  if ( (d & SrcMask) == SrcImm )
   3.157 -                    ea_off += (d & ByteOp) ? 1 :
   3.158 +                    ea.mem.off += (d & ByteOp) ? 1 :
   3.159                          ((op_bytes == 8) ? 4 : op_bytes);
   3.160                  else if ( (d & SrcMask) == SrcImmByte )
   3.161 -                    ea_off += 1;
   3.162 +                    ea.mem.off += 1;
   3.163                  else if ( ((b == 0xf6) || (b == 0xf7)) &&
   3.164                            ((modrm_reg & 7) <= 1) )
   3.165                      /* Special case in Grp3: test has immediate operand. */
   3.166 -                    ea_off += (d & ByteOp) ? 1
   3.167 +                    ea.mem.off += (d & ByteOp) ? 1
   3.168                          : ((op_bytes == 8) ? 4 : op_bytes);
   3.169                  break;
   3.170              case 1:
   3.171 -                ea_off += insn_fetch_type(int8_t);
   3.172 +                ea.mem.off += insn_fetch_type(int8_t);
   3.173                  break;
   3.174              case 2:
   3.175 -                ea_off += insn_fetch_type(int32_t);
   3.176 +                ea.mem.off += insn_fetch_type(int32_t);
   3.177                  break;
   3.178              }
   3.179 +            ea.mem.off = truncate_ea(ea.mem.off);
   3.180          }
   3.181 -
   3.182 -        ea_off = truncate_ea(ea_off);
   3.183      }
   3.184  
   3.185      /* Special instructions do their own operand decoding. */
   3.186 @@ -652,7 +664,7 @@ x86_emulate_memop(
   3.187          if ( d & ByteOp )
   3.188          {
   3.189              src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
   3.190 -            src.val = src.orig_val = *(uint8_t *)src.reg;
   3.191 +            src.val = *(uint8_t *)src.reg;
   3.192              src.bytes = 1;
   3.193          }
   3.194          else
   3.195 @@ -660,28 +672,35 @@ x86_emulate_memop(
   3.196              src.reg = decode_register(modrm_reg, &_regs, 0);
   3.197              switch ( (src.bytes = op_bytes) )
   3.198              {
   3.199 -            case 2: src.val = src.orig_val = *(uint16_t *)src.reg; break;
   3.200 -            case 4: src.val = src.orig_val = *(uint32_t *)src.reg; break;
   3.201 -            case 8: src.val = src.orig_val = *(uint64_t *)src.reg; break;
   3.202 +            case 2: src.val = *(uint16_t *)src.reg; break;
   3.203 +            case 4: src.val = *(uint32_t *)src.reg; break;
   3.204 +            case 8: src.val = *(uint64_t *)src.reg; break;
   3.205              }
   3.206          }
   3.207          break;
   3.208      case SrcMem16:
   3.209 -        src.bytes = 2;
   3.210 +        ea.bytes = 2;
   3.211          goto srcmem_common;
   3.212      case SrcMem32:
   3.213 -        src.bytes = 4;
   3.214 +        ea.bytes = 4;
   3.215          goto srcmem_common;
   3.216      case SrcMem:
   3.217 -        src.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.218 +        ea.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.219      srcmem_common:
   3.220 -        src.type  = OP_MEM;
   3.221 -        src.mem_seg = ea_seg;
   3.222 -        src.mem_off = ea_off;
   3.223 -        if ( (rc = ops->read(src.mem_seg, src.mem_off,
   3.224 -                             &src.val, src.bytes, ctxt)) != 0 )
   3.225 +        src = ea;
   3.226 +        if ( src.type == OP_REG )
   3.227 +        {
   3.228 +            switch ( src.bytes )
   3.229 +            {
   3.230 +            case 1: src.val = *(uint8_t  *)src.reg; break;
   3.231 +            case 2: src.val = *(uint16_t *)src.reg; break;
   3.232 +            case 4: src.val = *(uint32_t *)src.reg; break;
   3.233 +            case 8: src.val = *(uint64_t *)src.reg; break;
   3.234 +            }
   3.235 +        }
   3.236 +        else if ( (rc = ops->read(src.mem.seg, src.mem.off,
   3.237 +                                  &src.val, src.bytes, ctxt)) )
   3.238              goto done;
   3.239 -        src.orig_val = src.val;
   3.240          break;
   3.241      case SrcImm:
   3.242          src.type  = OP_IMM;
   3.243 @@ -725,8 +744,7 @@ x86_emulate_memop(
   3.244          }
   3.245          break;
   3.246      case DstBitBase:
   3.247 -        dst.mem_off = ea_off;
   3.248 -        if ( (d & SrcMask) == SrcImmByte )
   3.249 +        if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) )
   3.250          {
   3.251              src.val &= (op_bytes << 3) - 1;
   3.252          }
   3.253 @@ -746,28 +764,34 @@ x86_emulate_memop(
   3.254              {
   3.255                  unsigned long byte_offset;
   3.256                  byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));
   3.257 -                dst.mem_off -= byte_offset;
   3.258 +                ea.mem.off -= byte_offset;
   3.259                  src.val = (byte_offset << 3) + src.val;
   3.260              }
   3.261              else
   3.262              {
   3.263 -                dst.mem_off += (src.val >> 3) & ~(op_bytes - 1);
   3.264 +                ea.mem.off += (src.val >> 3) & ~(op_bytes - 1);
   3.265                  src.val &= (op_bytes << 3) - 1;
   3.266              }
   3.267          }
   3.268          /* Becomes a normal DstMem operation from here on. */
   3.269          d = (d & ~DstMask) | DstMem;
   3.270 -        goto dstmem_common;
   3.271      case DstMem:
   3.272 -        dst.mem_off = ea_off;
   3.273 -    dstmem_common:
   3.274 -        dst.mem_seg = ea_seg;
   3.275 -        dst.type  = OP_MEM;
   3.276 -        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.277 -        if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
   3.278 -             ((rc = ops->read(dst.mem_seg, dst.mem_off,
   3.279 -                              &dst.val, dst.bytes, ctxt)) != 0) )
   3.280 -             goto done;
   3.281 +        ea.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.282 +        dst = ea;
   3.283 +        if ( dst.type == OP_REG )
   3.284 +        {
   3.285 +            switch ( dst.bytes )
   3.286 +            {
   3.287 +            case 1: dst.val = *(uint8_t  *)dst.reg; break;
   3.288 +            case 2: dst.val = *(uint16_t *)dst.reg; break;
   3.289 +            case 4: dst.val = *(uint32_t *)dst.reg; break;
   3.290 +            case 8: dst.val = *(uint64_t *)dst.reg; break;
   3.291 +            }
   3.292 +        }
   3.293 +        else if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
   3.294 +                  (rc = ops->read(dst.mem.seg, dst.mem.off,
   3.295 +                                  &dst.val, dst.bytes, ctxt)) )
   3.296 +            goto done;
   3.297          break;
   3.298      }
   3.299      dst.orig_val = dst.val;
   3.300 @@ -920,7 +944,7 @@ x86_emulate_memop(
   3.301              if ( mode == X86EMUL_MODE_PROT64 )
   3.302              {
   3.303                  dst.bytes = 8;
   3.304 -                if ( (rc = ops->read(dst.mem_seg, dst.mem_off,
   3.305 +                if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
   3.306                                       &dst.val, 8, ctxt)) != 0 )
   3.307                      goto done;
   3.308              }
   3.309 @@ -954,11 +978,11 @@ x86_emulate_memop(
   3.310          case OP_MEM:
   3.311              if ( lock_prefix )
   3.312                  rc = ops->cmpxchg(
   3.313 -                    dst.mem_seg, dst.mem_off, dst.orig_val,
   3.314 +                    dst.mem.seg, dst.mem.off, dst.orig_val,
   3.315                      dst.val, dst.bytes, ctxt);
   3.316              else
   3.317                  rc = ops->write(
   3.318 -                    dst.mem_seg, dst.mem_off, dst.val, dst.bytes, ctxt);
   3.319 +                    dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
   3.320              if ( rc != 0 )
   3.321                  goto done;
   3.322          default:
   3.323 @@ -987,29 +1011,29 @@ x86_emulate_memop(
   3.324      }
   3.325      switch ( b )
   3.326      {
   3.327 -    case 0xa0 ... 0xa1: /* mov moffs,{%al,%ax,%eax,%rax} */
   3.328 +    case 0xa0 ... 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
   3.329          /* Source EA is not encoded via ModRM. */
   3.330          dst.type  = OP_REG;
   3.331          dst.reg   = (unsigned long *)&_regs.eax;
   3.332          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.333 -        if ( (rc = ops->read(ea_seg, insn_fetch_bytes(ad_bytes),
   3.334 +        if ( (rc = ops->read(ea.mem.seg, insn_fetch_bytes(ad_bytes),
   3.335                               &dst.val, dst.bytes, ctxt)) != 0 )
   3.336              goto done;
   3.337          break;
   3.338 -    case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},moffs */
   3.339 +    case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
   3.340          /* Destination EA is not encoded via ModRM. */
   3.341 -        dst.type    = OP_MEM;
   3.342 -        dst.mem_seg = ea_seg;
   3.343 -        dst.mem_off = insn_fetch_bytes(ad_bytes);
   3.344 -        dst.bytes   = (d & ByteOp) ? 1 : op_bytes;
   3.345 -        dst.val     = (unsigned long)_regs.eax;
   3.346 +        dst.type  = OP_MEM;
   3.347 +        dst.mem.seg = ea.mem.seg;
   3.348 +        dst.mem.off = insn_fetch_bytes(ad_bytes);
   3.349 +        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.350 +        dst.val   = (unsigned long)_regs.eax;
   3.351          break;
   3.352      case 0xa4 ... 0xa5: /* movs */
   3.353          dst.type  = OP_MEM;
   3.354          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.355 -        dst.mem_seg = x86_seg_es;
   3.356 -        dst.mem_off = truncate_ea(_regs.edi);
   3.357 -        if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
   3.358 +        dst.mem.seg = x86_seg_es;
   3.359 +        dst.mem.off = truncate_ea(_regs.edi);
   3.360 +        if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
   3.361                               &dst.val, dst.bytes, ctxt)) != 0 )
   3.362              goto done;
   3.363          register_address_increment(
   3.364 @@ -1020,8 +1044,8 @@ x86_emulate_memop(
   3.365      case 0xaa ... 0xab: /* stos */
   3.366          dst.type  = OP_MEM;
   3.367          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.368 -        dst.mem_seg = x86_seg_es;
   3.369 -        dst.mem_off = truncate_ea(_regs.edi);
   3.370 +        dst.mem.seg = x86_seg_es;
   3.371 +        dst.mem.off = truncate_ea(_regs.edi);
   3.372          dst.val   = _regs.eax;
   3.373          register_address_increment(
   3.374              _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   3.375 @@ -1030,7 +1054,7 @@ x86_emulate_memop(
   3.376          dst.type  = OP_REG;
   3.377          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   3.378          dst.reg   = (unsigned long *)&_regs.eax;
   3.379 -        if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
   3.380 +        if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
   3.381                               &dst.val, dst.bytes, ctxt)) != 0 )
   3.382              goto done;
   3.383          register_address_increment(
   3.384 @@ -1105,9 +1129,14 @@ x86_emulate_memop(
   3.385      case 0xab: bts: /* bts */
   3.386          emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
   3.387          break;
   3.388 -    case 0xb6 ... 0xb7: /* movzx */
   3.389 +    case 0xb6: /* movzx rm8,r{16,32,64} */
   3.390 +        /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
   3.391 +        dst.reg   = decode_register(modrm_reg, &_regs, 0);
   3.392          dst.bytes = op_bytes;
   3.393 -        dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val;
   3.394 +        dst.val   = (uint8_t)src.val;
   3.395 +        break;
   3.396 +    case 0xb7: /* movzx rm16,r{16,32,64} */
   3.397 +        dst.val = (uint16_t)src.val;
   3.398          break;
   3.399      case 0xbb: btc: /* btc */
   3.400          emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
   3.401 @@ -1121,9 +1150,14 @@ x86_emulate_memop(
   3.402          case 3: goto btc;
   3.403          }
   3.404          break;
   3.405 -    case 0xbe ... 0xbf: /* movsx */
   3.406 +    case 0xbe: /* movsx rm8,r{16,32,64} */
   3.407 +        /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
   3.408 +        dst.reg   = decode_register(modrm_reg, &_regs, 0);
   3.409          dst.bytes = op_bytes;
   3.410 -        dst.val = (d & ByteOp) ? (int8_t)src.val : (int16_t)src.val;
   3.411 +        dst.val   = (int8_t)src.val;
   3.412 +        break;
   3.413 +    case 0xbf: /* movsx rm16,r{16,32,64} */
   3.414 +        dst.val = (int16_t)src.val;
   3.415          break;
   3.416      case 0xc0 ... 0xc1: /* xadd */
   3.417          /* Write back the register source. */
   3.418 @@ -1150,8 +1184,8 @@ x86_emulate_memop(
   3.419  #if defined(__i386__)
   3.420      {
   3.421          unsigned long old_lo, old_hi;
   3.422 -        if ( ((rc = ops->read(ea_seg, ea_off+0, &old_lo, 4, ctxt)) != 0) ||
   3.423 -             ((rc = ops->read(ea_seg, ea_off+4, &old_hi, 4, ctxt)) != 0) )
   3.424 +        if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
   3.425 +             (rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
   3.426              goto done;
   3.427          if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
   3.428          {
   3.429 @@ -1166,7 +1200,7 @@ x86_emulate_memop(
   3.430          }
   3.431          else
   3.432          {
   3.433 -            if ( (rc = ops->cmpxchg8b(ea_seg, ea_off, old_lo, old_hi,
   3.434 +            if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi,
   3.435                                        _regs.ebx, _regs.ecx, ctxt)) != 0 )
   3.436                  goto done;
   3.437              _regs.eflags |= EFLG_ZF;
   3.438 @@ -1176,7 +1210,7 @@ x86_emulate_memop(
   3.439  #elif defined(__x86_64__)
   3.440      {
   3.441          unsigned long old, new;
   3.442 -        if ( (rc = ops->read(ea_seg, ea_off, &old, 8, ctxt)) != 0 )
   3.443 +        if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
   3.444              goto done;
   3.445          if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
   3.446               ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
   3.447 @@ -1188,7 +1222,8 @@ x86_emulate_memop(
   3.448          else
   3.449          {
   3.450              new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
   3.451 -            if ( (rc = ops->cmpxchg(ea_seg, ea_off, old, new, 8, ctxt)) != 0 )
   3.452 +            if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
   3.453 +                                    new, 8, ctxt)) != 0 )
   3.454                  goto done;
   3.455              _regs.eflags |= EFLG_ZF;
   3.456          }
   3.457 @@ -1201,10 +1236,10 @@ x86_emulate_memop(
   3.458   cannot_emulate:
   3.459  #ifdef __XEN__
   3.460      gdprintk(XENLOG_DEBUG, "Instr:");
   3.461 -    for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ )
   3.462 +    for ( ea.mem.off = ctxt->regs->eip; ea.mem.off < _regs.eip; ea.mem.off++ )
   3.463      {
   3.464          unsigned long x;
   3.465 -        ops->insn_fetch(x86_seg_cs, ea_off, &x, 1, ctxt);
   3.466 +        ops->insn_fetch(x86_seg_cs, ea.mem.off, &x, 1, ctxt);
   3.467          printk(" %02x", (uint8_t)x);
   3.468      }
   3.469      printk("\n");