aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Vivier <Laurent.Vivier@bull.net>2007-10-01 11:01:06 +0200
committerAvi Kivity <avi@qumranet.com>2007-10-02 08:05:27 +0200
commit06ba8d55ba4052ded08eea5bed9519c6f6780d8c (patch)
treea26f40da61c8beac0dd5a9fae36e2ca8b66a280c
parentc78fc6fb953bbbd9e0b931759b03162768991132 (diff)
KVM: x86 emulator: Correct management of REP prefixkvm-45
This patch corrects some errors appearing when we have an emulation failure on an operation using REP prefix. When x86_emulate_insn() fails, saving EIP and ECX is not enough as emulation should have modified other registers like RSI or RDI. Moreover, the emulation can fail on the writeback, and in this case we are not able to restore registers. At beginning of x86_emulate_insn(), we restore registers from vcpu as they were not modified by x86d_decode_insn() and we save EIP to be able to restore it in case of failure. Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net> Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/x86_emulate.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 35069e36268f..887de7de4fdc 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -1146,10 +1146,18 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
unsigned long cr2 = ctxt->cr2;
u64 msr_data;
- unsigned long saved_rcx = 0, saved_eip = 0;
+ unsigned long saved_eip;
struct decode_cache *c = &ctxt->decode;
int rc = 0;
+ /* Shadow copy of register state. Committed on successful emulation.
+ * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't
+ * modify them.
+ */
+
+ memcpy(c->regs, ctxt->vcpu->regs, sizeof c->regs);
+ saved_eip = c->eip;
+
if ((c->d & ModRM) && (c->modrm_mod != 3))
cr2 = c->modrm_ea;
@@ -1354,7 +1362,11 @@ writeback:
ctxt->vcpu->rip = c->eip;
done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ if (rc == X86EMUL_UNHANDLEABLE) {
+ c->eip = saved_eip;
+ return -1;
+ }
+ return 0;
special_insn:
if (c->twobyte)
@@ -1396,8 +1408,10 @@ special_insn:
register_address(ctxt->es_base,
c->regs[VCPU_REGS_RDI]),
c->rep_prefix,
- c->regs[VCPU_REGS_RDX]) == 0)
+ c->regs[VCPU_REGS_RDX]) == 0) {
+ c->eip = saved_eip;
return -1;
+ }
return 0;
case 0x6e: /* outsb */
case 0x6f: /* outsw/outsd */
@@ -1412,8 +1426,10 @@ special_insn:
ctxt->ds_base,
c->regs[VCPU_REGS_RSI]),
c->rep_prefix,
- c->regs[VCPU_REGS_RDX]) == 0)
+ c->regs[VCPU_REGS_RDX]) == 0) {
+ c->eip = saved_eip;
return -1;
+ }
return 0;
case 0x70 ... 0x7f: /* jcc (short) */ {
int rel = insn_fetch(s8, 1, c->eip);
@@ -1441,8 +1457,6 @@ special_insn:
ctxt->vcpu->rip = c->eip;
goto done;
}
- saved_rcx = c->regs[VCPU_REGS_RCX];
- saved_eip = c->eip;
c->regs[VCPU_REGS_RCX]--;
c->eip = ctxt->vcpu->rip;
}
@@ -1459,10 +1473,6 @@ special_insn:
c->regs[VCPU_REGS_RSI]),
&c->dst.val,
c->dst.bytes, ctxt->vcpu)) != 0) {
- if (c->rep_prefix) {
- c->regs[VCPU_REGS_RCX] = saved_rcx;
- c->eip = saved_eip;
- }
goto done;
}
register_address_increment(c->regs[VCPU_REGS_RSI],
@@ -1491,10 +1501,6 @@ special_insn:
if ((rc = ops->read_emulated(cr2, &c->dst.val,
c->dst.bytes,
ctxt->vcpu)) != 0) {
- if (c->rep_prefix) {
- c->regs[VCPU_REGS_RCX] = saved_rcx;
- c->eip = saved_eip;
- }
goto done;
}
register_address_increment(c->regs[VCPU_REGS_RSI],
@@ -1762,5 +1768,6 @@ twobyte_special_insn:
cannot_emulate:
DPRINTF("Cannot emulate %02x\n", c->b);
+ c->eip = saved_eip;
return -1;
}