[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] 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@xxxxxxxxxxxxxxx> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -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. */ --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -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 ) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |