Skip to content

Commit 09e2c95

Browse files
yosrym93sean-jc
authored andcommitted
x86/svm: Add more selective CR0 write and LMSW test cases
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 <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251110232642.633672-12-yosry.ahmed@linux.dev Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent cc34f04 commit 09e2c95

File tree

1 file changed

+72
-4
lines changed

1 file changed

+72
-4
lines changed

x86/svm_tests.c

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,36 @@ static bool finished_rsm_intercept(struct svm_test *test)
129129

130130
static void prepare_sel_cr0_intercept(struct svm_test *test)
131131
{
132+
/* Clear CR0.MP and CR0.CD as the tests will set either of them */
133+
vmcb->save.cr0 &= ~X86_CR0_MP;
132134
vmcb->save.cr0 &= ~X86_CR0_CD;
133135
vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
134136
}
135137

138+
static void prepare_sel_nonsel_cr0_intercepts(struct svm_test *test)
139+
{
140+
/* Clear CR0.MP and CR0.CD as the tests will set either of them */
141+
vmcb->save.cr0 &= ~X86_CR0_MP;
142+
vmcb->save.cr0 &= ~X86_CR0_CD;
143+
vmcb->control.intercept_cr_write |= (1ULL << 0);
144+
vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0);
145+
}
146+
136147
static void __test_cr0_write_bit(struct svm_test *test, unsigned long bit,
137-
bool intercept, bool fep)
148+
bool is_lmsw, bool intercept, bool fep)
138149
{
150+
unsigned short msw;
139151
unsigned long cr0;
140152

141153
cr0 = read_cr0();
142154
cr0 |= bit;
155+
msw = cr0 & 0xfUL;
143156
test->scratch = cr0;
144157

145-
asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
158+
if (is_lmsw)
159+
asm_conditional_fep_safe(fep, "lmsw %0", "r"(msw));
160+
else
161+
asm_conditional_fep_safe(fep, "mov %0,%%cr0", "r"(cr0));
146162

147163
/* This code should be unreachable when an intercept is expected */
148164
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,
151167
/* MOV-to-CR0 updating CR0.CD is intercepted by the selective intercept */
152168
static void test_sel_cr0_write_intercept(struct svm_test *test)
153169
{
154-
__test_cr0_write_bit(test, X86_CR0_CD, true, false);
170+
__test_cr0_write_bit(test, X86_CR0_CD, false, true, false);
155171
}
156172

157173
static void test_sel_cr0_write_intercept_emul(struct svm_test *test)
158174
{
159-
__test_cr0_write_bit(test, X86_CR0_CD, true, true);
175+
__test_cr0_write_bit(test, X86_CR0_CD, false, true, true);
176+
}
177+
178+
/* MOV-to-CR0 updating CR0.MP is NOT intercepted by the selective intercept */
179+
static void test_sel_cr0_write_nointercept(struct svm_test *test)
180+
{
181+
__test_cr0_write_bit(test, X86_CR0_MP, false, false, false);
182+
}
183+
184+
static void test_sel_cr0_write_nointercept_emul(struct svm_test *test)
185+
{
186+
__test_cr0_write_bit(test, X86_CR0_MP, false, false, true);
187+
}
188+
189+
/* LMSW updating CR0.MP is intercepted by the selective intercept */
190+
static void test_sel_cr0_lmsw_intercept(struct svm_test *test)
191+
{
192+
__test_cr0_write_bit(test, X86_CR0_MP, true, false, false);
193+
}
194+
195+
static void test_sel_cr0_lmsw_intercept_emul(struct svm_test *test)
196+
{
197+
__test_cr0_write_bit(test, X86_CR0_MP, true, false, true);
160198
}
161199

162200
static bool check_sel_cr0_intercept(struct svm_test *test)
@@ -165,6 +203,18 @@ static bool check_sel_cr0_intercept(struct svm_test *test)
165203
vmcb->save.cr0 != test->scratch;
166204
}
167205

206+
static bool check_nonsel_cr0_intercept(struct svm_test *test)
207+
{
208+
return vmcb->control.exit_code == SVM_EXIT_WRITE_CR0 &&
209+
vmcb->save.cr0 != test->scratch;
210+
}
211+
212+
static bool check_cr0_nointercept(struct svm_test *test)
213+
{
214+
return vmcb->control.exit_code == SVM_EXIT_VMMCALL &&
215+
vmcb->save.cr0 == test->scratch;
216+
}
217+
168218
static void prepare_cr3_intercept(struct svm_test *test)
169219
{
170220
default_prepare(test);
@@ -3473,6 +3523,24 @@ struct svm_test svm_tests[] = {
34733523
{ "sel cr0 write intercept emulate", fep_supported,
34743524
prepare_sel_cr0_intercept, default_prepare_gif_clear,
34753525
test_sel_cr0_write_intercept_emul, default_finished, check_sel_cr0_intercept},
3526+
{ "sel cr0 write intercept priority", default_supported,
3527+
prepare_sel_nonsel_cr0_intercepts, default_prepare_gif_clear,
3528+
test_sel_cr0_write_intercept, default_finished, check_nonsel_cr0_intercept},
3529+
{ "sel cr0 write intercept priority emulate", fep_supported,
3530+
prepare_sel_nonsel_cr0_intercepts, default_prepare_gif_clear,
3531+
test_sel_cr0_write_intercept_emul, default_finished, check_nonsel_cr0_intercept},
3532+
{ "sel cr0 write nointercept", default_supported,
3533+
prepare_sel_cr0_intercept, default_prepare_gif_clear,
3534+
test_sel_cr0_write_nointercept, default_finished, check_cr0_nointercept},
3535+
{ "sel cr0 write nointercept emulate", fep_supported,
3536+
prepare_sel_cr0_intercept, default_prepare_gif_clear,
3537+
test_sel_cr0_write_nointercept_emul, default_finished, check_cr0_nointercept},
3538+
{ "sel cr0 lmsw intercept", default_supported,
3539+
prepare_sel_cr0_intercept, default_prepare_gif_clear,
3540+
test_sel_cr0_lmsw_intercept, default_finished, check_sel_cr0_intercept},
3541+
{ "sel cr0 lmsw intercept emulate", fep_supported,
3542+
prepare_sel_cr0_intercept, default_prepare_gif_clear,
3543+
test_sel_cr0_lmsw_intercept_emul, default_finished, check_sel_cr0_intercept},
34763544
{ "cr3 read intercept", default_supported,
34773545
prepare_cr3_intercept, default_prepare_gif_clear,
34783546
test_cr3_intercept, default_finished, check_cr3_intercept },

0 commit comments

Comments
 (0)