x86emul: simplify DstBitBase handling code
authorJan Beulich <jbeulich@suse.com>
Wed, 23 Nov 2016 14:27:17 +0000 (15:27 +0100)
committerJan Beulich <jbeulich@suse.com>
Wed, 23 Nov 2016 14:27:17 +0000 (15:27 +0100)
..., 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 <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-acked-by: Wei Liu <wei.liu2@citrix.com>
tools/tests/x86_emulator/test_x86_emulator.c
xen/arch/x86/x86_emulate/x86_emulate.c

index 6f6d70f66d129b32706dd6d9c036c54185f9b586..948ee8d0f6d74bc79aa460c4da8d4c30b0c98abb 100644 (file)
@@ -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;
 
index 2cf819b7e61001787b38d688b349cc3186b15dfc..a85f45e2bbcdd5ae0b0f262f09a588a4e87e1b79 100644 (file)
@@ -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;