debuggers.hg
changeset 16527:0b9048f7f257
x86_emulate: Emulate SHLD and SHRD instructions.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
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;