KVM Archive mirror
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org, Sean Christopherson <seanjc@google.com>
Subject: [kvm-unit-tests PATCH 12/12] nSVM: Add test for NPT reserved bit and #NPF error code behavior
Date: Tue, 22 Jun 2021 14:00:47 -0700	[thread overview]
Message-ID: <20210622210047.3691840-13-seanjc@google.com> (raw)
In-Reply-To: <20210622210047.3691840-1-seanjc@google.com>

Add a test to verify that KVM generates the correct #NPF and PFEC when
host and guest EFER.NX and CR4.SMEP values diverge, and that KVM
correctly detects reserved bits in the first place.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 x86/svm.c       |   5 +-
 x86/svm_tests.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/x86/svm.c b/x86/svm.c
index 0959189..f185ca0 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -13,6 +13,7 @@
 #include "alloc_page.h"
 #include "isr.h"
 #include "apic.h"
+#include "vmalloc.h"
 
 /* for the nested page table*/
 u64 *pte[2048];
@@ -397,12 +398,14 @@ test_wanted(const char *name, char *filters[], int filter_count)
 
 int main(int ac, char **av)
 {
+	/* Omit PT_USER_MASK to allow tested host.CR4.SMEP=1. */
+	pteval_t opt_mask = 0;
 	int i = 0;
 
 	ac--;
 	av++;
 
-	setup_vm();
+	__setup_vm(&opt_mask);
 
 	if (!this_cpu_has(X86_FEATURE_SVM)) {
 		printf("SVM not availble\n");
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index fdef620..1aaf983 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -2499,6 +2499,148 @@ static void svm_guest_state_test(void)
 	test_vmrun_canonicalization();
 }
 
+static void __svm_npt_rsvd_bits_test(u64 *pxe, u64 rsvd_bits, u64 efer,
+				     ulong cr4, u64 guest_efer, ulong guest_cr4)
+{
+	u64 pxe_orig = *pxe;
+	int exit_reason;
+	u64 pfec;
+
+	wrmsr(MSR_EFER, efer);
+	write_cr4(cr4);
+
+	vmcb->save.efer = guest_efer;
+	vmcb->save.cr4  = guest_cr4;
+
+	*pxe |= rsvd_bits;
+
+	exit_reason = svm_vmrun();
+
+	report(exit_reason == SVM_EXIT_NPF,
+	       "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%x", rsvd_bits, exit_reason);
+
+	if (pxe == npt_get_pdpe() || pxe == npt_get_pml4e()) {
+		/*
+		 * The guest's page tables will blow up on a bad PDPE/PML4E,
+		 * before starting the final walk of the guest page.
+		 */
+		pfec = 0x20000000full;
+	} else {
+		/* RSVD #NPF on final walk of guest page. */
+		pfec = 0x10000000dULL;
+
+		/* PFEC.FETCH=1 if NX=1 *or* SMEP=1. */
+		if ((cr4 & X86_CR4_SMEP) || (efer & EFER_NX))
+			pfec |= 0x10;
+
+	}
+
+	report(vmcb->control.exit_info_1 == pfec,
+	       "Wanted PFEC = 0x%lx, got PFEC = %lx, PxE = 0x%lx.  "
+	       "host.NX = %u, host.SMEP = %u, guest.NX = %u, guest.SMEP = %u",
+	       pfec, vmcb->control.exit_info_1, *pxe,
+	       !!(efer & EFER_NX), !!(cr4 & X86_CR4_SMEP),
+	       !!(guest_efer & EFER_NX), !!(guest_cr4 & X86_CR4_SMEP));
+
+	*pxe = pxe_orig;
+}
+
+static void _svm_npt_rsvd_bits_test(u64 *pxe, u64 pxe_rsvd_bits,  u64 efer,
+				    ulong cr4, u64 guest_efer, ulong guest_cr4)
+{
+	u64 rsvd_bits;
+	int i;
+
+	/*
+	 * Test all combinations of guest/host EFER.NX and CR4.SMEP.  If host
+	 * EFER.NX=0, use NX as the reserved bit, otherwise use the passed in
+	 * @pxe_rsvd_bits.
+	 */
+	for (i = 0; i < 16; i++) {
+		if (i & 1) {
+			rsvd_bits = pxe_rsvd_bits;
+			efer |= EFER_NX;
+		} else {
+			rsvd_bits = PT64_NX_MASK;
+			efer &= ~EFER_NX;
+		}
+		if (i & 2)
+			cr4 |= X86_CR4_SMEP;
+		else
+			cr4 &= ~X86_CR4_SMEP;
+		if (i & 4)
+			guest_efer |= EFER_NX;
+		else
+			guest_efer &= ~EFER_NX;
+		if (i & 8)
+			guest_cr4 |= X86_CR4_SMEP;
+		else
+			guest_cr4 &= ~X86_CR4_SMEP;
+
+		__svm_npt_rsvd_bits_test(pxe, rsvd_bits, efer, cr4,
+					 guest_efer, guest_cr4);
+	}
+}
+
+static u64 get_random_bits(u64 hi, u64 low)
+{
+	u64 rsvd_bits;
+
+	do {
+		rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low);
+	} while (!rsvd_bits);
+
+	return rsvd_bits;
+}
+
+
+static void svm_npt_rsvd_bits_test(void)
+{
+	u64   saved_efer, host_efer, sg_efer, guest_efer;
+	ulong saved_cr4,  host_cr4,  sg_cr4,  guest_cr4;
+
+	if (!npt_supported()) {
+		report_skip("NPT not supported");
+		return;
+	}
+
+	saved_efer = host_efer  = rdmsr(MSR_EFER);
+	saved_cr4  = host_cr4   = read_cr4();
+	sg_efer    = guest_efer = vmcb->save.efer;
+	sg_cr4     = guest_cr4  = vmcb->save.cr4;
+
+	test_set_guest(basic_guest_main);
+
+	/*
+	 * 4k PTEs don't have reserved bits if MAXPHYADDR >= 52, just skip the
+	 * sub-test.  The NX test is still valid, but the extra bit of coverage
+	 * isn't worth the extra complexity.
+	 */
+	if (cpuid_maxphyaddr() >= 52)
+		goto skip_pte_test;
+
+	_svm_npt_rsvd_bits_test(npt_get_pte((u64)basic_guest_main),
+				get_random_bits(51, cpuid_maxphyaddr()),
+				host_efer, host_cr4, guest_efer, guest_cr4);
+
+skip_pte_test:
+	_svm_npt_rsvd_bits_test(npt_get_pde((u64)basic_guest_main),
+				get_random_bits(20, 13) | PT_PAGE_SIZE_MASK,
+				host_efer, host_cr4, guest_efer, guest_cr4);
+
+	_svm_npt_rsvd_bits_test(npt_get_pdpe(),
+				PT_PAGE_SIZE_MASK |
+					(this_cpu_has(X86_FEATURE_GBPAGES) ? get_random_bits(29, 13) : 0),
+				host_efer, host_cr4, guest_efer, guest_cr4);
+
+	_svm_npt_rsvd_bits_test(npt_get_pml4e(), BIT_ULL(8),
+				host_efer, host_cr4, guest_efer, guest_cr4);
+
+	wrmsr(MSR_EFER, saved_efer);
+	write_cr4(saved_cr4);
+	vmcb->save.efer = sg_efer;
+	vmcb->save.cr4  = sg_cr4;
+}
 
 static bool volatile svm_errata_reproduced = false;
 static unsigned long volatile physical = 0;
