ia64/xen-unstable

changeset 13383:a84fc0de350d

[XEN] More emulator fixes and emulate BSWAP.
Better handling of LOCK prefix.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Jan 11 11:41:44 2007 +0000 (2007-01-11)
parents c8bfa8d94cf6
children 866a167bcb49
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Thu Jan 11 10:36:41 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Thu Jan 11 11:41:44 2007 +0000
     1.3 @@ -178,8 +178,16 @@ static uint8_t twobyte_table[256] = {
     1.4      /* 0x88 - 0x8F */
     1.5      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
     1.6      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
     1.7 -    /* 0x90 - 0x9F */
     1.8 -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     1.9 +    /* 0x90 - 0x97 */
    1.10 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.11 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.12 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.13 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.14 +    /* 0x98 - 0x9F */
    1.15 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.16 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.17 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.18 +    ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.19      /* 0xA0 - 0xA7 */
    1.20      0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 
    1.21      /* 0xA8 - 0xAF */
    1.22 @@ -195,7 +203,8 @@ static uint8_t twobyte_table[256] = {
    1.23      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0,
    1.24      0, 0, 0, ImplicitOps|ModRM,
    1.25      /* 0xC8 - 0xCF */
    1.26 -    0, 0, 0, 0, 0, 0, 0, 0,
    1.27 +    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.28 +    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.29      /* 0xD0 - 0xDF */
    1.30      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1.31      /* 0xE0 - 0xEF */
    1.32 @@ -206,7 +215,7 @@ static uint8_t twobyte_table[256] = {
    1.33  
    1.34  /* Type, address-of, and value of an instruction's operand. */
    1.35  struct operand {
    1.36 -    enum { OP_REG, OP_MEM, OP_IMM } type;
    1.37 +    enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
    1.38      unsigned int  bytes;
    1.39      unsigned long val, orig_val;
    1.40      union {
    1.41 @@ -635,6 +644,9 @@ x86_emulate(
    1.42              goto cannot_emulate;
    1.43      }
    1.44  
    1.45 +    /* Lock prefix is allowed only on RMW instructions. */
    1.46 +    generate_exception_if((d & Mov) && lock_prefix, EXC_GP);
    1.47 +
    1.48      /* ModRM and SIB bytes. */
    1.49      if ( d & ModRM )
    1.50      {
    1.51 @@ -874,13 +886,18 @@ x86_emulate(
    1.52              case 8: dst.val = *(uint64_t *)dst.reg; break;
    1.53              }
    1.54          }
    1.55 -        else if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
    1.56 -                  (rc = ops->read(dst.mem.seg, dst.mem.off,
    1.57 -                                  &dst.val, dst.bytes, ctxt)) )
    1.58 -            goto done;
    1.59 +        else if ( !(d & Mov) ) /* optimisation - avoid slow emulated read */
    1.60 +        {
    1.61 +            if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
    1.62 +                                 &dst.val, dst.bytes, ctxt)) )
    1.63 +                goto done;
    1.64 +            dst.orig_val = dst.val;
    1.65 +        }
    1.66          break;
    1.67      }
    1.68 -    dst.orig_val = dst.val;
    1.69 +
    1.70 +    /* LOCK prefix allowed only on instructions with memory destination. */
    1.71 +    generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP);
    1.72  
    1.73      if ( twobyte )
    1.74          goto twobyte_insn;
    1.75 @@ -889,56 +906,56 @@ x86_emulate(
    1.76      {
    1.77      case 0x04 ... 0x05: /* add imm,%%eax */
    1.78          dst.reg = (unsigned long *)&_regs.eax;
    1.79 -        dst.val = dst.orig_val = _regs.eax;
    1.80 +        dst.val = _regs.eax;
    1.81      case 0x00 ... 0x03: add: /* add */
    1.82          emulate_2op_SrcV("add", src, dst, _regs.eflags);
    1.83          break;
    1.84  
    1.85      case 0x0c ... 0x0d: /* or imm,%%eax */
    1.86          dst.reg = (unsigned long *)&_regs.eax;
    1.87 -        dst.val = dst.orig_val = _regs.eax;
    1.88 +        dst.val = _regs.eax;
    1.89      case 0x08 ... 0x0b: or:  /* or */
    1.90          emulate_2op_SrcV("or", src, dst, _regs.eflags);
    1.91          break;
    1.92  
    1.93      case 0x14 ... 0x15: /* adc imm,%%eax */
    1.94          dst.reg = (unsigned long *)&_regs.eax;
    1.95 -        dst.val = dst.orig_val = _regs.eax;
    1.96 +        dst.val = _regs.eax;
    1.97      case 0x10 ... 0x13: adc: /* adc */
    1.98          emulate_2op_SrcV("adc", src, dst, _regs.eflags);
    1.99          break;
   1.100  
   1.101      case 0x1c ... 0x1d: /* sbb imm,%%eax */
   1.102          dst.reg = (unsigned long *)&_regs.eax;
   1.103 -        dst.val = dst.orig_val = _regs.eax;
   1.104 +        dst.val = _regs.eax;
   1.105      case 0x18 ... 0x1b: sbb: /* sbb */
   1.106          emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
   1.107          break;
   1.108  
   1.109      case 0x24 ... 0x25: /* and imm,%%eax */
   1.110          dst.reg = (unsigned long *)&_regs.eax;
   1.111 -        dst.val = dst.orig_val = _regs.eax;
   1.112 +        dst.val = _regs.eax;
   1.113      case 0x20 ... 0x23: and: /* and */
   1.114          emulate_2op_SrcV("and", src, dst, _regs.eflags);
   1.115          break;
   1.116  
   1.117      case 0x2c ... 0x2d: /* sub imm,%%eax */
   1.118          dst.reg = (unsigned long *)&_regs.eax;
   1.119 -        dst.val = dst.orig_val = _regs.eax;
   1.120 +        dst.val = _regs.eax;
   1.121      case 0x28 ... 0x2b: sub: /* sub */
   1.122          emulate_2op_SrcV("sub", src, dst, _regs.eflags);
   1.123          break;
   1.124  
   1.125      case 0x34 ... 0x35: /* xor imm,%%eax */
   1.126          dst.reg = (unsigned long *)&_regs.eax;
   1.127 -        dst.val = dst.orig_val = _regs.eax;
   1.128 +        dst.val = _regs.eax;
   1.129      case 0x30 ... 0x33: xor: /* xor */
   1.130          emulate_2op_SrcV("xor", src, dst, _regs.eflags);
   1.131          break;
   1.132  
   1.133      case 0x3c ... 0x3d: /* cmp imm,%%eax */
   1.134          dst.reg = (unsigned long *)&_regs.eax;
   1.135 -        dst.val = dst.orig_val = _regs.eax;
   1.136 +        dst.val = _regs.eax;
   1.137      case 0x38 ... 0x3b: cmp: /* cmp */
   1.138          emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
   1.139          break;
   1.140 @@ -965,7 +982,7 @@ x86_emulate(
   1.141  
   1.142      case 0xa8 ... 0xa9: /* test imm,%%eax */
   1.143          dst.reg = (unsigned long *)&_regs.eax;
   1.144 -        dst.val = dst.orig_val = _regs.eax;
   1.145 +        dst.val = _regs.eax;
   1.146      case 0x84 ... 0x85: test: /* test */
   1.147          emulate_2op_SrcV("test", src, dst, _regs.eflags);
   1.148          break;
   1.149 @@ -1106,7 +1123,7 @@ x86_emulate(
   1.150              if ( (rc = ops->write(x86_seg_ss, truncate_ea(_regs.esp),
   1.151                                    dst.val, dst.bytes, ctxt)) != 0 )
   1.152                  goto done;
   1.153 -            dst.val = dst.orig_val; /* skanky: disable writeback */
   1.154 +            dst.type = OP_NONE;
   1.155              break;
   1.156          case 7:
   1.157              fail_if(1);
   1.158 @@ -1117,33 +1134,32 @@ x86_emulate(
   1.159      }
   1.160  
   1.161   writeback:
   1.162 -    if ( (d & Mov) || (dst.orig_val != dst.val) )
   1.163 +    switch ( dst.type )
   1.164      {
   1.165 -        switch ( dst.type )
   1.166 +    case OP_REG:
   1.167 +        /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
   1.168 +        switch ( dst.bytes )
   1.169          {
   1.170 -        case OP_REG:
   1.171 -            /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
   1.172 -            switch ( dst.bytes )
   1.173 -            {
   1.174 -            case 1: *(uint8_t  *)dst.reg = (uint8_t)dst.val; break;
   1.175 -            case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
   1.176 -            case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
   1.177 -            case 8: *dst.reg = dst.val; break;
   1.178 -            }
   1.179 -            break;
   1.180 -        case OP_MEM:
   1.181 -            if ( lock_prefix )
   1.182 -                rc = ops->cmpxchg(
   1.183 -                    dst.mem.seg, dst.mem.off, dst.orig_val,
   1.184 -                    dst.val, dst.bytes, ctxt);
   1.185 -            else
   1.186 -                rc = ops->write(
   1.187 -                    dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
   1.188 -            if ( rc != 0 )
   1.189 -                goto done;
   1.190 -        default:
   1.191 -            break;
   1.192 +        case 1: *(uint8_t  *)dst.reg = (uint8_t)dst.val; break;
   1.193 +        case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
   1.194 +        case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
   1.195 +        case 8: *dst.reg = dst.val; break;
   1.196          }
   1.197 +        break;
   1.198 +    case OP_MEM:
   1.199 +        if ( !(d & Mov) && (dst.orig_val == dst.val) )
   1.200 +            /* nothing to do */;
   1.201 +        else if ( lock_prefix )
   1.202 +            rc = ops->cmpxchg(
   1.203 +                dst.mem.seg, dst.mem.off, dst.orig_val,
   1.204 +                dst.val, dst.bytes, ctxt);
   1.205 +        else
   1.206 +            rc = ops->write(
   1.207 +                dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
   1.208 +        if ( rc != 0 )
   1.209 +            goto done;
   1.210 +    default:
   1.211 +        break;
   1.212      }
   1.213  
   1.214      /* Commit shadow register state. */
   1.215 @@ -1153,8 +1169,13 @@ x86_emulate(
   1.216      return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
   1.217  
   1.218   special_insn:
   1.219 -    /* Default action: disable writeback. There may be no dest operand. */
   1.220 -    dst.orig_val = dst.val;
   1.221 +    dst.type = OP_NONE;
   1.222 +
   1.223 +    /*
   1.224 +     * The only implicit-operands instruction allowed a LOCK prefix is
   1.225 +     * CMPXCHG{8,16}B.
   1.226 +     */
   1.227 +    generate_exception_if(lock_prefix && (b != 0xc7), EXC_GP);
   1.228  
   1.229      if ( twobyte )
   1.230          goto twobyte_special_insn;
   1.231 @@ -1235,7 +1256,7 @@ x86_emulate(
   1.232          dst.type  = OP_REG;
   1.233          dst.reg   = decode_register(b & 7, &_regs, 0);
   1.234          dst.bytes = op_bytes;
   1.235 -        dst.orig_val = dst.val = *dst.reg;
   1.236 +        dst.val   = *dst.reg;
   1.237          if ( b & 8 )
   1.238              emulate_1op("dec", dst, _regs.eflags);
   1.239          else
   1.240 @@ -1285,7 +1306,7 @@ x86_emulate(
   1.241          src.val  = *src.reg;
   1.242          dst.reg  = decode_register(
   1.243              (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
   1.244 -        dst.val  = dst.orig_val = *dst.reg;
   1.245 +        dst.val  = *dst.reg;
   1.246          goto xchg;
   1.247  
   1.248      case 0x9e: /* sahf */
   1.249 @@ -1430,9 +1451,14 @@ x86_emulate(
   1.250   twobyte_insn:
   1.251      switch ( b )
   1.252      {
   1.253 -    case 0x40 ... 0x4f: /* cmov */
   1.254 -        dst.val = dst.orig_val = src.val;
   1.255 -        d = (d & ~Mov) | (test_cc(b, _regs.eflags) ? Mov : 0);
   1.256 +    case 0x40 ... 0x4f: /* cmovcc */
   1.257 +        dst.val = src.val;
   1.258 +        if ( !test_cc(b, _regs.eflags) )
   1.259 +            dst.type = OP_NONE;
   1.260 +        break;
   1.261 +
   1.262 +    case 0x90 ... 0x9f: /* setcc */
   1.263 +        dst.val = test_cc(b, _regs.eflags);
   1.264          break;
   1.265  
   1.266      case 0xb0 ... 0xb1: /* cmpxchg */
   1.267 @@ -1580,6 +1606,37 @@ x86_emulate(
   1.268          break;
   1.269      }
   1.270  #endif
   1.271 +
   1.272 +    case 0xc8 ... 0xcf: /* bswap */
   1.273 +        dst.type  = OP_REG;
   1.274 +        dst.reg   = decode_register(b & 7, &_regs, 0);
   1.275 +        dst.val = *dst.reg;
   1.276 +        switch ( dst.bytes = op_bytes )
   1.277 +        {
   1.278 +        case 2:
   1.279 +            dst.val = (((dst.val & 0x00FFUL) << 8) |
   1.280 +                       ((dst.val & 0xFF00UL) >> 8));
   1.281 +            break;
   1.282 +        case 4:
   1.283 +            dst.val = (((dst.val & 0x000000FFUL) << 24) |
   1.284 +                       ((dst.val & 0x0000FF00UL) <<  8) |
   1.285 +                       ((dst.val & 0x00FF0000UL) >>  8) |
   1.286 +                       ((dst.val & 0xFF000000UL) >> 24));
   1.287 +            break;
   1.288 +#ifdef __x86_64__
   1.289 +        case 8:
   1.290 +            dst.val = (((dst.val & 0x00000000000000FFUL) << 56) |
   1.291 +                       ((dst.val & 0x000000000000FF00UL) << 40) |
   1.292 +                       ((dst.val & 0x0000000000FF0000UL) << 24) |
   1.293 +                       ((dst.val & 0x00000000FF000000UL) <<  8) |
   1.294 +                       ((dst.val & 0x000000FF00000000UL) >>  8) |
   1.295 +                       ((dst.val & 0x0000FF0000000000UL) >> 24) |
   1.296 +                       ((dst.val & 0x00FF000000000000UL) >> 40) |
   1.297 +                       ((dst.val & 0xFF00000000000000UL) >> 56));
   1.298 +            break;
   1.299 +#endif
   1.300 +        }
   1.301 +        break;
   1.302      }
   1.303      goto writeback;
   1.304