diff options
-rw-r--r-- | drivers/kvm/x86_emulate.c | 35 |
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; } |