Skip to content

Commit cc34f04

Browse files
yosrym93sean-jc
authored andcommitted
x86/svm: Generalize and improve selective CR0 write intercept test
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 <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251110232642.633672-11-yosry.ahmed@linux.dev Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 044c33c commit cc34f04

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

x86/svm_tests.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,36 @@ static void prepare_sel_cr0_intercept(struct svm_test *test)
133133
vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
134134
}
135135

136-
static void test_sel_cr0_write_intercept(struct svm_test *test)
136+
static void __test_cr0_write_bit(struct svm_test *test, unsigned long bit,
137+
bool intercept, bool fep)
137138
{
138139
unsigned long cr0;
139140

140-
/* read cr0, set CD, and write back */
141-
cr0 = read_cr0();
142-
cr0 |= X86_CR0_CD;
143-
write_cr0(cr0);
141+
cr0 = read_cr0();
142+
cr0 |= bit;
143+
test->scratch = cr0;
144144

145-
/*
146-
* If we are here the test failed, not sure what to do now because we
147-
* are not in guest-mode anymore so we can't trigger an intercept.
148-
* Trigger a tripple-fault for now.
149-
*/
150-
report_fail("sel_cr0 test. Can not recover from this - exiting");
151-
exit(report_summary());
145+
asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
146+
147+
/* This code should be unreachable when an intercept is expected */
148+
report_svm_guest(!intercept, test, "Expected intercept on CR0 write");
149+
}
150+
151+
/* MOV-to-CR0 updating CR0.CD is intercepted by the selective intercept */
152+
static void test_sel_cr0_write_intercept(struct svm_test *test)
153+
{
154+
__test_cr0_write_bit(test, X86_CR0_CD, true, false);
155+
}
156+
157+
static void test_sel_cr0_write_intercept_emul(struct svm_test *test)
158+
{
159+
__test_cr0_write_bit(test, X86_CR0_CD, true, true);
152160
}
153161

154162
static bool check_sel_cr0_intercept(struct svm_test *test)
155163
{
156-
return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE;
164+
return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE &&
165+
vmcb->save.cr0 != test->scratch;
157166
}
158167

159168
static void prepare_cr3_intercept(struct svm_test *test)
@@ -3461,6 +3470,9 @@ struct svm_test svm_tests[] = {
34613470
{ "sel cr0 write intercept", default_supported,
34623471
prepare_sel_cr0_intercept, default_prepare_gif_clear,
34633472
test_sel_cr0_write_intercept, default_finished, check_sel_cr0_intercept},
3473+
{ "sel cr0 write intercept emulate", fep_supported,
3474+
prepare_sel_cr0_intercept, default_prepare_gif_clear,
3475+
test_sel_cr0_write_intercept_emul, default_finished, check_sel_cr0_intercept},
34643476
{ "cr3 read intercept", default_supported,
34653477
prepare_cr3_intercept, default_prepare_gif_clear,
34663478
test_cr3_intercept, default_finished, check_cr3_intercept },

0 commit comments

Comments
 (0)