xref: /kvm-unit-tests/x86/svm.c (revision 8650dffe7446173d89c6a49398f3126513f33b81)
1 /*
2  * Framework for testing nested virtualization
3  */
4 
5 #include "svm.h"
6 #include "libcflat.h"
7 #include "processor.h"
8 #include "desc.h"
9 #include "msr.h"
10 #include "vm.h"
11 #include "smp.h"
12 #include "types.h"
13 #include "alloc_page.h"
14 #include "isr.h"
15 #include "apic.h"
16 #include "vmalloc.h"
17 
18 /* for the nested page table*/
19 u64 *pte[2048];
20 u64 *pde[4];
21 u64 *pdpe;
22 u64 *pml4e;
23 
24 struct vmcb *vmcb;
25 
26 u64 *npt_get_pte(u64 address)
27 {
28 	int i1, i2;
29 
30 	address >>= 12;
31 	i1 = (address >> 9) & 0x7ff;
32 	i2 = address & 0x1ff;
33 
34 	return &pte[i1][i2];
35 }
36 
37 u64 *npt_get_pde(u64 address)
38 {
39 	int i1, i2;
40 
41 	address >>= 21;
42 	i1 = (address >> 9) & 0x3;
43 	i2 = address & 0x1ff;
44 
45 	return &pde[i1][i2];
46 }
47 
48 u64 *npt_get_pdpe(void)
49 {
50 	return pdpe;
51 }
52 
53 u64 *npt_get_pml4e(void)
54 {
55 	return pml4e;
56 }
57 
58 bool smp_supported(void)
59 {
60 	return cpu_count() > 1;
61 }
62 
63 bool default_supported(void)
64 {
65     return true;
66 }
67 
68 bool vgif_supported(void)
69 {
70 	return this_cpu_has(X86_FEATURE_VGIF);
71 }
72 
73 bool lbrv_supported(void)
74 {
75     return this_cpu_has(X86_FEATURE_LBRV);
76 }
77 
78 bool tsc_scale_supported(void)
79 {
80     return this_cpu_has(X86_FEATURE_TSCRATEMSR);
81 }
82 
83 bool pause_filter_supported(void)
84 {
85     return this_cpu_has(X86_FEATURE_PAUSEFILTER);
86 }
87 
88 bool pause_threshold_supported(void)
89 {
90     return this_cpu_has(X86_FEATURE_PFTHRESHOLD);
91 }
92 
93 
94 void default_prepare(struct svm_test *test)
95 {
96 	vmcb_ident(vmcb);
97 }
98 
99 void default_prepare_gif_clear(struct svm_test *test)
100 {
101 }
102 
103 bool default_finished(struct svm_test *test)
104 {
105 	return true; /* one vmexit */
106 }
107 
108 bool npt_supported(void)
109 {
110 	return this_cpu_has(X86_FEATURE_NPT);
111 }
112 
113 int get_test_stage(struct svm_test *test)
114 {
115 	barrier();
116 	return test->scratch;
117 }
118 
119 void set_test_stage(struct svm_test *test, int s)
120 {
121 	barrier();
122 	test->scratch = s;
123 	barrier();
124 }
125 
126 void inc_test_stage(struct svm_test *test)
127 {
128 	barrier();
129 	test->scratch++;
130 	barrier();
131 }
132 
133 static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
134                          u64 base, u32 limit, u32 attr)
135 {
136 	seg->selector = selector;
137 	seg->attrib = attr;
138 	seg->limit = limit;
139 	seg->base = base;
140 }
141 
142 inline void vmmcall(void)
143 {
144 	asm volatile ("vmmcall" : : : "memory");
145 }
146 
147 static test_guest_func guest_main;
148 
149 void test_set_guest(test_guest_func func)
150 {
151 	guest_main = func;
152 }
153 
154 static void test_thunk(struct svm_test *test)
155 {
156 	guest_main(test);
157 	vmmcall();
158 }
159 
160 u8 *io_bitmap;
161 u8 io_bitmap_area[16384];
162 
163 u8 *msr_bitmap;
164 u8 msr_bitmap_area[MSR_BITMAP_SIZE + PAGE_SIZE];
165 
166 void vmcb_ident(struct vmcb *vmcb)
167 {
168 	u64 vmcb_phys = virt_to_phys(vmcb);
169 	struct vmcb_save_area *save = &vmcb->save;
170 	struct vmcb_control_area *ctrl = &vmcb->control;
171 	u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
172 	    | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK;
173 	u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
174 	    | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK;
175 	struct descriptor_table_ptr desc_table_ptr;
176 
177 	memset(vmcb, 0, sizeof(*vmcb));
178 	asm volatile ("vmsave %0" : : "a"(vmcb_phys) : "memory");
179 	vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr);
180 	vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr);
181 	vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr);
182 	vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr);
183 	sgdt(&desc_table_ptr);
184 	vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
185 	sidt(&desc_table_ptr);
186 	vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
187 	ctrl->asid = 1;
188 	save->cpl = 0;
189 	save->efer = rdmsr(MSR_EFER);
190 	save->cr4 = read_cr4();
191 	save->cr3 = read_cr3();
192 	save->cr0 = read_cr0();
193 	save->dr7 = read_dr7();
194 	save->dr6 = read_dr6();
195 	save->cr2 = read_cr2();
196 	save->g_pat = rdmsr(MSR_IA32_CR_PAT);
197 	save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
198 	ctrl->intercept = (1ULL << INTERCEPT_VMRUN) |
199 			  (1ULL << INTERCEPT_VMMCALL) |
200 			  (1ULL << INTERCEPT_SHUTDOWN);
201 	ctrl->iopm_base_pa = virt_to_phys(io_bitmap);
202 	ctrl->msrpm_base_pa = virt_to_phys(msr_bitmap);
203 
204 	if (npt_supported()) {
205 		ctrl->nested_ctl = 1;
206 		ctrl->nested_cr3 = (u64)pml4e;
207 		ctrl->tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
208 	}
209 }
210 
211 struct regs regs;
212 
213 struct regs get_regs(void)
214 {
215 	return regs;
216 }
217 
218 // rax handled specially below
219 
220 
221 struct svm_test *v2_test;
222 
223 
224 u64 guest_stack[10000];
225 
226 int __svm_vmrun(u64 rip)
227 {
228 	vmcb->save.rip = (ulong)rip;
229 	vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
230 	regs.rdi = (ulong)v2_test;
231 
232 	asm volatile (
233 		ASM_PRE_VMRUN_CMD
234                 "vmrun %%rax\n\t"               \
235 		ASM_POST_VMRUN_CMD
236 		:
237 		: "a" (virt_to_phys(vmcb))
238 		: "memory", "r15");
239 
240 	return (vmcb->control.exit_code);
241 }
242 
243 int svm_vmrun(void)
244 {
245 	return __svm_vmrun((u64)test_thunk);
246 }
247 
248 extern u8 vmrun_rip;
249 
250 static noinline void test_run(struct svm_test *test)
251 {
252 	u64 vmcb_phys = virt_to_phys(vmcb);
253 
254 	irq_disable();
255 	vmcb_ident(vmcb);
256 
257 	test->prepare(test);
258 	guest_main = test->guest_func;
259 	vmcb->save.rip = (ulong)test_thunk;
260 	vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
261 	regs.rdi = (ulong)test;
262 	do {
263 		struct svm_test *the_test = test;
264 		u64 the_vmcb = vmcb_phys;
265 		asm volatile (
266 			"clgi;\n\t" // semi-colon needed for LLVM compatibility
267 			"sti \n\t"
268 			"call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t"
269 			"mov %[vmcb_phys], %%rax \n\t"
270 			ASM_PRE_VMRUN_CMD
271 			".global vmrun_rip\n\t"		\
272 			"vmrun_rip: vmrun %%rax\n\t"    \
273 			ASM_POST_VMRUN_CMD
274 			"cli \n\t"
275 			"stgi"
276 			: // inputs clobbered by the guest:
277 			"=D" (the_test),            // first argument register
278 			"=b" (the_vmcb)             // callee save register!
279 			: [test] "0" (the_test),
280 			[vmcb_phys] "1"(the_vmcb),
281 			[PREPARE_GIF_CLEAR] "i" (offsetof(struct svm_test, prepare_gif_clear))
282 			: "rax", "rcx", "rdx", "rsi",
283 			"r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15",
284 			"memory");
285 		++test->exits;
286 	} while (!test->finished(test));
287 	irq_enable();
288 
289 	report(test->succeeded(test), "%s", test->name);
290 
291         if (test->on_vcpu)
292 	    test->on_vcpu_done = true;
293 }
294 
295 static void set_additional_vcpu_msr(void *msr_efer)
296 {
297 	void *hsave = alloc_page();
298 
299 	wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
300 	wrmsr(MSR_EFER, (ulong)msr_efer | EFER_SVME);
301 }
302 
303 static void setup_svm(void)
304 {
305 	void *hsave = alloc_page();
306 	u64 *page, address;
307 	int i,j;
308 
309 	wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
310 	wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME);
311 
312 	io_bitmap = (void *) ALIGN((ulong)io_bitmap_area, PAGE_SIZE);
313 
314 	msr_bitmap = (void *) ALIGN((ulong)msr_bitmap_area, PAGE_SIZE);
315 
316 	if (!npt_supported())
317 		return;
318 
319 	for (i = 1; i < cpu_count(); i++)
320 		on_cpu(i, (void *)set_additional_vcpu_msr, (void *)rdmsr(MSR_EFER));
321 
322 	printf("NPT detected - running all tests with NPT enabled\n");
323 
324 	/*
325 	* Nested paging supported - Build a nested page table
326 	* Build the page-table bottom-up and map everything with 4k
327 	* pages to get enough granularity for the NPT unit-tests.
328 	*/
329 
330 	address = 0;
331 
332 	/* PTE level */
333 	for (i = 0; i < 2048; ++i) {
334 		page = alloc_page();
335 
336 		for (j = 0; j < 512; ++j, address += 4096)
337 	    		page[j] = address | 0x067ULL;
338 
339 		pte[i] = page;
340 	}
341 
342 	/* PDE level */
343 	for (i = 0; i < 4; ++i) {
344 		page = alloc_page();
345 
346 	for (j = 0; j < 512; ++j)
347 	    page[j] = (u64)pte[(i * 512) + j] | 0x027ULL;
348 
349 		pde[i] = page;
350 	}
351 
352 	/* PDPe level */
353 	pdpe   = alloc_page();
354 	for (i = 0; i < 4; ++i)
355 		pdpe[i] = ((u64)(pde[i])) | 0x27;
356 
357 	/* PML4e level */
358 	pml4e    = alloc_page();
359 	pml4e[0] = ((u64)pdpe) | 0x27;
360 }
361 
362 int matched;
363 
364 static bool
365 test_wanted(const char *name, char *filters[], int filter_count)
366 {
367         int i;
368         bool positive = false;
369         bool match = false;
370         char clean_name[strlen(name) + 1];
371         char *c;
372         const char *n;
373 
374         /* Replace spaces with underscores. */
375         n = name;
376         c = &clean_name[0];
377         do *c++ = (*n == ' ') ? '_' : *n;
378         while (*n++);
379 
380         for (i = 0; i < filter_count; i++) {
381                 const char *filter = filters[i];
382 
383                 if (filter[0] == '-') {
384                         if (simple_glob(clean_name, filter + 1))
385                                 return false;
386                 } else {
387                         positive = true;
388                         match |= simple_glob(clean_name, filter);
389                 }
390         }
391 
392         if (!positive || match) {
393                 matched++;
394                 return true;
395         } else {
396                 return false;
397         }
398 }
399 
400 int main(int ac, char **av)
401 {
402 	/* Omit PT_USER_MASK to allow tested host.CR4.SMEP=1. */
403 	pteval_t opt_mask = 0;
404 	int i = 0;
405 
406 	ac--;
407 	av++;
408 
409 	__setup_vm(&opt_mask);
410 
411 	if (!this_cpu_has(X86_FEATURE_SVM)) {
412 		printf("SVM not availble\n");
413 		return report_summary();
414 	}
415 
416 	setup_svm();
417 
418 	vmcb = alloc_page();
419 
420 	for (; svm_tests[i].name != NULL; i++) {
421 		if (!test_wanted(svm_tests[i].name, av, ac))
422 			continue;
423 		if (svm_tests[i].supported && !svm_tests[i].supported())
424 			continue;
425 		if (svm_tests[i].v2 == NULL) {
426 			if (svm_tests[i].on_vcpu) {
427 				if (cpu_count() <= svm_tests[i].on_vcpu)
428 					continue;
429 				on_cpu_async(svm_tests[i].on_vcpu, (void *)test_run, &svm_tests[i]);
430 				while (!svm_tests[i].on_vcpu_done)
431 					cpu_relax();
432 			}
433 			else
434 				test_run(&svm_tests[i]);
435 		} else {
436 			vmcb_ident(vmcb);
437 			v2_test = &(svm_tests[i]);
438 			svm_tests[i].v2();
439 		}
440 	}
441 
442 	if (!matched)
443 		report(matched, "command line didn't match any tests!");
444 
445 	return report_summary();
446 }
447