diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-12-24 19:52:16 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-01-09 04:24:11 -0500 |
commit | c205fb7d7d4f81e46fc577b707ceb9e356af1456 (patch) | |
tree | b73dbbae61efb80a231368f88f319688bc71d8b1 /arch/x86 | |
parent | 7e71a59b250330fd52ee7293eb9d31952f16682e (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.h | 12 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.h | 12 |
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 | |||
59 | static inline u64 rsvd_bits(int s, int e) | 47 | static 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; |