ia64/xen-unstable

changeset 16498:0b9048f7f257

x86_emulate: Emulate SHLD and SHRD instructions.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 28 22:09:19 2007 +0000 (2007-11-28)
parents c555a5f97982
children e10eacec8b91
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Wed Nov 28 13:36:56 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Wed Nov 28 22:09:19 2007 +0000
     1.3 @@ -228,10 +228,10 @@ static uint8_t twobyte_table[256] = {
     1.4      ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
     1.5      /* 0xA0 - 0xA7 */
     1.6      ImplicitOps, ImplicitOps, ImplicitOps, DstBitBase|SrcReg|ModRM,
     1.7 -    0, 0, 0, 0, 
     1.8 +    DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0, 
     1.9      /* 0xA8 - 0xAF */
    1.10      ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM,
    1.11 -    0, 0, 0, DstReg|SrcMem|ModRM,
    1.12 +    DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstReg|SrcMem|ModRM,
    1.13      /* 0xB0 - 0xB7 */
    1.14      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.15      DstReg|SrcMem|ModRM|Mov, DstBitBase|SrcReg|ModRM,
    1.16 @@ -484,13 +484,13 @@ do{ asm volatile (                      
    1.17  })
    1.18  #define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
    1.19  
    1.20 -#define _truncate_ea(ea, byte_width)            \
    1.21 +#define truncate_word(ea, byte_width)           \
    1.22  ({  unsigned long __ea = (ea);                  \
    1.23      unsigned int _width = (byte_width);         \
    1.24      ((_width == sizeof(unsigned long)) ? __ea : \
    1.25       (__ea & ((1UL << (_width << 3)) - 1)));    \
    1.26  })
    1.27 -#define truncate_ea(ea) _truncate_ea((ea), ad_bytes)
    1.28 +#define truncate_ea(ea) truncate_word((ea), ad_bytes)
    1.29  
    1.30  #define mode_64bit() (def_ad_bytes == 8)
    1.31  
    1.32 @@ -508,12 +508,11 @@ do {                                    
    1.33      }                                                                   \
    1.34  })
    1.35  
    1.36 -/* Given byte has even parity (even number of 1s)? */
    1.37 -static int even_parity(uint8_t v)
    1.38 +/* Given longword has even parity (even number of 1s)? */
    1.39 +static int even_parity(unsigned long v)
    1.40  {
    1.41 -    asm ( "test %%al,%%al; setp %%al"
    1.42 -              : "=a" (v) : "0" (v) );
    1.43 -    return v;
    1.44 +    asm ( "test %0,%0; setp %b0" : "=a" (v) : "0" (v) );
    1.45 +    return (uint8_t)v;
    1.46  }
    1.47  
    1.48  /* Update address held in a register, based on addressing mode. */
    1.49 @@ -534,10 +533,10 @@ do {                                    
    1.50  
    1.51  #define sp_pre_dec(dec) ({                                              \
    1.52      _register_address_increment(_regs.esp, -(dec), ctxt->sp_size/8);    \
    1.53 -    _truncate_ea(_regs.esp, ctxt->sp_size/8);                           \
    1.54 +    truncate_word(_regs.esp, ctxt->sp_size/8);                          \
    1.55  })
    1.56  #define sp_post_inc(inc) ({                                             \
    1.57 -    unsigned long __esp = _truncate_ea(_regs.esp, ctxt->sp_size/8);     \
    1.58 +    unsigned long __esp = truncate_word(_regs.esp, ctxt->sp_size/8);    \
    1.59      _register_address_increment(_regs.esp, (inc), ctxt->sp_size/8);     \
    1.60      __esp;                                                              \
    1.61  })
    1.62 @@ -1915,7 +1914,7 @@ x86_emulate(
    1.63          _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
    1.64          _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
    1.65          _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
    1.66 -        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
    1.67 +        _regs.eflags |= even_parity((uint8_t)_regs.eax) ? EFLG_PF : 0;
    1.68          break;
    1.69      }
    1.70  
    1.71 @@ -1939,7 +1938,7 @@ x86_emulate(
    1.72          _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
    1.73          _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
    1.74          _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
    1.75 -        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
    1.76 +        _regs.eflags |= even_parity((uint8_t)_regs.eax) ? EFLG_PF : 0;
    1.77          break;
    1.78      }
    1.79  
    1.80 @@ -2288,7 +2287,7 @@ x86_emulate(
    1.81              for ( i = 1; i < depth; i++ )
    1.82              {
    1.83                  unsigned long ebp, temp_data;
    1.84 -                ebp = _truncate_ea(_regs.ebp - i*dst.bytes, ctxt->sp_size/8);
    1.85 +                ebp = truncate_word(_regs.ebp - i*dst.bytes, ctxt->sp_size/8);
    1.86                  if ( (rc = ops->read(x86_seg_ss, ebp,
    1.87                                       &temp_data, dst.bytes, ctxt)) ||
    1.88                       (rc = ops->write(x86_seg_ss, sp_pre_dec(dst.bytes),
    1.89 @@ -2396,7 +2395,7 @@ x86_emulate(
    1.90          _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
    1.91          _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
    1.92          _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
    1.93 -        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
    1.94 +        _regs.eflags |= even_parity((uint8_t)_regs.eax) ? EFLG_PF : 0;
    1.95          break;
    1.96      }
    1.97  
    1.98 @@ -2408,7 +2407,7 @@ x86_emulate(
    1.99          _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
   1.100          _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
   1.101          _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
   1.102 -        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
   1.103 +        _regs.eflags |= even_parity((uint8_t)_regs.eax) ? EFLG_PF : 0;
   1.104          break;
   1.105      }
   1.106  
   1.107 @@ -2607,6 +2606,35 @@ x86_emulate(
   1.108          emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags);
   1.109          break;
   1.110  
   1.111 +    case 0xa4: /* shld imm8,r,r/m */
   1.112 +    case 0xa5: /* shld %%cl,r,r/m */
   1.113 +    case 0xac: /* shrd imm8,r,r/m */
   1.114 +    case 0xad: /* shrd %%cl,r,r/m */ {
   1.115 +        uint8_t shift, width = dst.bytes << 3;
   1.116 +        shift = (b & 1) ? (uint8_t)_regs.ecx : insn_fetch_type(uint8_t);
   1.117 +        if ( (shift &= width - 1) == 0 )
   1.118 +            break;
   1.119 +        dst.orig_val = truncate_word(dst.orig_val, dst.bytes);
   1.120 +        dst.val = ((shift == width) ? src.val :
   1.121 +                   (b & 8) ?
   1.122 +                   /* shrd */
   1.123 +                   ((dst.orig_val >> shift) |
   1.124 +                    truncate_word(src.val << (width - shift), dst.bytes)) :
   1.125 +                   /* shld */
   1.126 +                   ((dst.orig_val << shift) |
   1.127 +                    ((src.val >> (width - shift)) & ((1ull << shift) - 1))));
   1.128 +        dst.val = truncate_word(dst.val, dst.bytes);
   1.129 +        _regs.eflags &= ~(EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_PF|EFLG_CF);
   1.130 +        if ( (dst.val >> ((b & 8) ? (shift - 1) : (width - shift))) & 1 )
   1.131 +            _regs.eflags |= EFLG_CF;
   1.132 +        if ( ((dst.val ^ dst.orig_val) >> (width - 1)) & 1 )
   1.133 +            _regs.eflags |= EFLG_OF;
   1.134 +        _regs.eflags |= ((dst.val >> (width - 1)) & 1) ? EFLG_SF : 0;
   1.135 +        _regs.eflags |= (dst.val == 0) ? EFLG_ZF : 0;
   1.136 +        _regs.eflags |= even_parity(dst.val) ? EFLG_PF : 0;
   1.137 +        break;
   1.138 +    }
   1.139 +
   1.140      case 0xb3: btr: /* btr */
   1.141          emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags);
   1.142          break;