aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-09 10:09:04 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-09 10:09:04 +0000
commit98f4e2606f230327d128e88c3797a0744b512248 (patch)
treee69f5b43da0654e101a3ca564f7f218fe90cfa17
parentaa96438e580e76a181ae3ba923f9c204a8c1a3a5 (diff)
downloadxen-98f4e2606f230327d128e88c3797a0744b512248.tar.gz
xen-98f4e2606f230327d128e88c3797a0744b512248.tar.bz2
xen-98f4e2606f230327d128e88c3797a0744b512248.zip
Fix x86_emulate() handling of imul with immediate operands.
This fixes a repeatable crash in RHEL 4.2 ext2 filesystem during boot. Signed-off-by: Gary Grebus <ggrebus@virtualiron.com> Signed-off-by: Ben Guthro <bguthro@virtualiron.com>
-rw-r--r--xen/arch/x86/x86_emulate.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index 66ea5a8454..f894047068 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -103,8 +103,8 @@ static uint8_t opcode_table[256] = {
ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcMem16|ModRM|Mov,
0, 0, 0, 0,
/* 0x68 - 0x6F */
- ImplicitOps|Mov, DstMem|SrcImm|ModRM|Mov,
- ImplicitOps|Mov, DstMem|SrcImmByte|ModRM|Mov,
+ ImplicitOps|Mov, DstReg|SrcImm|ModRM|Mov,
+ ImplicitOps|Mov, DstReg|SrcImmByte|ModRM|Mov,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x70 - 0x77 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
@@ -1331,34 +1331,37 @@ x86_emulate(
case 0x69: /* imul imm16/32 */
case 0x6b: /* imul imm8 */ {
- unsigned long reg = *(long *)decode_register(modrm_reg, &_regs, 0);
+ unsigned long src1; /* ModR/M source operand */
+ if ( ea.type == OP_REG )
+ src1 = *ea.reg;
+ else if ( (rc = ops->read(ea.mem.seg, ea.mem.off,
+ &src1, op_bytes, ctxt)) )
+ goto done;
_regs.eflags &= ~(EFLG_OF|EFLG_CF);
switch ( dst.bytes )
{
case 2:
dst.val = ((uint32_t)(int16_t)src.val *
- (uint32_t)(int16_t)reg);
+ (uint32_t)(int16_t)src1);
if ( (int16_t)dst.val != (uint32_t)dst.val )
_regs.eflags |= EFLG_OF|EFLG_CF;
break;
#ifdef __x86_64__
case 4:
dst.val = ((uint64_t)(int32_t)src.val *
- (uint64_t)(int32_t)reg);
+ (uint64_t)(int32_t)src1);
if ( (int32_t)dst.val != dst.val )
_regs.eflags |= EFLG_OF|EFLG_CF;
break;
#endif
default: {
- unsigned long m[2] = { src.val, reg };
+ unsigned long m[2] = { src.val, src1 };
if ( imul_dbl(m) )
_regs.eflags |= EFLG_OF|EFLG_CF;
dst.val = m[0];
break;
}
}
- dst.type = OP_REG;
- dst.reg = decode_register(modrm_reg, &_regs, 0);
break;
}