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>
This commit is contained in:
Родитель
7e71a59b25
Коммит
c205fb7d7d
|
@ -160,6 +160,18 @@ enum {
|
||||||
#define DR7_FIXED_1 0x00000400
|
#define DR7_FIXED_1 0x00000400
|
||||||
#define DR7_VOLATILE 0xffff2bff
|
#define DR7_VOLATILE 0xffff2bff
|
||||||
|
|
||||||
|
#define PFERR_PRESENT_BIT 0
|
||||||
|
#define PFERR_WRITE_BIT 1
|
||||||
|
#define PFERR_USER_BIT 2
|
||||||
|
#define PFERR_RSVD_BIT 3
|
||||||
|
#define PFERR_FETCH_BIT 4
|
||||||
|
|
||||||
|
#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
|
||||||
|
#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
|
||||||
|
#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
|
||||||
|
#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
|
||||||
|
#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
|
||||||
|
|
||||||
/* apic attention bits */
|
/* apic attention bits */
|
||||||
#define KVM_APIC_CHECK_VAPIC 0
|
#define KVM_APIC_CHECK_VAPIC 0
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -4909,8 +4909,12 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||||
/* optimisation - avoid slow emulated read if Mov */
|
/* optimisation - avoid slow emulated read if Mov */
|
||||||
rc = segmented_read(ctxt, ctxt->dst.addr.mem,
|
rc = segmented_read(ctxt, ctxt->dst.addr.mem,
|
||||||
&ctxt->dst.val, ctxt->dst.bytes);
|
&ctxt->dst.val, ctxt->dst.bytes);
|
||||||
if (rc != X86EMUL_CONTINUE)
|
if (rc != X86EMUL_CONTINUE) {
|
||||||
|
if (rc == X86EMUL_PROPAGATE_FAULT &&
|
||||||
|
ctxt->exception.vector == PF_VECTOR)
|
||||||
|
ctxt->exception.error_code |= PFERR_WRITE_MASK;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctxt->dst.orig_val = ctxt->dst.val;
|
ctxt->dst.orig_val = ctxt->dst.val;
|
||||||
|
|
||||||
|
|
|
@ -44,18 +44,6 @@
|
||||||
#define PT_DIRECTORY_LEVEL 2
|
#define PT_DIRECTORY_LEVEL 2
|
||||||
#define PT_PAGE_TABLE_LEVEL 1
|
#define PT_PAGE_TABLE_LEVEL 1
|
||||||
|
|
||||||
#define PFERR_PRESENT_BIT 0
|
|
||||||
#define PFERR_WRITE_BIT 1
|
|
||||||
#define PFERR_USER_BIT 2
|
|
||||||
#define PFERR_RSVD_BIT 3
|
|
||||||
#define PFERR_FETCH_BIT 4
|
|
||||||
|
|
||||||
#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
|
|
||||||
#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
|
|
||||||
#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
|
|
||||||
#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
|
|
||||||
#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
|
|
||||||
|
|
||||||
static inline u64 rsvd_bits(int s, int e)
|
static inline u64 rsvd_bits(int s, int e)
|
||||||
{
|
{
|
||||||
return ((1ULL << (e - s + 1)) - 1) << s;
|
return ((1ULL << (e - s + 1)) - 1) << s;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче