]> xenbits.xensource.com Git - xen.git/commitdiff
x86emul: fix 3-operand IMUL
authorJan Beulich <jbeulich@suse.com>
Fri, 1 Feb 2019 11:05:11 +0000 (12:05 +0100)
committerJan Beulich <jbeulich@suse.com>
Fri, 1 Feb 2019 11:05:11 +0000 (12:05 +0100)
While commit 75066cd4ea ("x86emul: fix {,i}mul and {,i}div") indeed did
as its title says, it broke the 3-operand form by uniformly using AL/AX/
EAX/RAX as second source operand. Fix this and add tests covering both
cases.

Reported-by: Andrei Lutas <vlutas@bitdefender.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: 19232b378fab04997c0612e5c19e82c29b59d99e
master date: 2018-12-18 14:27:09 +0100

tools/tests/x86_emulator/test_x86_emulator.c
xen/arch/x86/x86_emulate/x86_emulate.c

index 1992c3fc92e6ecc3f366f1ff868f5b460b4dad38..afd99a7be6b9c80fbaee8f10d450afd28c6a5b5c 100644 (file)
@@ -700,6 +700,42 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
+    printf("%-40s", "Testing imull -4(%ecx)...");
+    instr[0] = 0xf7; instr[1] = 0x69; instr[2] = 0xfc;
+    regs.eflags = EFLAGS_ALWAYS_SET;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.eax    = 0x89abcdef;
+    res[0]      = 0x12345678;
+    regs.ecx    = (unsigned long)(res + 1);
+    rc = x86_emulate(&ctxt, &emulops);
+    if ( (rc != X86EMUL_OKAY) ||
+         (regs.eax != 0x89abcdef * 0x12345678) ||
+         (regs.edx != (uint64_t)((int64_t)(int32_t)0x89abcdef *
+                                 0x12345678) >> 32) ||
+         ((regs.eflags & (EFLAGS_ALWAYS_SET | X86_EFLAGS_CF |
+                          X86_EFLAGS_OF)) !=
+          (EFLAGS_ALWAYS_SET | X86_EFLAGS_CF | X86_EFLAGS_OF)) ||
+         (regs.eip != (unsigned long)&instr[3]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing imul $3,-4(%edx),%ecx...");
+    instr[0] = 0x6b; instr[1] = 0x4a; instr[2] = 0xfc; instr[3] = 0x03;
+    regs.eflags = EFLAGS_ALWAYS_SET;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.ecx    = 0x12345678;
+    res[0]      = 0x89abcdef;
+    regs.edx    = (unsigned long)(res + 1);
+    rc = x86_emulate(&ctxt, &emulops);
+    if ( (rc != X86EMUL_OKAY) ||
+         (regs.ecx != 0x89abcdef * 3) ||
+         ((regs.eflags & (EFLAGS_ALWAYS_SET | X86_EFLAGS_CF |
+                          X86_EFLAGS_OF)) !=
+          (EFLAGS_ALWAYS_SET | X86_EFLAGS_CF | X86_EFLAGS_OF)) ||
+         (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
 #ifndef __x86_64__
     printf("%-40s", "Testing daa/das (all inputs)...");
     /* Bits 0-7: AL; Bit 8: EFLAGS.AF; Bit 9: EFLAGS.CF; Bit 10: DAA vs. DAS. */
index 57fa0aae42ff37732027efca4ec74d8b114d1062..e2a1b1935a85412b10f68e8361acf59ddb9254e0 100644 (file)
@@ -4727,12 +4727,13 @@ x86_emulate(
             }
             break;
         case 5: /* imul */
+            dst.val = _regs.r(ax);
         imul:
             _regs.eflags &= ~(X86_EFLAGS_OF | X86_EFLAGS_CF);
             switch ( dst.bytes )
             {
             case 1:
-                dst.val = (int8_t)src.val * (int8_t)_regs.al;
+                dst.val = (int8_t)src.val * (int8_t)dst.val;
                 if ( (int8_t)dst.val != (int16_t)dst.val )
                     _regs.eflags |= X86_EFLAGS_OF | X86_EFLAGS_CF;
                 ASSERT(b > 0x6b);
@@ -4740,7 +4741,7 @@ x86_emulate(
                 break;
             case 2:
                 dst.val = ((uint32_t)(int16_t)src.val *
-                           (uint32_t)(int16_t)_regs.ax);
+                           (uint32_t)(int16_t)dst.val);
                 if ( (int16_t)dst.val != (int32_t)dst.val )
                     _regs.eflags |= X86_EFLAGS_OF | X86_EFLAGS_CF;
                 if ( b > 0x6b )
@@ -4749,7 +4750,7 @@ x86_emulate(
 #ifdef __x86_64__
             case 4:
                 dst.val = ((uint64_t)(int32_t)src.val *
-                           (uint64_t)(int32_t)_regs.eax);
+                           (uint64_t)(int32_t)dst.val);
                 if ( (int32_t)dst.val != dst.val )
                     _regs.eflags |= X86_EFLAGS_OF | X86_EFLAGS_CF;
                 if ( b > 0x6b )
@@ -4758,7 +4759,7 @@ x86_emulate(
 #endif
             default:
                 u[0] = src.val;
-                u[1] = _regs.r(ax);
+                u[1] = dst.val;
                 if ( imul_dbl(u) )
                     _regs.eflags |= X86_EFLAGS_OF | X86_EFLAGS_CF;
                 if ( b > 0x6b )