From: Mihai Donțu <mdo...@bitdefender.com>

The information we can provide this way is incomplete, but current users
of the page tracking code can work with it.

Signed-off-by: Mihai Donțu <mdo...@bitdefender.com>
Signed-off-by: Adalbert Lazăr <ala...@bitdefender.com>
---
 arch/x86/kvm/x86.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 9a3fac9b30ba..a9caacea0207 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7872,6 +7872,51 @@ int x86_decode_emulated_instruction(struct kvm_vcpu 
*vcpu, int emulation_type,
 }
 EXPORT_SYMBOL_GPL(x86_decode_emulated_instruction);
 
+/*
+ * With introspection enabled, emulation failures translate in events being
+ * missed because the read/write callbacks are not invoked. All we have is
+ * the fetch event (kvm_page_track_preexec). Below we use the EPT/NPT VMEXIT
+ * information to generate the events, but without providing accurate
+ * data and size (the emulator would have computed those). If an instruction
+ * would happen to read and write in the same page, the second event will
+ * initially be missed and we rely on the page tracking mechanism to bring
+ * us back here to send it.
+ */
+static bool kvm_page_track_emulation_failure(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+       u64 error_code = vcpu->arch.error_code;
+       u8 data = 0;
+       gva_t gva;
+       bool ret;
+
+       /* MMIO emulation failures should be treated the normal way */
+       if (unlikely(error_code & PFERR_RSVD_MASK))
+               return true;
+
+       /* EPT/NTP must be enabled */
+       if (unlikely(!vcpu->arch.mmu->direct_map))
+               return true;
+
+       /*
+        * The A/D bit emulation should make this test unneeded, but just
+        * in case
+        */
+       if (unlikely((error_code & PFERR_NESTED_GUEST_PAGE) ==
+                    PFERR_NESTED_GUEST_PAGE))
+               return true;
+
+       gva = static_call(kvm_x86_fault_gla)(vcpu);
+
+       if (error_code & PFERR_WRITE_MASK)
+               ret = kvm_page_track_prewrite(vcpu, gpa, gva, &data, 0);
+       else if (error_code & PFERR_USER_MASK)
+               ret = kvm_page_track_preread(vcpu, gpa, gva, 0);
+       else
+               ret = true;
+
+       return ret;
+}
+
 int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
                            int emulation_type, void *insn, int insn_len)
 {
@@ -7905,6 +7950,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t 
cr2_or_gpa,
                                kvm_queue_exception(vcpu, UD_VECTOR);
                                return 1;
                        }
+                       if (!kvm_page_track_emulation_failure(vcpu, cr2_or_gpa))
+                               return 1;
                        if (reexecute_instruction(vcpu, cr2_or_gpa,
                                                  write_fault_to_spt,
                                                  emulation_type))
@@ -7974,6 +8021,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t 
cr2_or_gpa,
                return 1;
 
        if (r == EMULATION_FAILED) {
+               if (!kvm_page_track_emulation_failure(vcpu, cr2_or_gpa))
+                       return 1;
                if (reexecute_instruction(vcpu, cr2_or_gpa, write_fault_to_spt,
                                        emulation_type))
                        return 1;
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

Reply via email to