mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
x86emul: fix 3-operand IMUL
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>
This commit is contained in:
1 parent
95d9996671
commit
19232b378f
2 files changed
+41
-4
No files matched your search
@@ -890,6 +890,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. */
|
||||
|
||||
@@ -5055,12 +5055,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);
|
||||
@@ -5068,7 +5069,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 )
|
||||
@@ -5077,7 +5078,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 )
|
||||
@@ -5086,7 +5087,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 )
|
||||
|
||||