aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2014-12-24 19:52:16 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2015-01-09 04:24:11 -0500
commitc205fb7d7d4f81e46fc577b707ceb9e356af1456 (patch)
treeb73dbbae61efb80a231368f88f319688bc71d8b1 /arch/x86
parent7e71a59b250330fd52ee7293eb9d31952f16682e (diff)
KVM: x86: #PF error-code on R/W operations is wrong
When emulating an instruction that reads the destination memory operand (i.e., instructions without the Mov flag in the emulator), the operand is first read. If a page-fault is detected in this phase, the error-code which would be delivered to the VM does not indicate that the access that caused the exception is a write one. This does not conform with real hardware, and may cause the VM to enter the page-fault handler twice for no reason (once for read, once for write). Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/kvm_host.h12
-rw-r--r--arch/x86/kvm/emulate.c6
-rw-r--r--arch/x86/kvm/mmu.h12
3 files changed, 17 insertions, 13 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index cb19d05af3cd..97a5dd0222c8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -160,6 +160,18 @@ enum {
160#define DR7_FIXED_1 0x00000400 160#define DR7_FIXED_1 0x00000400
161#define DR7_VOLATILE 0xffff2bff 161#define DR7_VOLATILE 0xffff2bff
162 162
163#define PFERR_PRESENT_BIT 0
164#define PFERR_WRITE_BIT 1
165#define PFERR_USER_BIT 2
166#define PFERR_RSVD_BIT 3
167#define PFERR_FETCH_BIT 4
168
169#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
170#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
171#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
172#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
173#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
174
163/* apic attention bits */ 175/* apic attention bits */
164#define KVM_APIC_CHECK_VAPIC 0 176#define KVM_APIC_CHECK_VAPIC 0
165/* 177/*
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index d949287ed010..ef23c1e5fa9f 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -4909,8 +4909,12 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
4909 /* optimisation - avoid slow emulated read if Mov */ 4909 /* optimisation - avoid slow emulated read if Mov */
4910 rc = segmented_read(ctxt, ctxt->dst.addr.mem, 4910 rc = segmented_read(ctxt, ctxt->dst.addr.mem,
4911 &ctxt->dst.val, ctxt->dst.bytes); 4911 &ctxt->dst.val, ctxt->dst.bytes);
4912 if (rc != X86EMUL_CONTINUE) 4912 if (rc != X86EMUL_CONTINUE) {
4913 if (rc == X86EMUL_PROPAGATE_FAULT &&
4914 ctxt->exception.vector == PF_VECTOR)
4915 ctxt->exception.error_code |= PFERR_WRITE_MASK;
4913 goto done; 4916 goto done;
4917 }
4914 } 4918 }
4915 ctxt->dst.orig_val = ctxt->dst.val; 4919 ctxt->dst.orig_val = ctxt->dst.val;
4916 4920
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index a7f9a121690d..c7d65637c851 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -44,18 +44,6 @@
44#define PT_DIRECTORY_LEVEL 2 44#define PT_DIRECTORY_LEVEL 2
45#define PT_PAGE_TABLE_LEVEL 1 45#define PT_PAGE_TABLE_LEVEL 1
46 46
47#define PFERR_PRESENT_BIT 0
48#define PFERR_WRITE_BIT 1
49#define PFERR_USER_BIT 2
50#define PFERR_RSVD_BIT 3
51#define PFERR_FETCH_BIT 4
52
53#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
54#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
55#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
56#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
57#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
58
59static inline u64 rsvd_bits(int s, int e) 47static inline u64 rsvd_bits(int s, int e)
60{ 48{
61 return ((1ULL << (e - s + 1)) - 1) << s; 49 return ((1ULL << (e - s + 1)) - 1) << s;