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.
This patch takes another approach: at the beginning of x86_emulate_insn() we
restore state we have at end of x86_decode_insn(). To do that, we store EIP in
a new field in decode_cache, decode_eip. This field store the EIP as it is at
the end of x86_decode_insn(); and at beginning of x86_emulate_insn(), we restore
all registers as they are in vcpu. We can do that, because the x86_decode_insn()
doesn't modify registers (except EIP).
Signed-off-by: Laurent Vivier <[EMAIL PROTECTED]>
---
drivers/kvm/x86_emulate.c | 71 +++++++++++++++++++++++---------------------
drivers/kvm/x86_emulate.h | 1 +
2 files changed, 38 insertions(+), 34 deletions(-)
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 35069e3..3febb58 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -526,10 +526,11 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct
x86_emulate_ops *ops)
int mode = ctxt->mode;
int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
- /* Shadow copy of register state. Committed on successful emulation. */
-
memset(c, 0, sizeof(struct decode_cache));
- c->eip = ctxt->vcpu->rip;
+
+ /* decode_eip will contain EIP after decode phase */
+
+ c->decode_eip = ctxt->vcpu->rip;
memcpy(c->regs, ctxt->vcpu->regs, sizeof c->regs);
switch (mode) {
@@ -552,7 +553,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct
x86_emulate_ops *ops)
/* Legacy prefixes. */
for (;;) {
- switch (c->b = insn_fetch(u8, 1, c->eip)) {
+ switch (c->b = insn_fetch(u8, 1, c->decode_eip)) {
case 0x66: /* operand-size override */
c->op_bytes ^= 6; /* switch between 2/4 bytes */
break;
@@ -620,7 +621,7 @@ done_prefixes:
/* Two-byte opcode? */
if (c->b == 0x0f) {
c->twobyte = 1;
- c->b = insn_fetch(u8, 1, c->eip);
+ c->b = insn_fetch(u8, 1, c->decode_eip);
c->d = twobyte_table[c->b];
}
@@ -633,7 +634,7 @@ done_prefixes:
/* ModRM and SIB bytes. */
if (c->d & ModRM) {
- c->modrm = insn_fetch(u8, 1, c->eip);
+ c->modrm = insn_fetch(u8, 1, c->decode_eip);
c->modrm_mod |= (c->modrm & 0xc0) >> 6;
c->modrm_reg |= (c->modrm & 0x38) >> 3;
c->modrm_rm |= (c->modrm & 0x07);
@@ -657,13 +658,14 @@ done_prefixes:
case 0:
if (c->modrm_rm == 6)
c->modrm_ea +=
- insn_fetch(u16, 2, c->eip);
+ insn_fetch(u16, 2, c->decode_eip);
break;
case 1:
- c->modrm_ea += insn_fetch(s8, 1, c->eip);
+ c->modrm_ea += insn_fetch(s8, 1, c->decode_eip);
break;
case 2:
- c->modrm_ea += insn_fetch(u16, 2, c->eip);
+ c->modrm_ea += insn_fetch(u16, 2,
+ c->decode_eip);
break;
}
switch (c->modrm_rm) {
@@ -703,7 +705,7 @@ done_prefixes:
switch (c->modrm_rm) {
case 4:
case 12:
- sib = insn_fetch(u8, 1, c->eip);
+ sib = insn_fetch(u8, 1, c->decode_eip);
index_reg |= (sib >> 3) & 7;
base_reg |= sib & 7;
scale = sib >> 6;
@@ -714,8 +716,8 @@ done_prefixes:
c->modrm_ea +=
c->regs[base_reg];
else
- c->modrm_ea +=
- insn_fetch(s32, 4, c->eip);
+ c->modrm_ea += insn_fetch(s32,
+ 4, c->decode_eip);
break;
default:
c->modrm_ea += c->regs[base_reg];
@@ -742,14 +744,15 @@ done_prefixes:
switch (c->modrm_mod) {
case 0:
if (c->modrm_rm == 5)
- c->modrm_ea +=
- insn_fetch(s32, 4, c->eip);
+ c->modrm_ea += insn_fetch(s32, 4,
+ c->decode_eip);
break;
case 1:
- c->modrm_ea += insn_fetch(s8, 1, c->eip);
+ c->modrm_ea += insn_fetch(s8, 1, c->decode_eip);
break;
case 2:
- c->modrm_ea += insn_fetch(s32, 4, c->eip);
+ c->modrm_ea += insn_fetch(s32, 4,
+ c->decode_eip);
break;
}
}
@@ -764,7 +767,7 @@ done_prefixes:
c->modrm_ea += *c->override_base;
if (rip_relative) {
- c->modrm_ea += c->eip;
+ c->modrm_ea += c->decode_eip;
switch (c->d & SrcMask) {
case SrcImmByte:
c->modrm_ea += 1;
@@ -837,28 +840,28 @@ done_prefixes:
break;
case SrcImm:
c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
+ c->src.ptr = (unsigned long *)c->decode_eip;
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
if (c->src.bytes == 8)
c->src.bytes = 4;
/* NB. Immediates are sign-extended as necessary. */
switch (c->src.bytes) {
case 1:
- c->src.val = insn_fetch(s8, 1, c->eip);
+ c->src.val = insn_fetch(s8, 1, c->decode_eip);
break;
case 2:
- c->src.val = insn_fetch(s16, 2, c->eip);
+ c->src.val = insn_fetch(s16, 2, c->decode_eip);
break;
case 4:
- c->src.val = insn_fetch(s32, 4, c->eip);
+ c->src.val = insn_fetch(s32, 4, c->decode_eip);
break;
}
break;
case SrcImmByte:
c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
+ c->src.ptr = (unsigned long *)c->decode_eip;
c->src.bytes = 1;
- c->src.val = insn_fetch(s8, 1, c->eip);
+ c->src.val = insn_fetch(s8, 1, c->decode_eip);
break;
}
@@ -1146,10 +1149,20 @@ 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;
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);
+
+ /* restore eip after decoding phase */
+
+ c->eip = c->decode_eip;
+
if ((c->d & ModRM) && (c->modrm_mod != 3))
cr2 = c->modrm_ea;
@@ -1441,8 +1454,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 +1470,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 +1498,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],
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
index f03b128..9fd7bb2 100644
--- a/drivers/kvm/x86_emulate.h
+++ b/drivers/kvm/x86_emulate.h
@@ -131,6 +131,7 @@ struct decode_cache {
unsigned long *override_base;
unsigned int d;
unsigned long regs[NR_VCPU_REGS];
+ unsigned long decode_eip;
unsigned long eip;
/* modrm */
u8 modrm;
--
1.5.2.4
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel