diff options
author | Avi Kivity <avi@qumranet.com> | 2007-10-28 16:34:25 +0200 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 17:52:57 +0200 |
commit | c7e75a3db4ecd952e7a5562cea1b27007bf0c01c (patch) | |
tree | a83547a4a40ff4c05a62ab5eb112d4417462d235 /drivers | |
parent | fe7935d49fbe33308c1b5f0e35137989da851010 (diff) |
KVM: x86 emulator: don't depend on cr2 for mov abs emulation
The 'mov abs' instruction family (opcodes 0xa0 - 0xa3) still depends on cr2
provided by the page fault handler. This is wrong for several reasons:
- if an instruction accessed misaligned data that crosses a page boundary,
and if the fault happened on the second page, cr2 will point at the
second page, not the data itself.
- if we're emulating in real mode, or due to a FlexPriority exit, there
is no cr2 generated.
So, this change adds decoding for this instruction form and drops reliance
on cr2.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/x86_emulate.c | 50 |
1 files changed, 30 insertions, 20 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 73e3580c88e..087a8208f87 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -63,8 +63,9 @@ /* Destination is only written; never read. */ #define Mov (1<<7) #define BitOp (1<<8) +#define MemAbs (1<<9) /* Memory operand is absolute displacement */ -static u8 opcode_table[256] = { +static u16 opcode_table[256] = { /* 0x00 - 0x07 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, @@ -134,8 +135,8 @@ static u8 opcode_table[256] = { /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0, /* 0xA0 - 0xA7 */ - ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, - ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, + ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs, + ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, ByteOp | ImplicitOps, ImplicitOps, /* 0xA8 - 0xAF */ @@ -755,16 +756,6 @@ done_prefixes: break; } } - if (!c->override_base) - c->override_base = &ctxt->ds_base; - if (mode == X86EMUL_MODE_PROT64 && - c->override_base != &ctxt->fs_base && - c->override_base != &ctxt->gs_base) - c->override_base = NULL; - - if (c->override_base) - c->modrm_ea += *c->override_base; - if (rip_relative) { c->modrm_ea += c->eip; switch (c->d & SrcMask) { @@ -781,12 +772,35 @@ done_prefixes: c->modrm_ea += c->op_bytes; } } - if (c->ad_bytes != 8) - c->modrm_ea = (u32)c->modrm_ea; modrm_done: ; + } else if (c->d & MemAbs) { + switch (c->ad_bytes) { + case 2: + c->modrm_ea = insn_fetch(u16, 2, c->eip); + break; + case 4: + c->modrm_ea = insn_fetch(u32, 4, c->eip); + break; + case 8: + c->modrm_ea = insn_fetch(u64, 8, c->eip); + break; + } + } + if (!c->override_base) + c->override_base = &ctxt->ds_base; + if (mode == X86EMUL_MODE_PROT64 && + c->override_base != &ctxt->fs_base && + c->override_base != &ctxt->gs_base) + c->override_base = NULL; + + if (c->override_base) + c->modrm_ea += *c->override_base; + + if (c->ad_bytes != 8) + c->modrm_ea = (u32)c->modrm_ea; /* * Decode and fetch the source operand: register, memory * or immediate. @@ -1171,7 +1185,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) memcpy(c->regs, ctxt->vcpu->regs, sizeof c->regs); saved_eip = c->eip; - if ((c->d & ModRM) && (c->modrm_mod != 3)) + if (((c->d & ModRM) && (c->modrm_mod != 3)) || (c->d & MemAbs)) cr2 = c->modrm_ea; if (c->src.type == OP_MEM) { @@ -1326,13 +1340,9 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) case 0xa0 ... 0xa1: /* mov */ c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; c->dst.val = c->src.val; - /* skip src displacement */ - c->eip += c->ad_bytes; break; case 0xa2 ... 0xa3: /* mov */ c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX]; - /* skip c->dst displacement */ - c->eip += c->ad_bytes; break; case 0xc0 ... 0xc1: emulate_grp2(ctxt); |