mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [kvm-unit-tests 0/7] More tests for selective CR0 intercept
@ 2025-10-24 19:49 Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 1/7] x86/svm: Cleanup selective cr0 write intercept test Yosry Ahmed
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Add more test cases for the selective CR0 write intercept, covering bugs
fixed by
https://lore.kernel.org/kvm/20251024192918.3191141-1-yosry.ahmed@linux.dev/.

Patches 1-5 are cleanups and prep work. Patch 6 generalizes the existing
test to make it easy to extend, and patch 7 adds the actual tests.

Yosry Ahmed (7):
  x86/svm: Cleanup selective cr0 write intercept test
  x86/svm: Move CR0 selective write intercept test near CR3 intercept
  x86/svm: Add FEP helpers for SVM tests
  x86/svm: Report unsupported SVM tests
  x86/svm: Move report_svm_guest() to the top of svm_tests.c
  x86/svm: Generalize and improve selective CR0 write intercept test
  x86/svm: Add more selective CR0 write and LMSW test cases

 lib/x86/desc.h  |   8 +++
 x86/svm.c       |   9 ++-
 x86/svm.h       |   1 +
 x86/svm_tests.c | 178 ++++++++++++++++++++++++++++++++++--------------
 4 files changed, 144 insertions(+), 52 deletions(-)

-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 1/7] x86/svm: Cleanup selective cr0 write intercept test
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 2/7] x86/svm: Move CR0 selective write intercept test near CR3 intercept Yosry Ahmed
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Rename the test and functions to more general names describing the test
more accurately. Use X86_CR0_CD instead of hardcoding the bitmask, and
explicitly clear the bit in the prepare() function to make it clearer
that it would only be set by the test.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm_tests.c | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 80d5aeb1..e9116591 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -793,23 +793,19 @@ static bool check_asid_zero(struct svm_test *test)
 	return vmcb->control.exit_code == SVM_EXIT_ERR;
 }
 
-static void sel_cr0_bug_prepare(struct svm_test *test)
+static void prepare_sel_cr0_intercept(struct svm_test *test)
 {
+	vmcb->save.cr0 &= ~X86_CR0_CD;
 	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
 }
 
-static bool sel_cr0_bug_finished(struct svm_test *test)
-{
-	return true;
-}
-
-static void sel_cr0_bug_test(struct svm_test *test)
+static void test_sel_cr0_write_intercept(struct svm_test *test)
 {
 	unsigned long cr0;
 
-	/* read cr0, clear CD, and write back */
+	/* read cr0, set CD, and write back */
 	cr0  = read_cr0();
-	cr0 |= (1UL << 30);
+	cr0 |= X86_CR0_CD;
 	write_cr0(cr0);
 
 	/*
@@ -821,7 +817,7 @@ static void sel_cr0_bug_test(struct svm_test *test)
 	exit(report_summary());
 }
 
-static bool sel_cr0_bug_check(struct svm_test *test)
+static bool check_sel_cr0_intercept(struct svm_test *test)
 {
 	return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE;
 }
@@ -3486,9 +3482,9 @@ struct svm_test svm_tests[] = {
 	{ "asid_zero", default_supported, prepare_asid_zero,
 	  default_prepare_gif_clear, test_asid_zero,
 	  default_finished, check_asid_zero },
-	{ "sel_cr0_bug", default_supported, sel_cr0_bug_prepare,
-	  default_prepare_gif_clear, sel_cr0_bug_test,
-	  sel_cr0_bug_finished, sel_cr0_bug_check },
+	{ "sel cr0 write intercept", default_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_write_intercept, default_finished, check_sel_cr0_intercept},
 	{ "tsc_adjust", tsc_adjust_supported, tsc_adjust_prepare,
 	  default_prepare_gif_clear, tsc_adjust_test,
 	  default_finished, tsc_adjust_check },
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 2/7] x86/svm: Move CR0 selective write intercept test near CR3 intercept
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 1/7] x86/svm: Cleanup selective cr0 write intercept test Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 3/7] x86/svm: Add FEP helpers for SVM tests Yosry Ahmed
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

It makes more semantic sense for these tests to be in close proximity.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm_tests.c | 64 ++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index e9116591..feeb27d6 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -112,6 +112,35 @@ static bool finished_rsm_intercept(struct svm_test *test)
 	return get_test_stage(test) == 2;
 }
 
+static void prepare_sel_cr0_intercept(struct svm_test *test)
+{
+	vmcb->save.cr0 &= ~X86_CR0_CD;
+	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
+}
+
+static void test_sel_cr0_write_intercept(struct svm_test *test)
+{
+	unsigned long cr0;
+
+	/* read cr0, set CD, and write back */
+	cr0  = read_cr0();
+	cr0 |= X86_CR0_CD;
+	write_cr0(cr0);
+
+	/*
+	 * If we are here the test failed, not sure what to do now because we
+	 * are not in guest-mode anymore so we can't trigger an intercept.
+	 * Trigger a tripple-fault for now.
+	 */
+	report_fail("sel_cr0 test. Can not recover from this - exiting");
+	exit(report_summary());
+}
+
+static bool check_sel_cr0_intercept(struct svm_test *test)
+{
+	return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE;
+}
+
 static void prepare_cr3_intercept(struct svm_test *test)
 {
 	default_prepare(test);
@@ -793,35 +822,6 @@ static bool check_asid_zero(struct svm_test *test)
 	return vmcb->control.exit_code == SVM_EXIT_ERR;
 }
 
