ia64/xen-unstable

changeset 13282:df00f7a98821

[XEN] Add more instructions to the emulator.

Fix prefix handling to ignore misplaced REX bytes and to grok both
kinds of REP prefix properly. These fixes are from Jan Beulich
<jbeulich@novell.com>.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Jan 05 15:54:06 2007 +0000 (2007-01-05)
parents 568efb79a0f6
children a22258c9fe75
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Fri Jan 05 15:52:58 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Fri Jan 05 15:54:06 2007 +0000
     1.3 @@ -55,35 +55,35 @@ static uint8_t opcode_table[256] = {
     1.4      /* 0x00 - 0x07 */
     1.5      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
     1.6      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
     1.7 -    0, 0, 0, 0,
     1.8 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
     1.9      /* 0x08 - 0x0F */
    1.10      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.11      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.12 -    0, 0, 0, 0,
    1.13 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.14      /* 0x10 - 0x17 */
    1.15      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.16      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.17 -    0, 0, 0, 0,
    1.18 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.19      /* 0x18 - 0x1F */
    1.20      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.21      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.22 -    0, 0, 0, 0,
    1.23 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.24      /* 0x20 - 0x27 */
    1.25      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.26      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.27 -    0, 0, 0, 0,
    1.28 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.29      /* 0x28 - 0x2F */
    1.30      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.31      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.32 -    0, 0, 0, 0,
    1.33 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.34      /* 0x30 - 0x37 */
    1.35      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.36      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.37 -    0, 0, 0, 0,
    1.38 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.39      /* 0x38 - 0x3F */
    1.40      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.41      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.42 -    0, 0, 0, 0,
    1.43 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.44      /* 0x40 - 0x4F */
    1.45      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.46      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.47 @@ -108,8 +108,11 @@ static uint8_t opcode_table[256] = {
    1.48      ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
    1.49      ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
    1.50      0, DstReg|SrcNone|ModRM, 0, DstMem|SrcNone|ModRM|Mov,
    1.51 -    /* 0x90 - 0x9F */
    1.52 -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1.53 +    /* 0x90 - 0x97 */
    1.54 +    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.55 +    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.56 +    /* 0x98 - 0x9F */
    1.57 +    0, 0, 0, 0, 0, 0, 0, 0,
    1.58      /* 0xA0 - 0xA7 */
    1.59      ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
    1.60      ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
    1.61 @@ -134,10 +137,10 @@ static uint8_t opcode_table[256] = {
    1.62      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1.63      /* 0xF0 - 0xF7 */
    1.64      0, 0, 0, 0,
    1.65 -    0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
    1.66 +    0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
    1.67      /* 0xF8 - 0xFF */
    1.68 -    0, 0, 0, 0,
    1.69 -    0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
    1.70 +    ImplicitOps, ImplicitOps, 0, 0,
    1.71 +    ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
    1.72  };
    1.73  
    1.74  static uint8_t twobyte_table[256] = {
    1.75 @@ -488,7 +491,7 @@ x86_emulate(
    1.76          return -1;
    1.77      }
    1.78  
    1.79 -    /* Legacy prefixes. */
    1.80 +    /* Prefix bytes. */
    1.81      for ( i = 0; i < 8; i++ )
    1.82      {
    1.83          switch ( b = insn_fetch_type(uint8_t) )
    1.84 @@ -523,25 +526,26 @@ x86_emulate(
    1.85          case 0xf0: /* LOCK */
    1.86              lock_prefix = 1;
    1.87              break;
    1.88 +        case 0xf2: /* REPNE/REPNZ */
    1.89          case 0xf3: /* REP/REPE/REPZ */
    1.90              rep_prefix = 1;
    1.91              break;
    1.92 -        case 0xf2: /* REPNE/REPNZ */
    1.93 -            break;
    1.94 +        case 0x40 ... 0x4f: /* REX */
    1.95 +            if ( mode != X86EMUL_MODE_PROT64 )
    1.96 +                goto done_prefixes;
    1.97 +            rex_prefix = b;
    1.98 +            continue;
    1.99          default:
   1.100              goto done_prefixes;
   1.101          }
   1.102 +
   1.103 +        /* Any legacy prefix after a REX prefix nullifies its effect. */
   1.104 +        rex_prefix = 0;
   1.105      }
   1.106   done_prefixes:
   1.107  
   1.108 -    /* REX prefix. */
   1.109 -    if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
   1.110 -    {
   1.111 -        rex_prefix = b;
   1.112 -        if ( b & 8 ) /* REX.W */
   1.113 -            op_bytes = 8;
   1.114 -        b = insn_fetch_type(uint8_t);
   1.115 -    }
   1.116 +    if ( rex_prefix & 8 ) /* REX.W */
   1.117 +        op_bytes = 8;
   1.118  
   1.119      /* Opcode byte(s). */
   1.120      d = opcode_table[b];
   1.121 @@ -570,6 +574,7 @@ x86_emulate(
   1.122  
   1.123          if ( modrm_mod == 3 )
   1.124          {
   1.125 +            modrm_rm |= (rex_prefix & 1) << 3;
   1.126              ea.type = OP_REG;
   1.127              ea.reg  = decode_register(
   1.128                  modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));
   1.129 @@ -812,28 +817,52 @@ x86_emulate(
   1.130  
   1.131      switch ( b )
   1.132      {
   1.133 -    case 0x00 ... 0x05: add: /* add */
   1.134 +    case 0x04 ... 0x05: /* add imm,%%eax */
   1.135 +        dst.reg = (unsigned long *)&_regs.eax;
   1.136 +        dst.val = dst.orig_val = _regs.eax;
   1.137 +    case 0x00 ... 0x03: add: /* add */
   1.138          emulate_2op_SrcV("add", src, dst, _regs.eflags);
   1.139          break;
   1.140 -    case 0x08 ... 0x0d: or:  /* or */
   1.141 +    case 0x0c ... 0x0d: /* or imm,%%eax */
   1.142 +        dst.reg = (unsigned long *)&_regs.eax;
   1.143 +        dst.val = dst.orig_val = _regs.eax;
   1.144 +    case 0x08 ... 0x0b: or:  /* or */
   1.145          emulate_2op_SrcV("or", src, dst, _regs.eflags);
   1.146          break;
   1.147 -    case 0x10 ... 0x15: adc: /* adc */
   1.148 +    case 0x14 ... 0x15: /* adc imm,%%eax */
   1.149 +        dst.reg = (unsigned long *)&_regs.eax;
   1.150 +        dst.val = dst.orig_val = _regs.eax;
   1.151 +    case 0x10 ... 0x13: adc: /* adc */
   1.152          emulate_2op_SrcV("adc", src, dst, _regs.eflags);
   1.153          break;
   1.154 -    case 0x18 ... 0x1d: sbb: /* sbb */
   1.155 +    case 0x1c ... 0x1d: /* sbb imm,%%eax */
   1.156 +        dst.reg = (unsigned long *)&_regs.eax;
   1.157 +        dst.val = dst.orig_val = _regs.eax;
   1.158 +    case 0x18 ... 0x1b: sbb: /* sbb */
   1.159          emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
   1.160          break;
   1.161 -    case 0x20 ... 0x25: and: /* and */
   1.162 +    case 0x24 ... 0x25: /* and imm,%%eax */
   1.163 +        dst.reg = (unsigned long *)&_regs.eax;
   1.164 +        dst.val = dst.orig_val = _regs.eax;
   1.165 +    case 0x20 ... 0x23: and: /* and */
   1.166          emulate_2op_SrcV("and", src, dst, _regs.eflags);
   1.167          break;
   1.168 -    case 0x28 ... 0x2d: sub: /* sub */
   1.169 +    case 0x2c ... 0x2d: /* sub imm,%%eax */
   1.170 +        dst.reg = (unsigned long *)&_regs.eax;
   1.171 +        dst.val = dst.orig_val = _regs.eax;
   1.172 +    case 0x28 ... 0x2b: sub: /* sub */
   1.173          emulate_2op_SrcV("sub", src, dst, _regs.eflags);
   1.174          break;
   1.175 -    case 0x30 ... 0x35: xor: /* xor */
   1.176 +    case 0x34 ... 0x35: /* xor imm,%%eax */
   1.177 +        dst.reg = (unsigned long *)&_regs.eax;
   1.178 +        dst.val = dst.orig_val = _regs.eax;
   1.179 +    case 0x30 ... 0x33: xor: /* xor */
   1.180          emulate_2op_SrcV("xor", src, dst, _regs.eflags);
   1.181          break;
   1.182 -    case 0x38 ... 0x3d: cmp: /* cmp */
   1.183 +    case 0x3c ... 0x3d: /* cmp imm,%%eax */
   1.184 +        dst.reg = (unsigned long *)&_regs.eax;
   1.185 +        dst.val = dst.orig_val = _regs.eax;
   1.186 +    case 0x38 ... 0x3b: cmp: /* cmp */
   1.187          emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
   1.188          break;
   1.189      case 0x63: /* movsxd */
   1.190 @@ -857,7 +886,7 @@ x86_emulate(
   1.191      case 0x84 ... 0x85: test: /* test */
   1.192          emulate_2op_SrcV("test", src, dst, _regs.eflags);
   1.193          break;
   1.194 -    case 0x86 ... 0x87: /* xchg */
   1.195 +    case 0x86 ... 0x87: xchg: /* xchg */
   1.196          /* Write back the register source. */
   1.197          switch ( dst.bytes )
   1.198          {
   1.199 @@ -1011,6 +1040,8 @@ x86_emulate(
   1.200      return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
   1.201  
   1.202   special_insn:
   1.203 +    /* Default action: disable writeback. There may be no dest operand. */
   1.204 +    dst.orig_val = dst.val;
   1.205      if ( twobyte )
   1.206          goto twobyte_special_insn;
   1.207      if ( rep_prefix )
   1.208 @@ -1027,7 +1058,7 @@ x86_emulate(
   1.209      {
   1.210      case 0x40 ... 0x4f: /* inc/dec reg */
   1.211          dst.type  = OP_REG;
   1.212 -        dst.reg   = decode_register(b&7, &_regs, 0);
   1.213 +        dst.reg   = decode_register(b & 7, &_regs, 0);
   1.214          dst.bytes = op_bytes;
   1.215          dst.orig_val = dst.val = *dst.reg;
   1.216          if ( b & 8 )
   1.217 @@ -1040,14 +1071,16 @@ x86_emulate(
   1.218          dst.bytes = op_bytes;
   1.219          if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
   1.220              dst.bytes = 8;
   1.221 -        dst.val = *(unsigned long *)decode_register(b&7, &_regs, 0);
   1.222 +        dst.val = *(unsigned long *)decode_register(
   1.223 +            (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
   1.224          register_address_increment(_regs.esp, -dst.bytes);
   1.225          dst.mem.seg = x86_seg_ss;
   1.226          dst.mem.off = truncate_ea(_regs.esp);
   1.227          break;
   1.228      case 0x58 ... 0x5f: /* pop reg */
   1.229          dst.type  = OP_REG;
   1.230 -        dst.reg   = decode_register(b&7, &_regs, 0);
   1.231 +        dst.reg   = decode_register(
   1.232 +            (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
   1.233          dst.bytes = op_bytes;
   1.234          if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
   1.235              dst.bytes = 8;
   1.236 @@ -1056,6 +1089,18 @@ x86_emulate(
   1.237              goto done;
   1.238          register_address_increment(_regs.esp, dst.bytes);
   1.239          break;
   1.240 +    case 0x90: /* nop / xchg %%r8,%%rax */
   1.241 +        if ( !(rex_prefix & 1) )
   1.242 +            break; /* nop */
   1.243 +    case 0x91 ... 0x97: /* xchg reg,%%rax */
   1.244 +        src.type = OP_REG;
   1.245 +        src.reg  = (unsigned long *)&_regs.eax;
   1.246 +        src.val  = *src.reg;
   1.247 +        dst.type = OP_REG;
   1.248 +        dst.reg  = decode_register(
   1.249 +            (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
   1.250 +        dst.val  = dst.orig_val = *dst.reg;
   1.251 +        goto xchg;
   1.252      case 0xa0 ... 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
   1.253          /* Source EA is not encoded via ModRM. */
   1.254          dst.type  = OP_REG;
   1.255 @@ -1105,6 +1150,21 @@ x86_emulate(
   1.256          register_address_increment(
   1.257              _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.258          break;
   1.259 +    case 0xf5: /* cmc */
   1.260 +        _regs.eflags ^= EFLG_CF;
   1.261 +        break;
   1.262 +    case 0xf8: /* clc */
   1.263 +        _regs.eflags &= ~EFLG_CF;
   1.264 +        break;
   1.265 +    case 0xf9: /* stc */
   1.266 +        _regs.eflags |= EFLG_CF;
   1.267 +        break;
   1.268 +    case 0xfc: /* cld */
   1.269 +        _regs.eflags &= ~EFLG_DF;
   1.270 +        break;
   1.271 +    case 0xfd: /* std */
   1.272 +        _regs.eflags |= EFLG_DF;
   1.273 +        break;
   1.274      }
   1.275      goto writeback;
   1.276  
   1.277 @@ -1218,8 +1278,6 @@ x86_emulate(
   1.278      goto writeback;
   1.279  
   1.280   twobyte_special_insn:
   1.281 -    /* Disable writeback. */
   1.282 -    dst.orig_val = dst.val;
   1.283      switch ( b )
   1.284      {
   1.285      case 0x0d: /* GrpP (prefetch) */