]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86/mmu: Print SPTEs on unexpected #VE
authorSean Christopherson <seanjc@google.com>
Sat, 18 May 2024 00:04:27 +0000 (17:04 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 23 May 2024 16:28:45 +0000 (12:28 -0400)
Print the SPTEs that correspond to the faulting GPA on an unexpected EPT
Violation #VE to help the user debug failures, e.g. to pinpoint which SPTE
didn't have SUPPRESS_VE set.

Opportunistically assert that the underlying exit reason was indeed an EPT
Violation, as the CPU has *really* gone off the rails if a #VE occurs due
to a completely unexpected exit reason.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20240518000430.1118488-7-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/vmx/vmx.c

index ece45b3f6f2073ea81ad65b139173411c77b3d73..f8ca74e7678f3ab8dc44ea0d2cd355cf04c5e068 100644 (file)
@@ -2154,6 +2154,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 error_code,
                       void *insn, int insn_len);
+void kvm_mmu_print_sptes(struct kvm_vcpu *vcpu, gpa_t gpa, const char *msg);
 void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
 void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
                             u64 addr, unsigned long roots);
index 1ae1c1328268b84d98d4e10347c357bf4353a8f0..b7b4426a7221dfe01af50971ca9a4657bdd038bf 100644 (file)
@@ -4104,23 +4104,31 @@ static int get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes, int *root_level
        return leaf;
 }
 
-/* return true if reserved bit(s) are detected on a valid, non-MMIO SPTE. */
-static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
+static int get_sptes_lockless(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes,
+                             int *root_level)
 {
-       u64 sptes[PT64_ROOT_MAX_LEVEL + 1];
-       struct rsvd_bits_validate *rsvd_check;
-       int root, leaf, level;
-       bool reserved = false;
+       int leaf;
 
        walk_shadow_page_lockless_begin(vcpu);
 
        if (is_tdp_mmu_active(vcpu))
-               leaf = kvm_tdp_mmu_get_walk(vcpu, addr, sptes, &root);
+               leaf = kvm_tdp_mmu_get_walk(vcpu, addr, sptes, root_level);
        else
-               leaf = get_walk(vcpu, addr, sptes, &root);
+               leaf = get_walk(vcpu, addr, sptes, root_level);
 
        walk_shadow_page_lockless_end(vcpu);
+       return leaf;
+}
 
+/* return true if reserved bit(s) are detected on a valid, non-MMIO SPTE. */
+static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
+{
+       u64 sptes[PT64_ROOT_MAX_LEVEL + 1];
+       struct rsvd_bits_validate *rsvd_check;
+       int root, leaf, level;
+       bool reserved = false;
+
+       leaf = get_sptes_lockless(vcpu, addr, sptes, &root);
        if (unlikely(leaf < 0)) {
                *sptep = 0ull;
                return reserved;
@@ -5924,6 +5932,22 @@ emulate:
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_page_fault);
 
+void kvm_mmu_print_sptes(struct kvm_vcpu *vcpu, gpa_t gpa, const char *msg)
+{
+       u64 sptes[PT64_ROOT_MAX_LEVEL + 1];
+       int root_level, leaf, level;
+
+       leaf = get_sptes_lockless(vcpu, gpa, sptes, &root_level);
+       if (unlikely(leaf < 0))
+               return;
+
+       pr_err("%s %llx", msg, gpa);
+       for (level = root_level; level >= leaf; level--)
+               pr_cont(", spte[%d] = 0x%llx", level, sptes[level]);
+       pr_cont("\n");
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_print_sptes);
+
 static void __kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
                                      u64 addr, hpa_t root_hpa)
 {
index a02b2720023a3fb58a3e978be9023432e0dc8503..58832aae2248726a6cf20c91099876000893cdc4 100644 (file)
@@ -5218,7 +5218,12 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                return handle_ud(vcpu);
 
        if (WARN_ON_ONCE(is_ve_fault(intr_info))) {
+               struct vmx_ve_information *ve_info = vmx->ve_info;
+
+               WARN_ONCE(ve_info->exit_reason != EXIT_REASON_EPT_VIOLATION,
+                         "Unexpected #VE on VM-Exit reason 0x%x", ve_info->exit_reason);
                dump_vmcs(vcpu);
+               kvm_mmu_print_sptes(vcpu, ve_info->guest_physical_address, "#VE");
                return 1;
        }