[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86emul: also handle shifts through ->rmw()
commit 04a1a30c50615c1b578301eec7bbcd9ec482e41c Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Thu Mar 22 10:40:24 2018 +0100 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Thu Mar 22 10:40:24 2018 +0100 x86emul: also handle shifts through ->rmw() These don't allow LOCK, but still are read-modify-write operations, so are better handled that way too. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- tools/tests/x86_emulator/test_x86_emulator.c | 31 +++++++++ xen/arch/x86/x86_emulate/x86_emulate.c | 94 ++++++++++++++++++---------- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/tools/tests/x86_emulator/test_x86_emulator.c b/tools/tests/x86_emulator/test_x86_emulator.c index 8e99bfcbd0..ad9a5e72b7 100644 --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -585,6 +585,37 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); + printf("%-40s", "Testing rcll $2,(%edi)..."); + instr[0] = 0xc1; instr[1] = 0x17; instr[2] = 0x02; + *res = 0x2233445F; + regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS_CF; + regs.eip = (unsigned long)&instr[0]; + regs.edi = (unsigned long)res; + rc = x86_emulate(&ctxt, &emulops); + if ( (rc != X86EMUL_OKAY) || + (*res != ((0x2233445F << 2) | 2)) || + ((regs.eflags & (EFLAGS_MASK & ~X86_EFLAGS_OF)) + != EFLAGS_ALWAYS_SET) || + (regs.eip != (unsigned long)&instr[3]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing shrdl $8,%ecx,(%edi)..."); + instr[0] = 0x0f; instr[1] = 0xac; instr[2] = 0x0f; instr[3] = 0x08; + *res = 0x22334455; + regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS_CF; + regs.eip = (unsigned long)&instr[0]; + regs.ecx = 0x44332211; + regs.edi = (unsigned long)res; + rc = x86_emulate(&ctxt, &emulops); + if ( (rc != X86EMUL_OKAY) || + (*res != 0x11223344) || + ((regs.eflags & (EFLAGS_MASK & ~(X86_EFLAGS_OF|X86_EFLAGS_AF))) + != (EFLAGS_ALWAYS_SET | X86_EFLAGS_PF)) || + (regs.eip != (unsigned long)&instr[4]) ) + goto fail; + printf("okay\n"); + printf("%-40s", "Testing btrl $0x1,(%edi)..."); instr[0] = 0x0f; instr[1] = 0xba; instr[2] = 0x37; instr[3] = 0x01; *res = 0x2233445F; diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 5a07238090..d97e262386 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -682,7 +682,16 @@ struct x86_emulate_state { rmw_neg, rmw_not, rmw_or, + rmw_rcl, + rmw_rcr, + rmw_rol, + rmw_ror, + rmw_sar, rmw_sbb, + rmw_shl, + rmw_shld, + rmw_shr, + rmw_shrd, rmw_sub, rmw_xadd, rmw_xchg, @@ -4112,36 +4121,25 @@ x86_emulate( case 0xc0 ... 0xc1: grp2: /* Grp2 */ generate_exception_if(lock_prefix, EXC_UD); - if ( ops->rmw && dst.type == OP_MEM && - (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val, - dst.bytes, ctxt, ops)) != X86EMUL_OKAY ) - goto done; - dst.orig_val = dst.val; - switch ( modrm_reg & 7 ) { - case 0: /* rol */ - emulate_2op_SrcB("rol", src, dst, _regs.eflags); - break; - case 1: /* ror */ - emulate_2op_SrcB("ror", src, dst, _regs.eflags); - break; - case 2: /* rcl */ - emulate_2op_SrcB("rcl", src, dst, _regs.eflags); - break; - case 3: /* rcr */ - emulate_2op_SrcB("rcr", src, dst, _regs.eflags); - break; - case 4: /* sal/shl */ - case 6: /* sal/shl */ - emulate_2op_SrcB("sal", src, dst, _regs.eflags); - break; - case 5: /* shr */ - emulate_2op_SrcB("shr", src, dst, _regs.eflags); - break; - case 7: /* sar */ - emulate_2op_SrcB("sar", src, dst, _regs.eflags); - break; +#define GRP2(name, ext) \ + case ext: \ + if ( ops->rmw && dst.type == OP_MEM ) \ + state->rmw = rmw_##name; \ + else \ + emulate_2op_SrcB(#name, src, dst, _regs.eflags); \ + break + + GRP2(rol, 0); + GRP2(ror, 1); + GRP2(rcl, 2); + GRP2(rcr, 3); + case 6: /* sal/shl alias */ + GRP2(shl, 4); + GRP2(shr, 5); + GRP2(sar, 7); +#undef GRP2 } break; @@ -6571,11 +6569,6 @@ x86_emulate( generate_exception_if(lock_prefix, EXC_UD); - if ( ops->rmw && dst.type == OP_MEM && - (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val, - dst.bytes, ctxt, ops)) != X86EMUL_OKAY ) - goto done; - if ( b & 1 ) shift = _regs.cl; else @@ -6584,6 +6577,14 @@ x86_emulate( src.reg = decode_gpr(&_regs, modrm_reg); src.val = truncate_word(*src.reg, dst.bytes); } + + if ( ops->rmw && dst.type == OP_MEM ) + { + ea.orig_val = shift; + state->rmw = b & 8 ? rmw_shrd : rmw_shld; + break; + } + if ( (shift &= width - 1) == 0 ) break; dst.orig_val = dst.val; @@ -8730,6 +8731,11 @@ int x86_emul_rmw( state->ea.val, dst, bytes, *eflags, \ "c" ((long)state->lock_prefix) ); \ break +#define SHIFT(op) \ + case rmw_##op: \ + ASSERT(!state->lock_prefix); \ + _emulate_2op_SrcB(#op, state->ea.val, dst, bytes, *eflags); \ + break BINOP(adc, ); BINOP(add, ); @@ -8741,12 +8747,20 @@ int x86_emul_rmw( UNOP(inc); UNOP(neg); BINOP(or, ); + SHIFT(rcl); + SHIFT(rcr); + SHIFT(rol); + SHIFT(ror); + SHIFT(sar); BINOP(sbb, ); + SHIFT(shl); + SHIFT(shr); BINOP(sub, ); BINOP(xor, ); #undef UNOP #undef BINOP +#undef SHIFT case rmw_not: switch ( state->op_bytes ) @@ -8772,6 +8786,20 @@ int x86_emul_rmw( } break; + case rmw_shld: + ASSERT(!state->lock_prefix); + _emulate_2op_SrcV_nobyte("shld", + state->ea.val, dst, bytes, *eflags, + "c" (state->ea.orig_val) ); + break; + + case rmw_shrd: + ASSERT(!state->lock_prefix); + _emulate_2op_SrcV_nobyte("shrd", + state->ea.val, dst, bytes, *eflags, + "c" (state->ea.orig_val) ); + break; + case rmw_xadd: switch ( state->op_bytes ) { -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |