Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: kvm@vger.kernel.org
Cc: Jon Kohler <jon@nutanix.com>, Nikunj A Dadhania <nikunj@amd.com>,
	Amit Shah <amit.shah@amd.com>,
	Sean Christopherson <seanjc@google.com>
Subject: [PATCH kvm-unit-tests 3/9] svm: add basic GMET tests
Date: Thu, 26 Mar 2026 10:50:29 -0400	[thread overview]
Message-ID: <20260326145035.119519-4-pbonzini@redhat.com> (raw)
In-Reply-To: <20260326145035.119519-1-pbonzini@redhat.com>

These cover three basic scenarios of running successfully,
failing due to NX=1 and failing due to U/S=1.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile            |  2 +-
 lib/x86/processor.h |  1 +
 x86/svm.c           | 17 ++++++++++
 x86/svm.h           |  1 +
 x86/svm_npt.c       | 83 +++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 0ce0813b..403fd495 100644
--- a/Makefile
+++ b/Makefile
@@ -93,7 +93,7 @@ COMMON_CFLAGS += $(wunused_but_set_parameter)
 CFLAGS += $(COMMON_CFLAGS)
 CFLAGS += $(wmissing_parameter_type)
 CFLAGS += $(wold_style_declaration)
-CFLAGS += -Woverride-init -Wmissing-prototypes -Wstrict-prototypes
+CFLAGS += -Wmissing-prototypes -Wstrict-prototypes
 
 # Evaluate and add late cflags last -- they may depend on previous flags
 LATE_CFLAGS := $(LATE_CFLAGS)
diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 42dd2d2a..32ce08e2 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -377,6 +377,7 @@ struct x86_cpu_feature {
 #define X86_FEATURE_PAUSEFILTER		X86_CPU_FEATURE(0x8000000A, 0, EDX, 10)
 #define X86_FEATURE_PFTHRESHOLD		X86_CPU_FEATURE(0x8000000A, 0, EDX, 12)
 #define X86_FEATURE_VGIF		X86_CPU_FEATURE(0x8000000A, 0, EDX, 16)
+#define X86_FEATURE_GMET		X86_CPU_FEATURE(0x8000000A, 0, EDX, 17)
 #define X86_FEATURE_VNMI		X86_CPU_FEATURE(0x8000000A, 0, EDX, 25)
 #define X86_FEATURE_SME			X86_CPU_FEATURE(0x8000001F, 0, EAX,  0)
 #define X86_FEATURE_SEV			X86_CPU_FEATURE(0x8000001F, 0, EAX,  1)
diff --git a/x86/svm.c b/x86/svm.c
index 58cbf0a5..a85da905 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -43,6 +43,23 @@ u64 *npt_get_pml4e(void)
 	return pml4e;
 }
 
+void npt_prepare_gmet_pte(bool user)
+{
+	extern u8 start;
+	u64 address = (u64)&start & ~(1 << 21);
+	u64 mask = user ? PT_USER_MASK : 0;
+	u64 *pte;
+	int i;
+
+
+	/* flip the U bit on the 2 MiB region where the code is loaded.
+	 * the U bit is only used for execution, therefore page table accesses ignore it
+	 */
+	pte = npt_get_pte(address);
+	for (i = 0; i < 512; i++)
+		pte[i] = (pte[i] & ~PT_USER_MASK) | mask;
+}
+
 bool smp_supported(void)
 {
 	return cpu_count() > 1;
diff --git a/x86/svm.h b/x86/svm.h
index 947206bb..c5695b37 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -418,6 +418,7 @@ u64 *npt_get_pte(u64 address);
 u64 *npt_get_pde(u64 address);
 u64 *npt_get_pdpe(u64 address);
 u64 *npt_get_pml4e(void);
+void npt_prepare_gmet_pte(bool user);
 bool smp_supported(void);
 bool default_supported(void);
 bool fep_supported(void);
diff --git a/x86/svm_npt.c b/x86/svm_npt.c
index bd5e8f35..75d9c2c9 100644
--- a/x86/svm_npt.c
+++ b/x86/svm_npt.c
@@ -87,6 +87,79 @@ static bool npt_us_check(struct svm_test *test)
 	    && (vmcb->control.exit_info_1 == 0x100000005ULL);
 }
 
+static bool npt_gmet_supported(void)
+{
+	return npt_supported() && this_cpu_has(X86_FEATURE_GMET);
+}
+
+static void npt_gmet_null_prepare(struct svm_test *test)
+{
+	/* set U=0 - no failure */
+	npt_prepare_gmet_pte(false);
+	vmcb->control.nested_ctl |= SVM_NESTED_GMET;
+}
+
+static bool npt_gmet_null_check(struct svm_test *test)
+{
+	/* reset U=1 */
+	npt_prepare_gmet_pte(true);
+	vmcb->control.nested_ctl &= ~SVM_NESTED_GMET;
+        return vmcb->control.exit_code == SVM_EXIT_VMMCALL;
+}
+
+static void npt_gmet_nx_prepare(struct svm_test *test)
+{
+	u64 *pte = npt_get_pte((u64) null_test);
+
+	/* set U=0 - failure will be from NX */
+	npt_prepare_gmet_pte(false);
+	*pte |= PT64_NX_MASK;
+	vmcb->control.nested_ctl |= SVM_NESTED_GMET;
+
+	test->scratch = rdmsr(MSR_EFER);
+	wrmsr(MSR_EFER, test->scratch | EFER_NX);
+}
+
+static bool npt_gmet_nx_check(struct svm_test *test)
+{
+	u64 *pte = npt_get_pte((u64) null_test);
+
+	/* reset U=1, NX=0 */
+	npt_prepare_gmet_pte(true);
+	*pte &= ~PT64_NX_MASK;
+	vmcb->control.nested_ctl &= ~SVM_NESTED_GMET;
+
+	wrmsr(MSR_EFER, test->scratch);
+
+	/* errata 1218 - the U bit in the page fault error code may be incorrect */
+	return (vmcb->control.exit_code == SVM_EXIT_NPF)
+	    && ((vmcb->control.exit_info_1 & ~PFERR_USER_MASK) == 0x100000011ULL);
+}
+
+static void npt_gmet_us_prepare(struct svm_test *test)
+{
+	u64 *pte = npt_get_pte((u64) null_test);
+
+	npt_prepare_gmet_pte(false);
+	*pte |= PT_USER_MASK;
+	vmcb->control.nested_ctl |= SVM_NESTED_GMET;
+
+	test->scratch = rdmsr(MSR_EFER);
+	wrmsr(MSR_EFER, test->scratch | EFER_NX);
+}
+
+static bool npt_gmet_us_check(struct svm_test *test)
+{
+	npt_prepare_gmet_pte(true);
+	vmcb->control.nested_ctl &= ~SVM_NESTED_GMET;
+
+	wrmsr(MSR_EFER, test->scratch);
+
+	/* errata 1218 - the U bit in the page fault error code may be incorrect */
+	return (vmcb->control.exit_code == SVM_EXIT_NPF)
+	    && ((vmcb->control.exit_info_1 & ~PFERR_USER_MASK) == 0x100000011ULL);
+}
+
 static void npt_rw_prepare(struct svm_test *test)
 {
 
@@ -380,9 +453,9 @@ skip_pte_test:
 	vmcb->save.cr4 = sg_cr4;
 }
 
-#define NPT_V1_TEST(name, prepare, guest_code, check)				\
+#define NPT_V1_TEST(name, prepare, guest_code, check, more...)				\
 	{ #name, npt_supported, prepare, default_prepare_gif_clear, guest_code,	\
-	  default_finished, check }
+	  default_finished, check, more }
 
 #define NPT_V2_TEST(name) { #name, .v2 = name }
 
@@ -390,6 +463,12 @@ static struct svm_test npt_tests[] = {
 	NPT_V1_TEST(npt_nx, npt_nx_prepare, null_test, npt_nx_check),
 	NPT_V1_TEST(npt_np, npt_np_prepare, npt_np_test, npt_np_check),
 	NPT_V1_TEST(npt_us, npt_us_prepare, npt_us_test, npt_us_check),
+	NPT_V1_TEST(npt_gmet_null, npt_gmet_null_prepare, null_test, npt_gmet_null_check,
+		.supported = npt_gmet_supported),
+	NPT_V1_TEST(npt_gmet_nx, npt_gmet_nx_prepare, null_test, npt_gmet_nx_check,
+		.supported = npt_gmet_supported),
+	NPT_V1_TEST(npt_gmet_us, npt_gmet_us_prepare, null_test, npt_gmet_us_check,
+		.supported = npt_gmet_supported),
 	NPT_V1_TEST(npt_rw, npt_rw_prepare, npt_rw_test, npt_rw_check),
 	NPT_V1_TEST(npt_rw_pfwalk, npt_rw_pfwalk_prepare, null_test, npt_rw_pfwalk_check),
 	NPT_V1_TEST(npt_l1mmio, npt_l1mmio_prepare, npt_l1mmio_test, npt_l1mmio_check),
-- 
2.52.0



  parent reply	other threads:[~2026-03-26 14:50 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-26 14:50 [PATCH kvm-unit-tests 0/9] Combined GMET and MBEC tests Paolo Bonzini
2026-03-26 14:50 ` [PATCH kvm-unit-tests 1/9] move PFERR_* constants to lib Paolo Bonzini
2026-03-26 14:50 ` [PATCH kvm-unit-tests 2/9] add definitions for nested_ctl Paolo Bonzini
2026-03-26 14:50 ` Paolo Bonzini [this message]
2026-03-27 16:03   ` [PATCH kvm-unit-tests 3/9] svm: add basic GMET tests Jon Kohler
2026-03-26 14:50 ` [PATCH kvm-unit-tests 4/9] x86/vmx: update EPT installation to use EPT_PRESENT flag Paolo Bonzini
2026-03-26 14:50 ` [PATCH kvm-unit-tests 5/9] x86/vmx: diagnose unexpected EPT violations Paolo Bonzini
2026-03-26 14:50 ` [PATCH kvm-unit-tests 6/9] x86/vmx: add mode-based execute control test for Skylake and above Paolo Bonzini
2026-03-27 15:57   ` Jon Kohler
2026-03-26 14:50 ` [PATCH kvm-unit-tests 7/9] x86/vmx: add user execution operation to EPT access tests Paolo Bonzini
2026-03-26 14:50 ` [PATCH kvm-unit-tests 8/9] x86/vmx: run EPT tests with MBEC enabled when available Paolo Bonzini
2026-03-26 16:13   ` Paolo Bonzini
2026-03-27 15:57     ` Jon Kohler
2026-03-27 15:57   ` Jon Kohler
2026-03-26 14:50 ` [PATCH kvm-unit-tests 9/9] x86/vmx: add EPT tests covering XU permission Paolo Bonzini
2026-03-27 15:56   ` Jon Kohler
2026-05-12 11:06 ` [PATCH kvm-unit-tests 0/9] Combined GMET and MBEC tests 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=20260326145035.119519-4-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=amit.shah@amd.com \
    --cc=jon@nutanix.com \
    --cc=kvm@vger.kernel.org \
    --cc=nikunj@amd.com \
    --cc=seanjc@google.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