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
next prev 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).