-static void prepare_sel_cr0_intercept(struct svm_test *test)
-{
-	vmcb->save.cr0 &= ~X86_CR0_CD;
-	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
-}
-
-static void test_sel_cr0_write_intercept(struct svm_test *test)
-{
-	unsigned long cr0;
-
-	/* read cr0, set CD, and write back */
-	cr0  = read_cr0();
-	cr0 |= X86_CR0_CD;
-	write_cr0(cr0);
-
-	/*
-	 * If we are here the test failed, not sure what to do now because we
-	 * are not in guest-mode anymore so we can't trigger an intercept.
-	 * Trigger a tripple-fault for now.
-	 */
-	report_fail("sel_cr0 test. Can not recover from this - exiting");
-	exit(report_summary());
-}
-
-static bool check_sel_cr0_intercept(struct svm_test *test)
-{
-	return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE;
-}
-
 #define TSC_ADJUST_VALUE    (1ll << 32)
 #define TSC_OFFSET_VALUE    (~0ull << 48)
 static bool ok;
@@ -3458,6 +3458,9 @@ struct svm_test svm_tests[] = {
 	{ "rsm", default_supported,
 	  prepare_rsm_intercept, default_prepare_gif_clear,
 	  test_rsm_intercept, finished_rsm_intercept, check_rsm_intercept },
+	{ "sel cr0 write intercept", default_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_write_intercept, default_finished, check_sel_cr0_intercept},
 	{ "cr3 read intercept", default_supported,
 	  prepare_cr3_intercept, default_prepare_gif_clear,
 	  test_cr3_intercept, default_finished, check_cr3_intercept },
@@ -3482,9 +3485,6 @@ struct svm_test svm_tests[] = {
 	{ "asid_zero", default_supported, prepare_asid_zero,
 	  default_prepare_gif_clear, test_asid_zero,
 	  default_finished, check_asid_zero },
-	{ "sel cr0 write intercept", default_supported,
-	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
-	  test_sel_cr0_write_intercept, default_finished, check_sel_cr0_intercept},
 	{ "tsc_adjust", tsc_adjust_supported, tsc_adjust_prepare,
 	  default_prepare_gif_clear, tsc_adjust_test,
 	  default_finished, tsc_adjust_check },
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 3/7] x86/svm: Add FEP helpers for SVM tests
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 1/7] x86/svm: Cleanup selective cr0 write intercept test Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 2/7] x86/svm: Move CR0 selective write intercept test near CR3 intercept Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 4/7] x86/svm: Report unsupported " Yosry Ahmed
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Add helpers to check if FEP is enabled to use as supported() callbacks
in SVM tests for the emulator. Also add a macro that executes an
assembly instruction conditionally with FEP, which will make writing
SVM tests that run with and without FEP more convenient.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 lib/x86/desc.h | 8 ++++++++
 x86/svm.c      | 5 +++++
 x86/svm.h      | 1 +
 3 files changed, 14 insertions(+)

diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 68f38f3d..06c8be65 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -284,6 +284,14 @@ extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
 #define asm_fep_safe(insn, inputs...)				\
 	__asm_safe_out1(KVM_FEP, insn,, inputs)
 
+#define asm_conditional_fep_safe(fep, insn, inputs...)			\
+({									\
+	if (fep)							\
+		asm_fep_safe(insn, inputs);				\
+	else								\
+		asm_safe(insn, inputs);					\
+})
+
 #define __asm_safe_out1(fep, insn, output, inputs...)			\
 ({									\
 	asm volatile(__ASM_TRY(fep, "1f")				\
diff --git a/x86/svm.c b/x86/svm.c
index e715e270..035367a1 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -53,6 +53,11 @@ bool default_supported(void)
 	return true;
 }
 
+bool fep_supported(void)
+{
+	return is_fep_available;
+}
+
 bool vgif_supported(void)
 {
 	return this_cpu_has(X86_FEATURE_VGIF);
diff --git a/x86/svm.h b/x86/svm.h
index c1dd84af..264583a6 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -417,6 +417,7 @@ u64 *npt_get_pdpe(u64 address);
 u64 *npt_get_pml4e(void);
 bool smp_supported(void);
 bool default_supported(void);
+bool fep_supported(void);
 bool vgif_supported(void);
 bool lbrv_supported(void);
 bool tsc_scale_supported(void);
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 4/7] x86/svm: Report unsupported SVM tests
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
                   ` (2 preceding siblings ...)
  2025-10-24 19:49 ` [kvm-unit-tests 3/7] x86/svm: Add FEP helpers for SVM tests Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 5/7] x86/svm: Move report_svm_guest() to the top of svm_tests.c Yosry Ahmed
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Print a message when a test is skipped due to being unsupported for
better visibility.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/x86/svm.c b/x86/svm.c
index 035367a1..5015339d 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -403,8 +403,10 @@ int run_svm_tests(int ac, char **av, struct svm_test *svm_tests)
 	for (; svm_tests[i].name != NULL; i++) {
 		if (!test_wanted(svm_tests[i].name, av, ac))
 			continue;
-		if (svm_tests[i].supported && !svm_tests[i].supported())
+		if (svm_tests[i].supported && !svm_tests[i].supported()) {
+			report_skip("%s (not supported)", svm_tests[i].name);
 			continue;
+		}
 		if (svm_tests[i].v2 == NULL) {
 			if (svm_tests[i].on_vcpu) {
 				if (cpu_count() <= svm_tests[i].on_vcpu)
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 5/7] x86/svm: Move report_svm_guest() to the top of svm_tests.c
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
                   ` (3 preceding siblings ...)
  2025-10-24 19:49 ` [kvm-unit-tests 4/7] x86/svm: Report unsupported " Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 6/7] x86/svm: Generalize and improve selective CR0 write intercept test Yosry Ahmed
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Move the macro ahead of other tests that will start using it.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm_tests.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index feeb27d6..61ab63db 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -37,6 +37,21 @@ u64 latclgi_max;
 u64 latclgi_min;
 u64 runs;
 
+/*
+ * Report failures from SVM guest code, and on failure, set the stage to -1 and
+ * do VMMCALL to terminate the test (host side must treat -1 as "finished").
+ * TODO: fix the tests that don't play nice with a straight report, e.g. the
+ * V_TPR test fails if report() is invoked.
+ */
+#define report_svm_guest(cond, test, fmt, args...)	\
+do {							\
+	if (!(cond)) {					\
+		report_fail(fmt, ##args);		\
+		set_test_stage(test, -1);		\
+		vmmcall();				\
+	}						\
+} while (0)
+
 static void null_test(struct svm_test *test)
 {
 }
@@ -1074,21 +1089,6 @@ static bool lat_svm_insn_check(struct svm_test *test)
 	return true;
 }
 
-/*
- * Report failures from SVM guest code, and on failure, set the stage to -1 and
- * do VMMCALL to terminate the test (host side must treat -1 as "finished").
- * TODO: fix the tests that don't play nice with a straight report, e.g. the
- * V_TPR test fails if report() is invoked.
- */
-#define report_svm_guest(cond, test, fmt, args...)	\
-do {							\
-	if (!(cond)) {					\
-		report_fail(fmt, ##args);		\
-		set_test_stage(test, -1);		\
-		vmmcall();				\
-	}						\
-} while (0)
-
 bool pending_event_ipi_fired;
 bool pending_event_guest_run;
 
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 6/7] x86/svm: Generalize and improve selective CR0 write intercept test
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
                   ` (4 preceding siblings ...)
  2025-10-24 19:49 ` [kvm-unit-tests 5/7] x86/svm: Move report_svm_guest() to the top of svm_tests.c Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 19:49 ` [kvm-unit-tests 7/7] x86/svm: Add more selective CR0 write and LMSW test cases Yosry Ahmed
  2025-10-24 20:02 ` [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

In preparation for adding more test cases, make the test easier to
extend. Create a generic helper that sets an arbitrary bit in CR0,
optionally using FEP. The helper also stores the value to be written in
test->scratch, making it possible to double check if the write was
actually executed or not.

Use report_svm_guest() instead of report_fail() + exit().

Make test_sel_cr0_write_intercept() use the generic helper, and add
another test case that sets FEP to exercise the interception path in the
emulator.

Finally, in check_sel_cr0_intercept() also check that the write was not
executed by comparing CR0 value in the VMCB12 with the
value-to-be-written stored in test->scratch.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm_tests.c | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 61ab63db..71afb38a 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -133,27 +133,36 @@ static void prepare_sel_cr0_intercept(struct svm_test *test)
 	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
 }
 
-static void test_sel_cr0_write_intercept(struct svm_test *test)
+static void __test_cr0_write_bit(struct svm_test *test, unsigned long bit,
+				 bool intercept, bool fep)
 {
 	unsigned long cr0;
 
-	/* read cr0, set CD, and write back */
-	cr0  = read_cr0();
-	cr0 |= X86_CR0_CD;
-	write_cr0(cr0);
+	cr0 = read_cr0();
+	cr0 |= bit;
+	test->scratch = cr0;
 
-	/*
-	 * If we are here the test failed, not sure what to do now because we
-	 * are not in guest-mode anymore so we can't trigger an intercept.
-	 * Trigger a tripple-fault for now.
-	 */
-	report_fail("sel_cr0 test. Can not recover from this - exiting");
-	exit(report_summary());
+	asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
+
+	/* This code should be unreachable when an intercept is expected */
+	report_svm_guest(!intercept, test, "Expected intercept on CR0 write");
+}
+
+/* MOV-to-CR0 updating CR0.CD is intercepted by the selective intercept */
+static void test_sel_cr0_write_intercept(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_CD, true, false);
+}
+
+static void test_sel_cr0_write_intercept_emul(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_CD, true, true);
 }
 
 static bool check_sel_cr0_intercept(struct svm_test *test)
 {
-	return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE;
+	return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE &&
+		vmcb->save.cr0 != test->scratch;
 }
 
 static void prepare_cr3_intercept(struct svm_test *test)
@@ -3461,6 +3470,9 @@ struct svm_test svm_tests[] = {
 	{ "sel cr0 write intercept", default_supported,
 	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
 	  test_sel_cr0_write_intercept, default_finished, check_sel_cr0_intercept},
+	{ "sel cr0 write intercept emulate", fep_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_write_intercept_emul, default_finished, check_sel_cr0_intercept},
 	{ "cr3 read intercept", default_supported,
 	  prepare_cr3_intercept, default_prepare_gif_clear,
 	  test_cr3_intercept, default_finished, check_cr3_intercept },
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [kvm-unit-tests 7/7] x86/svm: Add more selective CR0 write and LMSW test cases
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
                   ` (5 preceding siblings ...)
  2025-10-24 19:49 ` [kvm-unit-tests 6/7] x86/svm: Generalize and improve selective CR0 write intercept test Yosry Ahmed
@ 2025-10-24 19:49 ` Yosry Ahmed
  2025-10-24 20:02 ` [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 19:49 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel, Yosry Ahmed

From: Yosry Ahmed <yosryahmed@google.com>

Add more test cases that cover:
- The priority between selective and non-selective CR0 intercepts.
- Writes to CR0 that should not intercept (e.g. CR0.MP).
- Writes to CR0 using LMSW, which should always intercept (even when
  updating CR0.MP).

Emulator variants of all test cases are added as well.

The new tests exercises bugs fixed by:
https://lore.kernel.org/kvm/20251024192918.3191141-1-yosry.ahmed@linux.dev/.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 x86/svm_tests.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 72 insertions(+), 4 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 71afb38a..2981f459 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -129,20 +129,36 @@ static bool finished_rsm_intercept(struct svm_test *test)
 
 static void prepare_sel_cr0_intercept(struct svm_test *test)
 {
+	/* Clear CR0.MP and CR0.CD as the tests will set either of them */
+	vmcb->save.cr0 &= ~X86_CR0_MP;
 	vmcb->save.cr0 &= ~X86_CR0_CD;
 	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
 }
 
+static void prepare_sel_nonsel_cr0_intercepts(struct svm_test *test)
+{
+	/* Clear CR0.MP and CR0.CD as the tests will set either of them */
+	vmcb->save.cr0 &= ~X86_CR0_MP;
+	vmcb->save.cr0 &= ~X86_CR0_CD;
+	vmcb->control.intercept_cr_write |= (1ULL << 0);
+	vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
+}
+
 static void __test_cr0_write_bit(struct svm_test *test, unsigned long bit,
-				 bool intercept, bool fep)
+				 bool is_lmsw, bool intercept, bool fep)
 {
+	unsigned short msw;
 	unsigned long cr0;
 
 	cr0 = read_cr0();
 	cr0 |= bit;
+	msw = cr0 & 0xfUL;
 	test->scratch = cr0;
 
-	asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
+	if (is_lmsw)
+		asm_conditional_fep_safe(fep, "lmsw %0", "r"(msw));
+	else
+		asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
 
 	/* This code should be unreachable when an intercept is expected */
 	report_svm_guest(!intercept, test, "Expected intercept on CR0 write");
@@ -151,12 +167,34 @@ static void __test_cr0_write_bit(struct svm_test *test, unsigned long bit,
 /* MOV-to-CR0 updating CR0.CD is intercepted by the selective intercept */
 static void test_sel_cr0_write_intercept(struct svm_test *test)
 {
-	__test_cr0_write_bit(test, X86_CR0_CD, true, false);
+	__test_cr0_write_bit(test, X86_CR0_CD, false, true, false);
 }
 
 static void test_sel_cr0_write_intercept_emul(struct svm_test *test)
 {
-	__test_cr0_write_bit(test, X86_CR0_CD, true, true);
+	__test_cr0_write_bit(test, X86_CR0_CD, false, true, true);
+}
+
+/* MOV-to-CR0 updating CR0.MP is NOT intercepted by the selective intercept */
+static void test_sel_cr0_write_nointercept(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_MP, false, false, false);
+}
+
+static void test_sel_cr0_write_nointercept_emul(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_MP, false, false, true);
+}
+
+/* LMSW updating CR0.MP is intercepted by the selective intercept */
+static void test_sel_cr0_lmsw_intercept(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_MP, true, false, false);
+}
+
+static void test_sel_cr0_lmsw_intercept_emul(struct svm_test *test)
+{
+	__test_cr0_write_bit(test, X86_CR0_MP, true, false, true);
 }
 
 static bool check_sel_cr0_intercept(struct svm_test *test)
@@ -165,6 +203,18 @@ static bool check_sel_cr0_intercept(struct svm_test *test)
 		vmcb->save.cr0 != test->scratch;
 }
 
