* [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