ia64/xen-unstable

changeset 14034:4719e34ed7a7

x86: Fix emulation of REP prefix.
Firstly, it should be ignored when used with any opcode for which it
is undefined. Secondly, the count register (rCX) width depends on
address size.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Feb 20 16:57:50 2007 +0000 (2007-02-20)
parents b5ee25f50861
children e7994a122aab
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Tue Feb 20 16:19:40 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Tue Feb 20 16:57:50 2007 +0000
     1.3 @@ -519,6 +519,37 @@ do {                                    
     1.4                       ? (uint16_t)_regs.eip : (uint32_t)_regs.eip);      \
     1.5  } while (0)
     1.6  
     1.7 +static int __handle_rep_prefix(
     1.8 +    struct cpu_user_regs *int_regs,
     1.9 +    struct cpu_user_regs *ext_regs,
    1.10 +    int ad_bytes)
    1.11 +{
    1.12 +    unsigned long ecx = ((ad_bytes == 2) ? (uint16_t)int_regs->ecx :
    1.13 +                         (ad_bytes == 4) ? (uint32_t)int_regs->ecx :
    1.14 +                         int_regs->ecx);
    1.15 +
    1.16 +    if ( ecx-- == 0 )
    1.17 +    {
    1.18 +        ext_regs->eip = int_regs->eip;
    1.19 +        return 1;
    1.20 +    }
    1.21 +
    1.22 +    if ( ad_bytes == 2 )
    1.23 +        *(uint16_t *)&int_regs->ecx = ecx;
    1.24 +    else if ( ad_bytes == 4 )
    1.25 +        int_regs->ecx = (uint32_t)ecx;
    1.26 +    else
    1.27 +        int_regs->ecx = ecx;
    1.28 +    int_regs->eip = ext_regs->eip;
    1.29 +    return 0;
    1.30 +}
    1.31 +
    1.32 +#define handle_rep_prefix()                                                \
    1.33 +do {                                                                       \
    1.34 +    if ( rep_prefix && __handle_rep_prefix(&_regs, ctxt->regs, ad_bytes) ) \
    1.35 +        goto done;                                                         \
    1.36 +} while (0)
    1.37 +
    1.38  /*
    1.39   * Unsigned multiplication with double-word result.
    1.40   * IN:  Multiplicand=m[0], Multiplier=m[1]
    1.41 @@ -1579,17 +1610,6 @@ x86_emulate(
    1.42      if ( twobyte )
    1.43          goto twobyte_special_insn;
    1.44  
    1.45 -    if ( rep_prefix )
    1.46 -    {
    1.47 -        if ( _regs.ecx == 0 )
    1.48 -        {
    1.49 -            ctxt->regs->eip = _regs.eip;
    1.50 -            goto done;
    1.51 -        }
    1.52 -        _regs.ecx--;
    1.53 -        _regs.eip = ctxt->regs->eip;
    1.54 -    }
    1.55 -
    1.56      switch ( b )
    1.57      {
    1.58      case 0x27: /* daa */ {
    1.59 @@ -1727,6 +1747,7 @@ x86_emulate(
    1.60          break;
    1.61  
    1.62      case 0x6c ... 0x6d: /* ins %dx,%es:%edi */
    1.63 +        handle_rep_prefix();
    1.64          generate_exception_if(!mode_iopl(), EXC_GP);
    1.65          dst.type  = OP_MEM;
    1.66          dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
    1.67 @@ -1741,6 +1762,7 @@ x86_emulate(
    1.68          break;
    1.69  
    1.70      case 0x6e ... 0x6f: /* outs %esi,%dx */
    1.71 +        handle_rep_prefix();
    1.72          generate_exception_if(!mode_iopl(), EXC_GP);
    1.73          dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
    1.74          if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
    1.75 @@ -1827,6 +1849,7 @@ x86_emulate(
    1.76          break;
    1.77  
    1.78      case 0xa4 ... 0xa5: /* movs */
    1.79 +        handle_rep_prefix();
    1.80          dst.type  = OP_MEM;
    1.81          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
    1.82          dst.mem.seg = x86_seg_es;
    1.83 @@ -1841,6 +1864,7 @@ x86_emulate(
    1.84          break;
    1.85  
    1.86      case 0xaa ... 0xab: /* stos */
    1.87 +        handle_rep_prefix();
    1.88          dst.type  = OP_MEM;
    1.89          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
    1.90          dst.mem.seg = x86_seg_es;
    1.91 @@ -1851,6 +1875,7 @@ x86_emulate(
    1.92          break;
    1.93  
    1.94      case 0xac ... 0xad: /* lods */
    1.95 +        handle_rep_prefix();
    1.96          dst.type  = OP_REG;
    1.97          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
    1.98          dst.reg   = (unsigned long *)&_regs.eax;