@@ -2741,6 +2883,7 @@ struct svm_test svm_tests[] = {
       host_rflags_finished, host_rflags_check },
     TEST(svm_cr4_osxsave_test),
     TEST(svm_guest_state_test),
+    TEST(svm_npt_rsvd_bits_test),
     TEST(svm_vmrun_errata_test),
     TEST(svm_vmload_vmsave),
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
-- 
2.32.0.288.g62a8d224e6-goog


  parent reply	other threads:[~2021-06-22 21:01 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-22 21:00 [kvm-unit-tests PATCH 00/12] nSVM: NPT improvements and cleanups Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 01/12] nSVM: Provide expected and actual exit codes on VMRUN test failure Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 02/12] nSVM: Replace open coded NX manipulation with appropriate macros Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 03/12] nSVM: Reset the VMCB before every v1 test Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 04/12] nSVM: Explicitly save/update/restore EFER.NX for NPT NX test Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 05/12] nSVM: Remove NPT reserved bits tests (new one on the way) Sean Christopherson
2021-06-24 11:06   ` Paolo Bonzini
2021-06-24 17:43     ` Sean Christopherson
2021-06-24 17:47       ` Paolo Bonzini
2021-06-24 18:16         ` Sean Christopherson
2021-08-12  7:58       ` Maxim Levitsky
2021-06-22 21:00 ` [kvm-unit-tests PATCH 06/12] nSVM: Stop forcing EFER.NX=1 for all tests Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 07/12] nSVM: Remove a superfluous modification of guest EFER.NX in NPT NX test Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 08/12] nSVM: Clear guest's " Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 09/12] lib/vmalloc: Let arch code pass a value to its setup_mmu() helper Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 10/12] x86: Let tests omit PT_USER_MASK when configuring virtual memory Sean Christopherson
2021-06-22 21:00 ` [kvm-unit-tests PATCH 11/12] x86: Add GBPAGES CPUID macro, clean up CPUID comments Sean Christopherson
2021-06-22 21:00 ` Sean Christopherson [this message]
2021-06-23 11:52 ` [kvm-unit-tests PATCH 00/12] nSVM: NPT improvements and cleanups Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210622210047.3691840-13-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).