+static bool check_nonsel_cr0_intercept(struct svm_test *test)
+{
+	return vmcb->control.exit_code == SVM_EXIT_WRITE_CR0 &&
+		vmcb->save.cr0 != test->scratch;
+}
+
+static bool check_cr0_nointercept(struct svm_test *test)
+{
+	return vmcb->control.exit_code == SVM_EXIT_VMMCALL &&
+		vmcb->save.cr0 == test->scratch;
+}
+
 static void prepare_cr3_intercept(struct svm_test *test)
 {
 	default_prepare(test);
@@ -3473,6 +3523,24 @@ struct svm_test svm_tests[] = {
 	{ "sel cr0 write intercept emulate", fep_supported,
 	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
 	  test_sel_cr0_write_intercept_emul, default_finished, check_sel_cr0_intercept},
+	{ "sel cr0 write intercept priority", default_supported,
+	  prepare_sel_nonsel_cr0_intercepts, default_prepare_gif_clear,
+	  test_sel_cr0_write_intercept, default_finished, check_nonsel_cr0_intercept},
+	{ "sel cr0 write intercept priority emulate", fep_supported,
+	  prepare_sel_nonsel_cr0_intercepts, default_prepare_gif_clear,
+	  test_sel_cr0_write_intercept_emul, default_finished, check_nonsel_cr0_intercept},
+	{ "sel cr0 write nointercept", default_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_write_nointercept, default_finished, check_cr0_nointercept},
+	{ "sel cr0 write nointercept emulate", fep_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_write_nointercept_emul, default_finished, check_cr0_nointercept},
+	{ "sel cr0 lmsw intercept", default_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_lmsw_intercept, default_finished, check_sel_cr0_intercept},
+	{ "sel cr0 lmsw intercept emulate", fep_supported,
+	  prepare_sel_cr0_intercept, default_prepare_gif_clear,
+	  test_sel_cr0_lmsw_intercept_emul, default_finished, check_sel_cr0_intercept},
 	{ "cr3 read intercept", default_supported,
 	  prepare_cr3_intercept, default_prepare_gif_clear,
 	  test_cr3_intercept, default_finished, check_cr3_intercept },
-- 
2.51.1.821.gb6fe4d2222-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [kvm-unit-tests 0/7] More tests for selective CR0 intercept
  2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
                   ` (6 preceding siblings ...)
  2025-10-24 19:49 ` [kvm-unit-tests 7/7] x86/svm: Add more selective CR0 write and LMSW test cases Yosry Ahmed
@ 2025-10-24 20:02 ` Yosry Ahmed
  7 siblings, 0 replies; 9+ messages in thread
From: Yosry Ahmed @ 2025-10-24 20:02 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: Paolo Bonzini, Jim Mattson, kvm, linux-kernel

On Fri, Oct 24, 2025 at 07:49:18PM +0000, Yosry Ahmed wrote:
> From: Yosry Ahmed <yosryahmed@google.com>

Ugh I messed up the From email address again (and the Signed-off-by)..

> 
> Add more test cases for the selective CR0 write intercept, covering bugs
> fixed by
> https://lore.kernel.org/kvm/20251024192918.3191141-1-yosry.ahmed@linux.dev/.
> 
> Patches 1-5 are cleanups and prep work. Patch 6 generalizes the existing
> test to make it easy to extend, and patch 7 adds the actual tests.
> 
> Yosry Ahmed (7):
>   x86/svm: Cleanup selective cr0 write intercept test
>   x86/svm: Move CR0 selective write intercept test near CR3 intercept
>   x86/svm: Add FEP helpers for SVM tests
>   x86/svm: Report unsupported SVM tests
>   x86/svm: Move report_svm_guest() to the top of svm_tests.c
>   x86/svm: Generalize and improve selective CR0 write intercept test
>   x86/svm: Add more selective CR0 write and LMSW test cases
> 
>  lib/x86/desc.h  |   8 +++
>  x86/svm.c       |   9 ++-
>  x86/svm.h       |   1 +
>  x86/svm_tests.c | 178 ++++++++++++++++++++++++++++++++++--------------
>  4 files changed, 144 insertions(+), 52 deletions(-)
> 
> -- 
> 2.51.1.821.gb6fe4d2222-goog
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-10-24 20:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-24 19:49 [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 1/7] x86/svm: Cleanup selective cr0 write intercept test Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 2/7] x86/svm: Move CR0 selective write intercept test near CR3 intercept Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 3/7] x86/svm: Add FEP helpers for SVM tests Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 4/7] x86/svm: Report unsupported " Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 5/7] x86/svm: Move report_svm_guest() to the top of svm_tests.c Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 6/7] x86/svm: Generalize and improve selective CR0 write intercept test Yosry Ahmed
2025-10-24 19:49 ` [kvm-unit-tests 7/7] x86/svm: Add more selective CR0 write and LMSW test cases Yosry Ahmed
2025-10-24 20:02 ` [kvm-unit-tests 0/7] More tests for selective CR0 intercept Yosry Ahmed

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®