summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}