public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Correct management of REP prefix
@ 2007-09-27 21:34 Laurent Vivier
       [not found] ` <1190928863669-git-send-email-Laurent.Vivier-6ktuUTfB/bM@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Laurent Vivier @ 2007-09-27 21:34 UTC (permalink / raw)
  To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f; +Cc: Laurent Vivier

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 <Laurent.Vivier-6ktuUTfB/bM@public.gmane.org>
---
 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/

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-10-03 17:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-27 21:34 [PATCH] Correct management of REP prefix Laurent Vivier
     [not found] ` <1190928863669-git-send-email-Laurent.Vivier-6ktuUTfB/bM@public.gmane.org>
2007-09-30  9:06   ` Avi Kivity
     [not found]     ` <46FF6702.2060203-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-10-01  8:55       ` Laurent Vivier
     [not found]         ` <4700B611.1000803-6ktuUTfB/bM@public.gmane.org>
2007-10-02  6:14           ` Avi Kivity
2007-10-01  9:01   ` Laurent Vivier
     [not found]     ` <11912292661049-git-send-email-Laurent.Vivier-6ktuUTfB/bM@public.gmane.org>
2007-10-02  6:11       ` Avi Kivity
2007-10-02 22:23       ` Kamble, Nitin A
     [not found]         ` <5461330FA59EDB46BE9AB8AAF2C431AD055A4295-1a9uaKK1+wJcIJlls4ac1rfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-10-03  7:23           ` Laurent Vivier
     [not found]             ` <4703438A.6010307-6ktuUTfB/bM@public.gmane.org>
2007-10-03 17:10               ` Kamble, Nitin A

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox