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