@@ -129,20 +129,36 @@ static bool finished_rsm_intercept(struct svm_test *test)
129129
130130static 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+
136147static 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 */
152168static 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
157173static 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
162200static 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+
168218static 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