xref: /kvm-unit-tests/x86/svm_npt.c (revision 14b54ed754c8a8cae7a22895e4a0b745a3227a4b)
1 #include "svm.h"
2 #include "vm.h"
3 #include "alloc_page.h"
4 #include "vmalloc.h"
5 
6 static void *scratch_page;
7 
null_test(struct svm_test * test)8 static void null_test(struct svm_test *test)
9 {
10 }
11 
npt_np_prepare(struct svm_test * test)12 static void npt_np_prepare(struct svm_test *test)
13 {
14 	u64 *pte;
15 
16 	scratch_page = alloc_page();
17 	pte = npt_get_pte((u64) scratch_page);
18 
19 	*pte &= ~1ULL;
20 }
21 
npt_np_test(struct svm_test * test)22 static void npt_np_test(struct svm_test *test)
23 {
24 	(void)*(volatile u64 *)scratch_page;
25 }
26 
npt_np_check(struct svm_test * test)27 static bool npt_np_check(struct svm_test *test)
28 {
29 	u64 *pte = npt_get_pte((u64) scratch_page);
30 
31 	*pte |= 1ULL;
32 
33 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
34 	    && (vmcb->control.exit_info_1 == 0x100000004ULL);
35 }
36 
npt_nx_prepare(struct svm_test * test)37 static void npt_nx_prepare(struct svm_test *test)
38 {
39 	u64 *pte;
40 
41 	test->scratch = rdmsr(MSR_EFER);
42 	wrmsr(MSR_EFER, test->scratch | EFER_NX);
43 
44 	/* Clear the guest's EFER.NX, it should not affect NPT behavior. */
45 	vmcb->save.efer &= ~EFER_NX;
46 
47 	pte = npt_get_pte((u64) null_test);
48 
49 	*pte |= PT64_NX_MASK;
50 }
51 
npt_nx_check(struct svm_test * test)52 static bool npt_nx_check(struct svm_test *test)
53 {
54 	u64 *pte = npt_get_pte((u64) null_test);
55 
56 	wrmsr(MSR_EFER, test->scratch);
57 
58 	*pte &= ~PT64_NX_MASK;
59 
60 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
61 	    && (vmcb->control.exit_info_1 == 0x100000015ULL);
62 }
63 
npt_us_prepare(struct svm_test * test)64 static void npt_us_prepare(struct svm_test *test)
65 {
66 	u64 *pte;
67 
68 	scratch_page = alloc_page();
69 	pte = npt_get_pte((u64) scratch_page);
70 
71 	*pte &= ~(1ULL << 2);
72 }
73 
npt_us_test(struct svm_test * test)74 static void npt_us_test(struct svm_test *test)
75 {
76 	(void)*(volatile u64 *)scratch_page;
77 }
78 
npt_us_check(struct svm_test * test)79 static bool npt_us_check(struct svm_test *test)
80 {
81 	u64 *pte = npt_get_pte((u64) scratch_page);
82 
83 	*pte |= (1ULL << 2);
84 
85 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
86 	    && (vmcb->control.exit_info_1 == 0x100000005ULL);
87 }
88 
npt_rw_prepare(struct svm_test * test)89 static void npt_rw_prepare(struct svm_test *test)
90 {
91 
92 	u64 *pte;
93 
94 	pte = npt_get_pte(0x80000);
95 
96 	*pte &= ~(1ULL << 1);
97 }
98 
npt_rw_test(struct svm_test * test)99 static void npt_rw_test(struct svm_test *test)
100 {
101 	u64 *data = (void *)(0x80000);
102 
103 	*data = 0;
104 }
105 
npt_rw_check(struct svm_test * test)106 static bool npt_rw_check(struct svm_test *test)
107 {
108 	u64 *pte = npt_get_pte(0x80000);
109 
110 	*pte |= (1ULL << 1);
111 
112 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
113 	    && (vmcb->control.exit_info_1 == 0x100000007ULL);
114 }
115 
npt_rw_pfwalk_prepare(struct svm_test * test)116 static void npt_rw_pfwalk_prepare(struct svm_test *test)
117 {
118 
119 	u64 *pte;
120 
121 	pte = npt_get_pte(read_cr3());
122 
123 	*pte &= ~(1ULL << 1);
124 }
125 
npt_rw_pfwalk_check(struct svm_test * test)126 static bool npt_rw_pfwalk_check(struct svm_test *test)
127 {
128 	u64 *pte = npt_get_pte(read_cr3());
129 
130 	*pte |= (1ULL << 1);
131 
132 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
133 	    && (vmcb->control.exit_info_1 == 0x200000007ULL)
134 	    && (vmcb->control.exit_info_2 == read_cr3());
135 }
136 
npt_l1mmio_prepare(struct svm_test * test)137 static void npt_l1mmio_prepare(struct svm_test *test)
138 {
139 }
140 
141 u32 nested_apic_version1;
142 u32 nested_apic_version2;
143 
npt_l1mmio_test(struct svm_test * test)144 static void npt_l1mmio_test(struct svm_test *test)
145 {
146 	volatile u32 *data = (volatile void *)(0xfee00030UL);
147 
148 	nested_apic_version1 = *data;
149 	nested_apic_version2 = *data;
150 }
151 
npt_l1mmio_check(struct svm_test * test)152 static bool npt_l1mmio_check(struct svm_test *test)
153 {
154 	volatile u32 *data = (volatile void *)(0xfee00030);
155 	u32 lvr = *data;
156 
157 	return nested_apic_version1 == lvr && nested_apic_version2 == lvr;
158 }
159 
npt_rw_l1mmio_prepare(struct svm_test * test)160 static void npt_rw_l1mmio_prepare(struct svm_test *test)
161 {
162 
163 	u64 *pte;
164 
165 	pte = npt_get_pte(0xfee00080);
166 
167 	*pte &= ~(1ULL << 1);
168 }
169 
npt_rw_l1mmio_test(struct svm_test * test)170 static void npt_rw_l1mmio_test(struct svm_test *test)
171 {
172 	volatile u32 *data = (volatile void *)(0xfee00080);
173 
174 	*data = *data;
175 }
176 
npt_rw_l1mmio_check(struct svm_test * test)177 static bool npt_rw_l1mmio_check(struct svm_test *test)
178 {
179 	u64 *pte = npt_get_pte(0xfee00080);
180 
181 	*pte |= (1ULL << 1);
182 
183 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
184 	    && (vmcb->control.exit_info_1 == 0x100000007ULL);
185 }
186 
basic_guest_main(struct svm_test * test)187 static void basic_guest_main(struct svm_test *test)
188 {
189 }
190 
__svm_npt_rsvd_bits_test(u64 * pxe,u64 rsvd_bits,u64 efer,ulong cr4,u64 guest_efer,ulong guest_cr4)191 static void __svm_npt_rsvd_bits_test(u64 * pxe, u64 rsvd_bits, u64 efer,
192 				     ulong cr4, u64 guest_efer, ulong guest_cr4)
193 {
194 	u64 pxe_orig = *pxe;
195 	int exit_reason;
196 	u64 pfec;
197 
198 	wrmsr(MSR_EFER, efer);
199 	write_cr4(cr4);
200 
201 	vmcb->save.efer = guest_efer;
202 	vmcb->save.cr4 = guest_cr4;
203 
204 	*pxe |= rsvd_bits;
205 
206 	exit_reason = svm_vmrun();
207 
208 	report(exit_reason == SVM_EXIT_NPF,
209 	       "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%x", rsvd_bits,
210 	       exit_reason);
211 
212 	if (pxe == npt_get_pdpe((u64) basic_guest_main) || pxe == npt_get_pml4e()) {
213 		/*
214 		 * The guest's page tables will blow up on a bad PDPE/PML4E,
215 		 * before starting the final walk of the guest page.
216 		 */
217 		pfec = 0x20000000full;
218 	} else {
219 		/* RSVD #NPF on final walk of guest page. */
220 		pfec = 0x10000000dULL;
221 
222 		/* PFEC.FETCH=1 if NX=1 *or* SMEP=1. */
223 		if ((cr4 & X86_CR4_SMEP) || (efer & EFER_NX))
224 			pfec |= 0x10;
225 
226 	}
227 
228 	report(vmcb->control.exit_info_1 == pfec,
229 	       "Wanted PFEC = 0x%lx, got PFEC = %lx, PxE = 0x%lx.  "
230 	       "host.NX = %u, host.SMEP = %u, guest.NX = %u, guest.SMEP = %u",
231 	       pfec, vmcb->control.exit_info_1, *pxe,
232 	       !!(efer & EFER_NX), !!(cr4 & X86_CR4_SMEP),
233 	       !!(guest_efer & EFER_NX), !!(guest_cr4 & X86_CR4_SMEP));
234 
235 	*pxe = pxe_orig;
236 }
237 
_svm_npt_rsvd_bits_test(u64 * pxe,u64 pxe_rsvd_bits,u64 efer,ulong cr4,u64 guest_efer,ulong guest_cr4)238 static void _svm_npt_rsvd_bits_test(u64 * pxe, u64 pxe_rsvd_bits, u64 efer,
239 				    ulong cr4, u64 guest_efer, ulong guest_cr4)
240 {
241 	u64 rsvd_bits;
242 	int i;
243 
244 	/*
245 	 * RDTSC or RDRAND can sometimes fail to generate a valid reserved bits
246 	 */
247 	if (!pxe_rsvd_bits) {
248 		report_skip
249 		    ("svm_npt_rsvd_bits_test: Reserved bits are not valid");
250 		return;
251 	}
252 
253 	/*
254 	 * Test all combinations of guest/host EFER.NX and CR4.SMEP.  If host
255 	 * EFER.NX=0, use NX as the reserved bit, otherwise use the passed in
256 	 * @pxe_rsvd_bits.
257 	 */
258 	for (i = 0; i < 16; i++) {
259 		if (i & 1) {
260 			rsvd_bits = pxe_rsvd_bits;
261 			efer |= EFER_NX;
262 		} else {
263 			rsvd_bits = PT64_NX_MASK;
264 			efer &= ~EFER_NX;
265 		}
266 		if (i & 2)
267 			cr4 |= X86_CR4_SMEP;
268 		else
269 			cr4 &= ~X86_CR4_SMEP;
270 		if (i & 4)
271 			guest_efer |= EFER_NX;
272 		else
273 			guest_efer &= ~EFER_NX;
274 		if (i & 8)
275 			guest_cr4 |= X86_CR4_SMEP;
276 		else
277 			guest_cr4 &= ~X86_CR4_SMEP;
278 
279 		__svm_npt_rsvd_bits_test(pxe, rsvd_bits, efer, cr4,
280 					 guest_efer, guest_cr4);
281 	}
282 }
283 
get_random_bits(u64 hi,u64 low)284 static u64 get_random_bits(u64 hi, u64 low)
285 {
286 	unsigned retry = 5;
287 	u64 rsvd_bits = 0;
288 
289 	if (this_cpu_has(X86_FEATURE_RDRAND)) {
290 		do {
291 			rsvd_bits = (rdrand() << low) & GENMASK_ULL(hi, low);
292 			retry--;
293 		} while (!rsvd_bits && retry);
294 	}
295 
296 	if (!rsvd_bits) {
297 		retry = 5;
298 		do {
299 			rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low);
300 			retry--;
301 		} while (!rsvd_bits && retry);
302 	}
303 
304 	return rsvd_bits;
305 }
306 
svm_npt_rsvd_bits_test(void)307 static void svm_npt_rsvd_bits_test(void)
308 {
309 	u64 saved_efer, host_efer, sg_efer, guest_efer;
310 	ulong saved_cr4, host_cr4, sg_cr4, guest_cr4;
311 
312 	if (!npt_supported()) {
313 		report_skip("NPT not supported");
314 		return;
315 	}
316 
317 	saved_efer = host_efer = rdmsr(MSR_EFER);
318 	saved_cr4 = host_cr4 = read_cr4();
319 	sg_efer = guest_efer = vmcb->save.efer;
320 	sg_cr4 = guest_cr4 = vmcb->save.cr4;
321 
322 	test_set_guest(basic_guest_main);
323 
324 	/*
325 	 * 4k PTEs don't have reserved bits if MAXPHYADDR >= 52, just skip the
326 	 * sub-test.  The NX test is still valid, but the extra bit of coverage
327 	 * isn't worth the extra complexity.
328 	 */
329 	if (cpuid_maxphyaddr() >= 52)
330 		goto skip_pte_test;
331 
332 	_svm_npt_rsvd_bits_test(npt_get_pte((u64) basic_guest_main),
333 				get_random_bits(51, cpuid_maxphyaddr()),
334 				host_efer, host_cr4, guest_efer, guest_cr4);
335 
336 skip_pte_test:
337 	_svm_npt_rsvd_bits_test(npt_get_pde((u64) basic_guest_main),
338 				get_random_bits(20, 13) | PT_PAGE_SIZE_MASK,
339 				host_efer, host_cr4, guest_efer, guest_cr4);
340 
341 	_svm_npt_rsvd_bits_test(npt_get_pdpe((u64) basic_guest_main),
342 				PT_PAGE_SIZE_MASK |
343 				(this_cpu_has(X86_FEATURE_GBPAGES) ?
344 				 get_random_bits(29, 13) : 0), host_efer,
345 				host_cr4, guest_efer, guest_cr4);
346 
347 	_svm_npt_rsvd_bits_test(npt_get_pml4e(), BIT_ULL(8),
348 				host_efer, host_cr4, guest_efer, guest_cr4);
349 
350 	wrmsr(MSR_EFER, saved_efer);
351 	write_cr4(saved_cr4);
352 	vmcb->save.efer = sg_efer;
353 	vmcb->save.cr4 = sg_cr4;
354 }
355 
356 #define NPT_V1_TEST(name, prepare, guest_code, check)				\
357 	{ #name, npt_supported, prepare, default_prepare_gif_clear, guest_code,	\
358 	  default_finished, check }
359 
360 #define NPT_V2_TEST(name) { #name, .v2 = name }
361 
362 static struct svm_test npt_tests[] = {
363 	NPT_V1_TEST(npt_nx, npt_nx_prepare, null_test, npt_nx_check),
364 	NPT_V1_TEST(npt_np, npt_np_prepare, npt_np_test, npt_np_check),
365 	NPT_V1_TEST(npt_us, npt_us_prepare, npt_us_test, npt_us_check),
366 	NPT_V1_TEST(npt_rw, npt_rw_prepare, npt_rw_test, npt_rw_check),
367 	NPT_V1_TEST(npt_rw_pfwalk, npt_rw_pfwalk_prepare, null_test, npt_rw_pfwalk_check),
368 	NPT_V1_TEST(npt_l1mmio, npt_l1mmio_prepare, npt_l1mmio_test, npt_l1mmio_check),
369 	NPT_V1_TEST(npt_rw_l1mmio, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test, npt_rw_l1mmio_check),
370 	NPT_V2_TEST(svm_npt_rsvd_bits_test),
371 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
372 };
373 
main(int ac,char ** av)374 int main(int ac, char **av)
375 {
376 	pteval_t opt_mask = 0;
377 
378 	__setup_vm(&opt_mask);
379 	return run_svm_tests(ac, av, npt_tests);
380 }
381