Add has_emulator_context to kvm_queued_exception to record whether a
queued exception VM-Exit originated from the current emulator exception.
This provenance allows nested virtualization code to determine whether
the emulator decode state can be used for a nested #PF VM-Exit.

Explicit provenance is needed because a matching emulator RIP does not
prove that the fetch cache describes the faulting instruction. For
example, completing pending emulated I/O can advance RIP while leaving
the fetch cache populated with the completed instruction.

Determine provenance in kvm_inject_page_fault() and carry it through
exception queueing so that it is stored as part of the nested VM-Exit
event. Userspace-injected and other unrelated exceptions leave the flag
clear.

Signed-off-by: Tina Zhang <[email protected]>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/x86.c              | 33 ++++++++++++++++++++++-----------
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7a258831616f..8466a17cd046 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -688,6 +688,7 @@ struct kvm_queued_exception {
        bool pending;
        bool injected;
        bool has_error_code;
+       bool has_emulator_context;
        u8 vector;
        u32 error_code;
        unsigned long payload;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0f1a829032c0..e7aff420d6c6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -444,7 +444,8 @@ 
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_deliver_exception_payload);
 
 static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int 
vector,
                                       bool has_error_code, u32 error_code,
-                                      bool has_payload, unsigned long payload)
+                                      bool has_payload, unsigned long payload,
+                                      bool has_emulator_context)
 {
        struct kvm_queued_exception *ex = &vcpu->arch.exception_vmexit;
 
@@ -452,6 +453,7 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu 
*vcpu, unsigned int vecto
        ex->injected = false;
        ex->pending = true;
        ex->has_error_code = has_error_code;
+       ex->has_emulator_context = has_emulator_context;
        ex->error_code = error_code;
        ex->has_payload = has_payload;
        ex->payload = payload;
@@ -459,7 +461,8 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu 
*vcpu, unsigned int vecto
 
 static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned int nr,
                                   bool has_error, u32 error_code,
-                                  bool has_payload, unsigned long payload)
+                                  bool has_payload, unsigned long payload,
+                                  bool has_emulator_context)
 {
        u32 prev_nr;
        int class1, class2;
@@ -473,7 +476,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, 
unsigned int nr,
        if (is_guest_mode(vcpu) &&
            kvm_nested_call(is_exception_vmexit)(vcpu, nr, error_code)) {
                kvm_queue_exception_vmexit(vcpu, nr, has_error, error_code,
-                                          has_payload, payload);
+                                          has_payload, payload,
+                                          has_emulator_context);
                return;
        }
 
@@ -519,7 +523,7 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, 
unsigned int nr,
 
 void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
 {
-       kvm_multiple_exception(vcpu, nr, false, 0, false, 0);
+       kvm_multiple_exception(vcpu, nr, false, 0, false, 0, false);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception);
 
@@ -527,14 +531,16 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception);
 void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr,
                           unsigned long payload)
 {
-       kvm_multiple_exception(vcpu, nr, false, 0, true, payload);
+       kvm_multiple_exception(vcpu, nr, false, 0, true, payload, false);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception_p);
 
 static void kvm_queue_exception_e_p(struct kvm_vcpu *vcpu, unsigned nr,
-                                   u32 error_code, unsigned long payload)
+                                   u32 error_code, unsigned long payload,
+                                   bool has_emulator_context)
 {
-       kvm_multiple_exception(vcpu, nr, true, error_code, true, payload);
+       kvm_multiple_exception(vcpu, nr, true, error_code, true, payload,
+                              has_emulator_context);
 }
 
 void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr,
@@ -580,6 +586,9 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_complete_insn_gp);
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault,
                           bool from_hardware)
 {
+       struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
+       bool has_emulator_context = ctxt && fault == &ctxt->exception;
+
        ++vcpu->stat.pf_guest;
 
        /*
@@ -589,10 +598,12 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct 
x86_exception *fault,
        if (is_guest_mode(vcpu) && fault->async_page_fault)
                kvm_queue_exception_vmexit(vcpu, PF_VECTOR,
                                           true, fault->error_code,
-                                          true, fault->address);
+                                          true, fault->address,
+                                          has_emulator_context);
        else
                kvm_queue_exception_e_p(vcpu, PF_VECTOR, fault->error_code,
-                                       fault->address);
+                                       fault->address,
+                                       has_emulator_context);
 }
 
 void __kvm_inject_emulated_page_fault(struct kvm_vcpu *vcpu,
@@ -627,7 +638,7 @@ void kvm_inject_nmi(struct kvm_vcpu *vcpu)
 
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
 {
-       kvm_multiple_exception(vcpu, nr, true, error_code, false, 0);
+       kvm_multiple_exception(vcpu, nr, true, error_code, false, 0, false);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception_e);
 
@@ -8949,7 +8960,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
            kvm_nested_call(is_exception_vmexit)(vcpu, ex->vector, 
ex->error_code)) {
                kvm_queue_exception_vmexit(vcpu, ex->vector,
                                           ex->has_error_code, ex->error_code,
-                                          ex->has_payload, ex->payload);
+                                          ex->has_payload, ex->payload, false);
                ex->injected = false;
                ex->pending = false;
        }
-- 
2.43.7


Reply via email to