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