From 0af1b466c4489fca6640de4c49cc9efaad51538e Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 23 Nov 2016 15:27:17 +0100 Subject: [PATCH] x86emul: simplify DstBitBase handling code ..., at once making it more obvious that even in the negative bit offset case the resulting bit offset to be used by the inlined instructions will always be constrained to the operand size of the original instruction. Also add a test case which would have failed without the XSA-195 fix. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Release-acked-by: Wei Liu --- tools/tests/x86_emulator/test_x86_emulator.c | 16 ++++++++++++++++ xen/arch/x86/x86_emulate/x86_emulate.c | 11 ++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tools/tests/x86_emulator/test_x86_emulator.c b/tools/tests/x86_emulator/test_x86_emulator.c index 6f6d70f66d..948ee8d0f6 100644 --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -431,6 +431,22 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); +#ifdef __x86_64__ + printf("%-40s", "Testing btcq %r8,(%r11)..."); + instr[0] = 0x4d; instr[1] = 0x0f; instr[2] = 0xbb; instr[3] = 0x03; + regs.eflags = 0x200; + regs.rip = (unsigned long)&instr[0]; + regs.r8 = (-1L << 40) + 1; + regs.r11 = (unsigned long)(res + (1L << 35)); + rc = x86_emulate(&ctxt, &emulops); + if ( (rc != X86EMUL_OKAY) || + (*res != 0x2233445C) || + (regs.eflags != 0x201) || + (regs.rip != (unsigned long)&instr[4]) ) + goto fail; + printf("okay\n"); +#endif + res[0] = 0x12345678; res[1] = 0x87654321; diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 2cf819b7e6..a85f45e2bb 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -2560,18 +2560,11 @@ x86_emulate( else if ( op_bytes == 4 ) src.val = (int32_t)src.val; if ( (long)src.val < 0 ) - { - unsigned long byte_offset = + ea.mem.off -= op_bytes + (((-src.val - 1) >> 3) & ~(op_bytes - 1L)); - - ea.mem.off -= byte_offset; - src.val = (byte_offset << 3) + src.val; - } else - { ea.mem.off += (src.val >> 3) & ~(op_bytes - 1L); - src.val &= (op_bytes << 3) - 1; - } + src.val &= (op_bytes << 3) - 1; } /* Becomes a normal DstMem operation from here on. */ d = (d & ~DstMask) | DstMem; -- 2.30.2