summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2007-12-02 13:18:39 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2007-12-14 09:50:55 -0800
commitfb2fc4cf555e1a5eb4f061ca7c76adf667407f9c (patch)
tree67837dae9cfea044816dc62e049f2bdf562a7bed
parent117b22fffff1989cd9e2d90720f05dd438cea2f1 (diff)
KVM: x86 emulator: fix access registers for instructions with ModR/M byte and Mod = 3
patch 4e62417bf317504c0b85e0d7abd236f334f54eaf in mainline. The patch belows changes the access type to register from memory for instructions that are declared as SrcMem or DstMem, but have a ModR/M byte with Mod = 3. It fixes (at least) the lmsw and smsw instructions on an AMD64 CPU, which are needed for FreeBSD. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Avi Kivity <avi@qumranet.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/kvm/x86_emulate.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 804e86c57c60..08cd4a385c06 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -773,6 +773,14 @@ done_prefixes:
case SrcMem:
src.bytes = (d & ByteOp) ? 1 : op_bytes;
srcmem_common:
+ /*
+ * For instructions with a ModR/M byte, switch to register
+ * access if Mod = 3.
+ */
+ if ((d & ModRM) && modrm_mod == 3) {
+ src.type = OP_REG;
+ break;
+ }
src.type = OP_MEM;
src.ptr = (unsigned long *)cr2;
if ((rc = ops->read_emulated((unsigned long)src.ptr,
@@ -839,6 +847,15 @@ done_prefixes:
dst.type = OP_MEM;
dst.ptr = (unsigned long *)cr2;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.val = 0;
+ /*
+ * For instructions with a ModR/M byte, switch to register
+ * access if Mod = 3.
+ */
+ if ((d & ModRM) && modrm_mod == 3) {
+ dst.type = OP_REG;
+ break;
+ }
if (d & BitOp) {
unsigned long mask = ~(dst.bytes * 8 - 1);