Commit bca99c03 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini
Browse files

KVM: x86/mmu: Print SPTEs on unexpected #VE



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: default avatarSean Christopherson <seanjc@google.com>
Message-ID: <20240518000430.1118488-7-seanjc@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 743f1773
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+32 −8
Original line number Diff line number Diff line
@@ -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 @@ int noinline kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 err
}
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)
{
+5 −0
Original line number Diff line number Diff line
@@ -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;
	}