xref: /kvm-unit-tests/x86/vmx_tests.c (revision d5efd772c4ebf893e28e5bf3c8cf256d80a5154f)
1 /*
2  * All test cases of nested virtualization should be in this file
3  *
4  * Author : Arthur Chunqi Li <yzt356@gmail.com>
5  */
6 #include "vmx.h"
7 #include "msr.h"
8 #include "processor.h"
9 #include "vm.h"
10 #include "io.h"
11 #include "fwcfg.h"
12 
13 u64 ia32_pat;
14 u64 ia32_efer;
15 volatile u32 stage;
16 void *io_bitmap_a, *io_bitmap_b;
17 u16 ioport;
18 
19 bool init_fail;
20 unsigned long *pml4;
21 u64 eptp;
22 void *data_page1, *data_page2;
23 
24 static inline void vmcall()
25 {
26 	asm volatile("vmcall");
27 }
28 
29 static inline void set_stage(u32 s)
30 {
31 	barrier();
32 	stage = s;
33 	barrier();
34 }
35 
36 static inline u32 get_stage()
37 {
38 	u32 s;
39 
40 	barrier();
41 	s = stage;
42 	barrier();
43 	return s;
44 }
45 
46 void basic_init()
47 {
48 }
49 
50 void basic_guest_main()
51 {
52 	/* Here is a basic guest_main, print Hello World */
53 	printf("\tHello World, this is null_guest_main!\n");
54 }
55 
56 int basic_exit_handler()
57 {
58 	u64 guest_rip;
59 	ulong reason;
60 
61 	guest_rip = vmcs_read(GUEST_RIP);
62 	reason = vmcs_read(EXI_REASON) & 0xff;
63 
64 	switch (reason) {
65 	case VMX_VMCALL:
66 		print_vmexit_info();
67 		vmcs_write(GUEST_RIP, guest_rip + 3);
68 		return VMX_TEST_RESUME;
69 	default:
70 		break;
71 	}
72 	printf("ERROR : Unhandled vmx exit.\n");
73 	print_vmexit_info();
74 	return VMX_TEST_EXIT;
75 }
76 
77 void basic_syscall_handler(u64 syscall_no)
78 {
79 }
80 
81 void vmenter_main()
82 {
83 	u64 rax;
84 	u64 rsp, resume_rsp;
85 
86 	report("test vmlaunch", 1);
87 
88 	asm volatile(
89 		"mov %%rsp, %0\n\t"
90 		"mov %3, %%rax\n\t"
91 		"vmcall\n\t"
92 		"mov %%rax, %1\n\t"
93 		"mov %%rsp, %2\n\t"
94 		: "=r"(rsp), "=r"(rax), "=r"(resume_rsp)
95 		: "g"(0xABCD));
96 	report("test vmresume", (rax == 0xFFFF) && (rsp == resume_rsp));
97 }
98 
99 int vmenter_exit_handler()
100 {
101 	u64 guest_rip;
102 	ulong reason;
103 
104 	guest_rip = vmcs_read(GUEST_RIP);
105 	reason = vmcs_read(EXI_REASON) & 0xff;
106 	switch (reason) {
107 	case VMX_VMCALL:
108 		if (regs.rax != 0xABCD) {
109 			report("test vmresume", 0);
110 			return VMX_TEST_VMEXIT;
111 		}
112 		regs.rax = 0xFFFF;
113 		vmcs_write(GUEST_RIP, guest_rip + 3);
114 		return VMX_TEST_RESUME;
115 	default:
116 		report("test vmresume", 0);
117 		print_vmexit_info();
118 	}
119 	return VMX_TEST_VMEXIT;
120 }
121 
122 u32 preempt_scale;
123 volatile unsigned long long tsc_val;
124 volatile u32 preempt_val;
125 
126 void preemption_timer_init()
127 {
128 	u32 ctrl_pin;
129 
130 	ctrl_pin = vmcs_read(PIN_CONTROLS) | PIN_PREEMPT;
131 	ctrl_pin &= ctrl_pin_rev.clr;
132 	vmcs_write(PIN_CONTROLS, ctrl_pin);
133 	preempt_val = 10000000;
134 	vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
135 	preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F;
136 
137 	if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT))
138 		printf("\tSave preemption value is not supported\n");
139 }
140 
141 void preemption_timer_main()
142 {
143 	tsc_val = rdtsc();
144 	if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) {
145 		printf("\tPreemption timer is not supported\n");
146 		return;
147 	}
148 	if (ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) {
149 		set_stage(0);
150 		vmcall();
151 		if (get_stage() == 1)
152 			vmcall();
153 	}
154 	while (1) {
155 		if (((rdtsc() - tsc_val) >> preempt_scale)
156 				> 10 * preempt_val) {
157 			set_stage(2);
158 			vmcall();
159 		}
160 	}
161 }
162 
163 int preemption_timer_exit_handler()
164 {
165 	u64 guest_rip;
166 	ulong reason;
167 	u32 insn_len;
168 	u32 ctrl_exit;
169 
170 	guest_rip = vmcs_read(GUEST_RIP);
171 	reason = vmcs_read(EXI_REASON) & 0xff;
172 	insn_len = vmcs_read(EXI_INST_LEN);
173 	switch (reason) {
174 	case VMX_PREEMPT:
175 		if (((rdtsc() - tsc_val) >> preempt_scale) < preempt_val)
176 			report("Preemption timer", 0);
177 		else
178 			report("Preemption timer", 1);
179 		break;
180 	case VMX_VMCALL:
181 		switch (get_stage()) {
182 		case 0:
183 			if (vmcs_read(PREEMPT_TIMER_VALUE) != preempt_val)
184 				report("Save preemption value", 0);
185 			else {
186 				set_stage(get_stage() + 1);
187 				ctrl_exit = (vmcs_read(EXI_CONTROLS) |
188 					EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr;
189 				vmcs_write(EXI_CONTROLS, ctrl_exit);
190 			}
191 			vmcs_write(GUEST_RIP, guest_rip + insn_len);
192 			return VMX_TEST_RESUME;
193 		case 1:
194 			if (vmcs_read(PREEMPT_TIMER_VALUE) >= preempt_val)
195 				report("Save preemption value", 0);
196 			else
197 				report("Save preemption value", 1);
198 			vmcs_write(GUEST_RIP, guest_rip + insn_len);
199 			return VMX_TEST_RESUME;
200 		case 2:
201 			report("Preemption timer", 0);
202 			break;
203 		default:
204 			// Should not reach here
205 			printf("ERROR : unexpected stage, %d\n", get_stage());
206 			print_vmexit_info();
207 			return VMX_TEST_VMEXIT;
208 		}
209 		break;
210 	default:
211 		printf("Unknown exit reason, %d\n", reason);
212 		print_vmexit_info();
213 	}
214 	vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT);
215 	return VMX_TEST_VMEXIT;
216 }
217 
218 void msr_bmp_init()
219 {
220 	void *msr_bitmap;
221 	u32 ctrl_cpu0;
222 
223 	msr_bitmap = alloc_page();
224 	memset(msr_bitmap, 0x0, PAGE_SIZE);
225 	ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0);
226 	ctrl_cpu0 |= CPU_MSR_BITMAP;
227 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0);
228 	vmcs_write(MSR_BITMAP, (u64)msr_bitmap);
229 }
230 
231 static void test_ctrl_pat_init()
232 {
233 	u64 ctrl_ent;
234 	u64 ctrl_exi;
235 
236 	msr_bmp_init();
237 	ctrl_ent = vmcs_read(ENT_CONTROLS);
238 	ctrl_exi = vmcs_read(EXI_CONTROLS);
239 	vmcs_write(ENT_CONTROLS, ctrl_ent | ENT_LOAD_PAT);
240 	vmcs_write(EXI_CONTROLS, ctrl_exi | (EXI_SAVE_PAT | EXI_LOAD_PAT));
241 	ia32_pat = rdmsr(MSR_IA32_CR_PAT);
242 	vmcs_write(GUEST_PAT, 0x0);
243 	vmcs_write(HOST_PAT, ia32_pat);
244 }
245 
246 static void test_ctrl_pat_main()
247 {
248 	u64 guest_ia32_pat;
249 
250 	guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT);
251 	if (!(ctrl_enter_rev.clr & ENT_LOAD_PAT))
252 		printf("\tENT_LOAD_PAT is not supported.\n");
253 	else {
254 		if (guest_ia32_pat != 0) {
255 			report("Entry load PAT", 0);
256 			return;
257 		}
258 	}
259 	wrmsr(MSR_IA32_CR_PAT, 0x6);
260 	vmcall();
261 	guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT);
262 	if (ctrl_enter_rev.clr & ENT_LOAD_PAT) {
263 		if (guest_ia32_pat != ia32_pat) {
264 			report("Entry load PAT", 0);
265 			return;
266 		}
267 		report("Entry load PAT", 1);
268 	}
269 }
270 
271 static int test_ctrl_pat_exit_handler()
272 {
273 	u64 guest_rip;
274 	ulong reason;
275 	u64 guest_pat;
276 
277 	guest_rip = vmcs_read(GUEST_RIP);
278 	reason = vmcs_read(EXI_REASON) & 0xff;
279 	switch (reason) {
280 	case VMX_VMCALL:
281 		guest_pat = vmcs_read(GUEST_PAT);
282 		if (!(ctrl_exit_rev.clr & EXI_SAVE_PAT)) {
283 			printf("\tEXI_SAVE_PAT is not supported\n");
284 			vmcs_write(GUEST_PAT, 0x6);
285 		} else {
286 			if (guest_pat == 0x6)
287 				report("Exit save PAT", 1);
288 			else
289 				report("Exit save PAT", 0);
290 		}
291 		if (!(ctrl_exit_rev.clr & EXI_LOAD_PAT))
292 			printf("\tEXI_LOAD_PAT is not supported\n");
293 		else {
294 			if (rdmsr(MSR_IA32_CR_PAT) == ia32_pat)
295 				report("Exit load PAT", 1);
296 			else
297 				report("Exit load PAT", 0);
298 		}
299 		vmcs_write(GUEST_PAT, ia32_pat);
300 		vmcs_write(GUEST_RIP, guest_rip + 3);
301 		return VMX_TEST_RESUME;
302 	default:
303 		printf("ERROR : Undefined exit reason, reason = %d.\n", reason);
304 		break;
305 	}
306 	return VMX_TEST_VMEXIT;
307 }
308 
309 static void test_ctrl_efer_init()
310 {
311 	u64 ctrl_ent;
312 	u64 ctrl_exi;
313 
314 	msr_bmp_init();
315 	ctrl_ent = vmcs_read(ENT_CONTROLS) | ENT_LOAD_EFER;
316 	ctrl_exi = vmcs_read(EXI_CONTROLS) | EXI_SAVE_EFER | EXI_LOAD_EFER;
317 	vmcs_write(ENT_CONTROLS, ctrl_ent & ctrl_enter_rev.clr);
318 	vmcs_write(EXI_CONTROLS, ctrl_exi & ctrl_exit_rev.clr);
319 	ia32_efer = rdmsr(MSR_EFER);
320 	vmcs_write(GUEST_EFER, ia32_efer ^ EFER_NX);
321 	vmcs_write(HOST_EFER, ia32_efer ^ EFER_NX);
322 }
323 
324 static void test_ctrl_efer_main()
325 {
326 	u64 guest_ia32_efer;
327 
328 	guest_ia32_efer = rdmsr(MSR_EFER);
329 	if (!(ctrl_enter_rev.clr & ENT_LOAD_EFER))
330 		printf("\tENT_LOAD_EFER is not supported.\n");
331 	else {
332 		if (guest_ia32_efer != (ia32_efer ^ EFER_NX)) {
333 			report("Entry load EFER", 0);
334 			return;
335 		}
336 	}
337 	wrmsr(MSR_EFER, ia32_efer);
338 	vmcall();
339 	guest_ia32_efer = rdmsr(MSR_EFER);
340 	if (ctrl_enter_rev.clr & ENT_LOAD_EFER) {
341 		if (guest_ia32_efer != ia32_efer) {
342 			report("Entry load EFER", 0);
343 			return;
344 		}
345 		report("Entry load EFER", 1);
346 	}
347 }
348 
349 static int test_ctrl_efer_exit_handler()
350 {
351 	u64 guest_rip;
352 	ulong reason;
353 	u64 guest_efer;
354 
355 	guest_rip = vmcs_read(GUEST_RIP);
356 	reason = vmcs_read(EXI_REASON) & 0xff;
357 	switch (reason) {
358 	case VMX_VMCALL:
359 		guest_efer = vmcs_read(GUEST_EFER);
360 		if (!(ctrl_exit_rev.clr & EXI_SAVE_EFER)) {
361 			printf("\tEXI_SAVE_EFER is not supported\n");
362 			vmcs_write(GUEST_EFER, ia32_efer);
363 		} else {
364 			if (guest_efer == ia32_efer)
365 				report("Exit save EFER", 1);
366 			else
367 				report("Exit save EFER", 0);
368 		}
369 		if (!(ctrl_exit_rev.clr & EXI_LOAD_EFER)) {
370 			printf("\tEXI_LOAD_EFER is not supported\n");
371 			wrmsr(MSR_EFER, ia32_efer ^ EFER_NX);
372 		} else {
373 			if (rdmsr(MSR_EFER) == (ia32_efer ^ EFER_NX))
374 				report("Exit load EFER", 1);
375 			else
376 				report("Exit load EFER", 0);
377 		}
378 		vmcs_write(GUEST_PAT, ia32_efer);
379 		vmcs_write(GUEST_RIP, guest_rip + 3);
380 		return VMX_TEST_RESUME;
381 	default:
382 		printf("ERROR : Undefined exit reason, reason = %d.\n", reason);
383 		break;
384 	}
385 	return VMX_TEST_VMEXIT;
386 }
387 
388 u32 guest_cr0, guest_cr4;
389 
390 static void cr_shadowing_main()
391 {
392 	u32 cr0, cr4, tmp;
393 
394 	// Test read through
395 	set_stage(0);
396 	guest_cr0 = read_cr0();
397 	if (stage == 1)
398 		report("Read through CR0", 0);
399 	else
400 		vmcall();
401 	set_stage(1);
402 	guest_cr4 = read_cr4();
403 	if (stage == 2)
404 		report("Read through CR4", 0);
405 	else
406 		vmcall();
407 	// Test write through
408 	guest_cr0 = guest_cr0 ^ (X86_CR0_TS | X86_CR0_MP);
409 	guest_cr4 = guest_cr4 ^ (X86_CR4_TSD | X86_CR4_DE);
410 	set_stage(2);
411 	write_cr0(guest_cr0);
412 	if (stage == 3)
413 		report("Write throuth CR0", 0);
414 	else
415 		vmcall();
416 	set_stage(3);
417 	write_cr4(guest_cr4);
418 	if (stage == 4)
419 		report("Write through CR4", 0);
420 	else
421 		vmcall();
422 	// Test read shadow
423 	set_stage(4);
424 	vmcall();
425 	cr0 = read_cr0();
426 	if (stage != 5) {
427 		if (cr0 == guest_cr0)
428 			report("Read shadowing CR0", 1);
429 		else
430 			report("Read shadowing CR0", 0);
431 	}
432 	set_stage(5);
433 	cr4 = read_cr4();
434 	if (stage != 6) {
435 		if (cr4 == guest_cr4)
436 			report("Read shadowing CR4", 1);
437 		else
438 			report("Read shadowing CR4", 0);
439 	}
440 	// Test write shadow (same value with shadow)
441 	set_stage(6);
442 	write_cr0(guest_cr0);
443 	if (stage == 7)
444 		report("Write shadowing CR0 (same value with shadow)", 0);
445 	else
446 		vmcall();
447 	set_stage(7);
448 	write_cr4(guest_cr4);
449 	if (stage == 8)
450 		report("Write shadowing CR4 (same value with shadow)", 0);
451 	else
452 		vmcall();
453 	// Test write shadow (different value)
454 	set_stage(8);
455 	tmp = guest_cr0 ^ X86_CR0_TS;
456 	asm volatile("mov %0, %%rsi\n\t"
457 		"mov %%rsi, %%cr0\n\t"
458 		::"m"(tmp)
459 		:"rsi", "memory", "cc");
460 	if (stage != 9)
461 		report("Write shadowing different X86_CR0_TS", 0);
462 	else
463 		report("Write shadowing different X86_CR0_TS", 1);
464 	set_stage(9);
465 	tmp = guest_cr0 ^ X86_CR0_MP;
466 	asm volatile("mov %0, %%rsi\n\t"
467 		"mov %%rsi, %%cr0\n\t"
468 		::"m"(tmp)
469 		:"rsi", "memory", "cc");
470 	if (stage != 10)
471 		report("Write shadowing different X86_CR0_MP", 0);
472 	else
473 		report("Write shadowing different X86_CR0_MP", 1);
474 	set_stage(10);
475 	tmp = guest_cr4 ^ X86_CR4_TSD;
476 	asm volatile("mov %0, %%rsi\n\t"
477 		"mov %%rsi, %%cr4\n\t"
478 		::"m"(tmp)
479 		:"rsi", "memory", "cc");
480 	if (stage != 11)
481 		report("Write shadowing different X86_CR4_TSD", 0);
482 	else
483 		report("Write shadowing different X86_CR4_TSD", 1);
484 	set_stage(11);
485 	tmp = guest_cr4 ^ X86_CR4_DE;
486 	asm volatile("mov %0, %%rsi\n\t"
487 		"mov %%rsi, %%cr4\n\t"
488 		::"m"(tmp)
489 		:"rsi", "memory", "cc");
490 	if (stage != 12)
491 		report("Write shadowing different X86_CR4_DE", 0);
492 	else
493 		report("Write shadowing different X86_CR4_DE", 1);
494 }
495 
496 static int cr_shadowing_exit_handler()
497 {
498 	u64 guest_rip;
499 	ulong reason;
500 	u32 insn_len;
501 	u32 exit_qual;
502 
503 	guest_rip = vmcs_read(GUEST_RIP);
504 	reason = vmcs_read(EXI_REASON) & 0xff;
505 	insn_len = vmcs_read(EXI_INST_LEN);
506 	exit_qual = vmcs_read(EXI_QUALIFICATION);
507 	switch (reason) {
508 	case VMX_VMCALL:
509 		switch (get_stage()) {
510 		case 0:
511 			if (guest_cr0 == vmcs_read(GUEST_CR0))
512 				report("Read through CR0", 1);
513 			else
514 				report("Read through CR0", 0);
515 			break;
516 		case 1:
517 			if (guest_cr4 == vmcs_read(GUEST_CR4))
518 				report("Read through CR4", 1);
519 			else
520 				report("Read through CR4", 0);
521 			break;
522 		case 2:
523 			if (guest_cr0 == vmcs_read(GUEST_CR0))
524 				report("Write through CR0", 1);
525 			else
526 				report("Write through CR0", 0);
527 			break;
528 		case 3:
529 			if (guest_cr4 == vmcs_read(GUEST_CR4))
530 				report("Write through CR4", 1);
531 			else
532 				report("Write through CR4", 0);
533 			break;
534 		case 4:
535 			guest_cr0 = vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP);
536 			guest_cr4 = vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE);
537 			vmcs_write(CR0_MASK, X86_CR0_TS | X86_CR0_MP);
538 			vmcs_write(CR0_READ_SHADOW, guest_cr0 & (X86_CR0_TS | X86_CR0_MP));
539 			vmcs_write(CR4_MASK, X86_CR4_TSD | X86_CR4_DE);
540 			vmcs_write(CR4_READ_SHADOW, guest_cr4 & (X86_CR4_TSD | X86_CR4_DE));
541 			break;
542 		case 6:
543 			if (guest_cr0 == (vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP)))
544 				report("Write shadowing CR0 (same value)", 1);
545 			else
546 				report("Write shadowing CR0 (same value)", 0);
547 			break;
548 		case 7:
549 			if (guest_cr4 == (vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE)))
550 				report("Write shadowing CR4 (same value)", 1);
551 			else
552 				report("Write shadowing CR4 (same value)", 0);
553 			break;
554 		default:
555 			// Should not reach here
556 			printf("ERROR : unexpected stage, %d\n", get_stage());
557 			print_vmexit_info();
558 			return VMX_TEST_VMEXIT;
559 		}
560 		vmcs_write(GUEST_RIP, guest_rip + insn_len);
561 		return VMX_TEST_RESUME;
562 	case VMX_CR:
563 		switch (get_stage()) {
564 		case 4:
565 			report("Read shadowing CR0", 0);
566 			set_stage(stage + 1);
567 			break;
568 		case 5:
569 			report("Read shadowing CR4", 0);
570 			set_stage(stage + 1);
571 			break;
572 		case 6:
573 			report("Write shadowing CR0 (same value)", 0);
574 			set_stage(stage + 1);
575 			break;
576 		case 7:
577 			report("Write shadowing CR4 (same value)", 0);
578 			set_stage(stage + 1);
579 			break;
580 		case 8:
581 		case 9:
582 			// 0x600 encodes "mov %esi, %cr0"
583 			if (exit_qual == 0x600)
584 				set_stage(stage + 1);
585 			break;
586 		case 10:
587 		case 11:
588 			// 0x604 encodes "mov %esi, %cr4"
589 			if (exit_qual == 0x604)
590 				set_stage(stage + 1);
591 			break;
592 		default:
593 			// Should not reach here
594 			printf("ERROR : unexpected stage, %d\n", get_stage());
595 			print_vmexit_info();
596 			return VMX_TEST_VMEXIT;
597 		}
598 		vmcs_write(GUEST_RIP, guest_rip + insn_len);
599 		return VMX_TEST_RESUME;
600 	default:
601 		printf("Unknown exit reason, %d\n", reason);
602 		print_vmexit_info();
603 	}
604 	return VMX_TEST_VMEXIT;
605 }
606 
607 static void iobmp_init()
608 {
609 	u32 ctrl_cpu0;
610 
611 	io_bitmap_a = alloc_page();
612 	io_bitmap_a = alloc_page();
613 	memset(io_bitmap_a, 0x0, PAGE_SIZE);
614 	memset(io_bitmap_b, 0x0, PAGE_SIZE);
615 	ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0);
616 	ctrl_cpu0 |= CPU_IO_BITMAP;
617 	ctrl_cpu0 &= (~CPU_IO);
618 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0);
619 	vmcs_write(IO_BITMAP_A, (u64)io_bitmap_a);
620 	vmcs_write(IO_BITMAP_B, (u64)io_bitmap_b);
621 }
622 
623 static void iobmp_main()
624 {
625 	// stage 0, test IO pass
626 	set_stage(0);
627 	inb(0x5000);
628 	outb(0x0, 0x5000);
629 	if (stage != 0)
630 		report("I/O bitmap - I/O pass", 0);
631 	else
632 		report("I/O bitmap - I/O pass", 1);
633 	// test IO width, in/out
634 	((u8 *)io_bitmap_a)[0] = 0xFF;
635 	set_stage(2);
636 	inb(0x0);
637 	if (stage != 3)
638 		report("I/O bitmap - trap in", 0);
639 	else
640 		report("I/O bitmap - trap in", 1);
641 	set_stage(3);
642 	outw(0x0, 0x0);
643 	if (stage != 4)
644 		report("I/O bitmap - trap out", 0);
645 	else
646 		report("I/O bitmap - trap out", 1);
647 	set_stage(4);
648 	inl(0x0);
649 	if (stage != 5)
650 		report("I/O bitmap - I/O width, long", 0);
651 	// test low/high IO port
652 	set_stage(5);
653 	((u8 *)io_bitmap_a)[0x5000 / 8] = (1 << (0x5000 % 8));
654 	inb(0x5000);
655 	if (stage == 6)
656 		report("I/O bitmap - I/O port, low part", 1);
657 	else
658 		report("I/O bitmap - I/O port, low part", 0);
659 	set_stage(6);
660 	((u8 *)io_bitmap_b)[0x1000 / 8] = (1 << (0x1000 % 8));
661 	inb(0x9000);
662 	if (stage == 7)
663 		report("I/O bitmap - I/O port, high part", 1);
664 	else
665 		report("I/O bitmap - I/O port, high part", 0);
666 	// test partial pass
667 	set_stage(7);
668 	inl(0x4FFF);
669 	if (stage == 8)
670 		report("I/O bitmap - partial pass", 1);
671 	else
672 		report("I/O bitmap - partial pass", 0);
673 	// test overrun
674 	set_stage(8);
675 	memset(io_bitmap_a, 0x0, PAGE_SIZE);
676 	memset(io_bitmap_b, 0x0, PAGE_SIZE);
677 	inl(0xFFFF);
678 	if (stage == 9)
679 		report("I/O bitmap - overrun", 1);
680 	else
681 		report("I/O bitmap - overrun", 0);
682 }
683 
684 static int iobmp_exit_handler()
685 {
686 	u64 guest_rip;
687 	ulong reason, exit_qual;
688 	u32 insn_len;
689 
690 	guest_rip = vmcs_read(GUEST_RIP);
691 	reason = vmcs_read(EXI_REASON) & 0xff;
692 	exit_qual = vmcs_read(EXI_QUALIFICATION);
693 	insn_len = vmcs_read(EXI_INST_LEN);
694 	switch (reason) {
695 	case VMX_IO:
696 		switch (get_stage()) {
697 		case 0:
698 		case 1:
699 			set_stage(stage + 1);
700 			break;
701 		case 2:
702 			if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_BYTE)
703 				report("I/O bitmap - I/O width, byte", 0);
704 			else
705 				report("I/O bitmap - I/O width, byte", 1);
706 			if (!(exit_qual & VMX_IO_IN))
707 				report("I/O bitmap - I/O direction, in", 0);
708 			else
709 				report("I/O bitmap - I/O direction, in", 1);
710 			set_stage(stage + 1);
711 			break;
712 		case 3:
713 			if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_WORD)
714 				report("I/O bitmap - I/O width, word", 0);
715 			else
716 				report("I/O bitmap - I/O width, word", 1);
717 			if (!(exit_qual & VMX_IO_IN))
718 				report("I/O bitmap - I/O direction, out", 1);
719 			else
720 				report("I/O bitmap - I/O direction, out", 0);
721 			set_stage(stage + 1);
722 			break;
723 		case 4:
724 			if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_LONG)
725 				report("I/O bitmap - I/O width, long", 0);
726 			else
727 				report("I/O bitmap - I/O width, long", 1);
728 			set_stage(stage + 1);
729 			break;
730 		case 5:
731 			if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x5000)
732 				set_stage(stage + 1);
733 			break;
734 		case 6:
735 			if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x9000)
736 				set_stage(stage + 1);
737 			break;
738 		case 7:
739 			if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x4FFF)
740 				set_stage(stage + 1);
741 			break;
742 		case 8:
743 			if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0xFFFF)
744 				set_stage(stage + 1);
745 			break;
746 		default:
747 			// Should not reach here
748 			printf("ERROR : unexpected stage, %d\n", get_stage());
749 			print_vmexit_info();
750 			return VMX_TEST_VMEXIT;
751 		}
752 		vmcs_write(GUEST_RIP, guest_rip + insn_len);
753 		return VMX_TEST_RESUME;
754 	default:
755 		printf("guest_rip = 0x%llx\n", guest_rip);
756 		printf("\tERROR : Undefined exit reason, reason = %d.\n", reason);
757 		break;
758 	}
759 	return VMX_TEST_VMEXIT;
760 }
761 
762 #define INSN_CPU0		0
763 #define INSN_CPU1		1
764 #define INSN_ALWAYS_TRAP	2
765 #define INSN_NEVER_TRAP		3
766 
767 #define FIELD_EXIT_QUAL		0
768 #define FIELD_INSN_INFO		1
769 
770 asm(
771 	"insn_hlt: hlt;ret\n\t"
772 	"insn_invlpg: invlpg 0x12345678;ret\n\t"
773 	"insn_mwait: mwait;ret\n\t"
774 	"insn_rdpmc: rdpmc;ret\n\t"
775 	"insn_rdtsc: rdtsc;ret\n\t"
776 	"insn_monitor: monitor;ret\n\t"
777 	"insn_pause: pause;ret\n\t"
778 	"insn_wbinvd: wbinvd;ret\n\t"
779 	"insn_cpuid: cpuid;ret\n\t"
780 	"insn_invd: invd;ret\n\t"
781 );
782 extern void insn_hlt();
783 extern void insn_invlpg();
784 extern void insn_mwait();
785 extern void insn_rdpmc();
786 extern void insn_rdtsc();
787 extern void insn_monitor();
788 extern void insn_pause();
789 extern void insn_wbinvd();
790 extern void insn_cpuid();
791 extern void insn_invd();
792 
793 u32 cur_insn;
794 
795 struct insn_table {
796 	const char *name;
797 	u32 flag;
798 	void (*insn_func)();
799 	u32 type;
800 	u32 reason;
801 	ulong exit_qual;
802 	u32 insn_info;
803 	// Use FIELD_EXIT_QUAL and FIELD_INSN_INFO to efines
804 	// which field need to be tested, reason is always tested
805 	u32 test_field;
806 };
807 
808 /*
809  * Add more test cases of instruction intercept here. Elements in this
810  * table is:
811  *	name/control flag/insn function/type/exit reason/exit qulification/
812  *	instruction info/field to test
813  * The last field defines which fields (exit_qual and insn_info) need to be
814  * tested in exit handler. If set to 0, only "reason" is checked.
815  */
816 static struct insn_table insn_table[] = {
817 	// Flags for Primary Processor-Based VM-Execution Controls
818 	{"HLT",  CPU_HLT, insn_hlt, INSN_CPU0, 12, 0, 0, 0},
819 	{"INVLPG", CPU_INVLPG, insn_invlpg, INSN_CPU0, 14,
820 		0x12345678, 0, FIELD_EXIT_QUAL},
821 	{"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0},
822 	{"RDPMC", CPU_RDPMC, insn_rdpmc, INSN_CPU0, 15, 0, 0, 0},
823 	{"RDTSC", CPU_RDTSC, insn_rdtsc, INSN_CPU0, 16, 0, 0, 0},
824 	{"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0},
825 	{"PAUSE", CPU_PAUSE, insn_pause, INSN_CPU0, 40, 0, 0, 0},
826 	// Flags for Secondary Processor-Based VM-Execution Controls
827 	{"WBINVD", CPU_WBINVD, insn_wbinvd, INSN_CPU1, 54, 0, 0, 0},
828 	// Instructions always trap
829 	{"CPUID", 0, insn_cpuid, INSN_ALWAYS_TRAP, 10, 0, 0, 0},
830 	{"INVD", 0, insn_invd, INSN_ALWAYS_TRAP, 13, 0, 0, 0},
831 	// Instructions never trap
832 	{NULL},
833 };
834 
835 static void insn_intercept_init()
836 {
837 	u32 ctrl_cpu[2];
838 
839 	ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
840 	ctrl_cpu[0] |= CPU_HLT | CPU_INVLPG | CPU_MWAIT | CPU_RDPMC | CPU_RDTSC |
841 		CPU_MONITOR | CPU_PAUSE | CPU_SECONDARY;
842 	ctrl_cpu[0] &= ctrl_cpu_rev[0].clr;
843 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
844 	ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
845 	ctrl_cpu[1] |= CPU_WBINVD | CPU_RDRAND;
846 	ctrl_cpu[1] &= ctrl_cpu_rev[1].clr;
847 	vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]);
848 }
849 
850 static void insn_intercept_main()
851 {
852 	cur_insn = 0;
853 	while(insn_table[cur_insn].name != NULL) {
854 		set_stage(cur_insn);
855 		if ((insn_table[cur_insn].type == INSN_CPU0
856 			&& !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag))
857 			|| (insn_table[cur_insn].type == INSN_CPU1
858 			&& !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) {
859 			printf("\tCPU_CTRL1.CPU_%s is not supported.\n",
860 				insn_table[cur_insn].name);
861 			continue;
862 		}
863 		insn_table[cur_insn].insn_func();
864 		switch (insn_table[cur_insn].type) {
865 		case INSN_CPU0:
866 		case INSN_CPU1:
867 		case INSN_ALWAYS_TRAP:
868 			if (stage != cur_insn + 1)
869 				report(insn_table[cur_insn].name, 0);
870 			else
871 				report(insn_table[cur_insn].name, 1);
872 			break;
873 		case INSN_NEVER_TRAP:
874 			if (stage == cur_insn + 1)
875 				report(insn_table[cur_insn].name, 0);
876 			else
877 				report(insn_table[cur_insn].name, 1);
878 			break;
879 		}
880 		cur_insn ++;
881 	}
882 }
883 
884 static int insn_intercept_exit_handler()
885 {
886 	u64 guest_rip;
887 	u32 reason;
888 	ulong exit_qual;
889 	u32 insn_len;
890 	u32 insn_info;
891 	bool pass;
892 
893 	guest_rip = vmcs_read(GUEST_RIP);
894 	reason = vmcs_read(EXI_REASON) & 0xff;
895 	exit_qual = vmcs_read(EXI_QUALIFICATION);
896 	insn_len = vmcs_read(EXI_INST_LEN);
897 	insn_info = vmcs_read(EXI_INST_INFO);
898 	pass = (cur_insn == get_stage()) &&
899 			insn_table[cur_insn].reason == reason;
900 	if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL)
901 		pass = pass && insn_table[cur_insn].exit_qual == exit_qual;
902 	if (insn_table[cur_insn].test_field & FIELD_INSN_INFO)
903 		pass = pass && insn_table[cur_insn].insn_info == insn_info;
904 	if (pass)
905 		set_stage(stage + 1);
906 	vmcs_write(GUEST_RIP, guest_rip + insn_len);
907 	return VMX_TEST_RESUME;
908 }
909 
910 
911 static int setup_ept()
912 {
913 	int support_2m;
914 	unsigned long end_of_memory;
915 
916 	if (!(ept_vpid.val & EPT_CAP_UC) &&
917 			!(ept_vpid.val & EPT_CAP_WB)) {
918 		printf("\tEPT paging-structure memory type "
919 				"UC&WB are not supported\n");
920 		return 1;
921 	}
922 	if (ept_vpid.val & EPT_CAP_UC)
923 		eptp = EPT_MEM_TYPE_UC;
924 	else
925 		eptp = EPT_MEM_TYPE_WB;
926 	if (!(ept_vpid.val & EPT_CAP_PWL4)) {
927 		printf("\tPWL4 is not supported\n");
928 		return 1;
929 	}
930 	eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT);
931 	pml4 = alloc_page();
932 	memset(pml4, 0, PAGE_SIZE);
933 	eptp |= virt_to_phys(pml4);
934 	vmcs_write(EPTP, eptp);
935 	support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE);
936 	end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
937 	if (end_of_memory < (1ul << 32))
938 		end_of_memory = (1ul << 32);
939 	if (setup_ept_range(pml4, 0, end_of_memory,
940 			0, support_2m, EPT_WA | EPT_RA | EPT_EA)) {
941 		printf("\tSet ept tables failed.\n");
942 		return 1;
943 	}
944 	return 0;
945 }
946 
947 static void ept_init()
948 {
949 	unsigned long base_addr1, base_addr2;
950 	u32 ctrl_cpu[2];
951 
952 	init_fail = false;
953 	ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
954 	ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
955 	ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY)
956 		& ctrl_cpu_rev[0].clr;
957 	ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT)
958 		& ctrl_cpu_rev[1].clr;
959 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
960 	vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]);
961 	if (setup_ept())
962 		init_fail = true;
963 	data_page1 = alloc_page();
964 	data_page2 = alloc_page();
965 	memset(data_page1, 0x0, PAGE_SIZE);
966 	memset(data_page2, 0x0, PAGE_SIZE);
967 	*((u32 *)data_page1) = MAGIC_VAL_1;
968 	*((u32 *)data_page2) = MAGIC_VAL_2;
969 	base_addr1 = (unsigned long)data_page1 & PAGE_MASK_2M;
970 	base_addr2 = (unsigned long)data_page2 & PAGE_MASK_2M;
971 	if (setup_ept_range(pml4, base_addr1, base_addr1 + PAGE_SIZE_2M, 0, 0,
972 			    EPT_WA | EPT_RA | EPT_EA) ||
973 	    setup_ept_range(pml4, base_addr2, base_addr2 + PAGE_SIZE_2M, 0, 0,
974 			    EPT_WA | EPT_RA | EPT_EA))
975 		init_fail = true;
976 	install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2,
977 			EPT_RA | EPT_WA | EPT_EA);
978 }
979 
980 static void ept_main()
981 {
982 	if (init_fail)
983 		return;
984 	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)
985 		&& !(ctrl_cpu_rev[1].clr & CPU_EPT)) {
986 		printf("\tEPT is not supported");
987 		return;
988 	}
989 	set_stage(0);
990 	if (*((u32 *)data_page2) != MAGIC_VAL_1 ||
991 			*((u32 *)data_page1) != MAGIC_VAL_1)
992 		report("EPT basic framework - read", 0);
993 	else {
994 		*((u32 *)data_page2) = MAGIC_VAL_3;
995 		vmcall();
996 		if (get_stage() == 1) {
997 			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
998 					*((u32 *)data_page2) == MAGIC_VAL_2)
999 				report("EPT basic framework", 1);
1000 			else
1001 				report("EPT basic framework - remap", 1);
1002 		}
1003 	}
1004 	// Test EPT Misconfigurations
1005 	set_stage(1);
1006 	vmcall();
1007 	*((u32 *)data_page1) = MAGIC_VAL_1;
1008 	if (get_stage() != 2) {
1009 		report("EPT misconfigurations", 0);
1010 		goto t1;
1011 	}
1012 	set_stage(2);
1013 	vmcall();
1014 	*((u32 *)data_page1) = MAGIC_VAL_1;
1015 	if (get_stage() != 3) {
1016 		report("EPT misconfigurations", 0);
1017 		goto t1;
1018 	}
1019 	report("EPT misconfigurations", 1);
1020 t1:
1021 	// Test EPT violation
1022 	set_stage(3);
1023 	vmcall();
1024 	*((u32 *)data_page1) = MAGIC_VAL_1;
1025 	if (get_stage() == 4)
1026 		report("EPT violation - page permission", 1);
1027 	else
1028 		report("EPT violation - page permission", 0);
1029 	// Violation caused by EPT paging structure
1030 	set_stage(4);
1031 	vmcall();
1032 	*((u32 *)data_page1) = MAGIC_VAL_2;
1033 	if (get_stage() == 5)
1034 		report("EPT violation - paging structure", 1);
1035 	else
1036 		report("EPT violation - paging structure", 0);
1037 }
1038 
1039 static int ept_exit_handler()
1040 {
1041 	u64 guest_rip;
1042 	ulong reason;
1043 	u32 insn_len;
1044 	u32 exit_qual;
1045 	static unsigned long data_page1_pte, data_page1_pte_pte;
1046 
1047 	guest_rip = vmcs_read(GUEST_RIP);
1048 	reason = vmcs_read(EXI_REASON) & 0xff;
1049 	insn_len = vmcs_read(EXI_INST_LEN);
1050 	exit_qual = vmcs_read(EXI_QUALIFICATION);
1051 	switch (reason) {
1052 	case VMX_VMCALL:
1053 		switch (get_stage()) {
1054 		case 0:
1055 			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
1056 					*((u32 *)data_page2) == MAGIC_VAL_2) {
1057 				set_stage(get_stage() + 1);
1058 				install_ept(pml4, (unsigned long)data_page2,
1059 						(unsigned long)data_page2,
1060 						EPT_RA | EPT_WA | EPT_EA);
1061 			} else
1062 				report("EPT basic framework - write\n", 0);
1063 			break;
1064 		case 1:
1065 			install_ept(pml4, (unsigned long)data_page1,
1066  				(unsigned long)data_page1, EPT_WA);
1067 			invept(INVEPT_SINGLE, eptp);
1068 			break;
1069 		case 2:
1070 			install_ept(pml4, (unsigned long)data_page1,
1071  				(unsigned long)data_page1,
1072  				EPT_RA | EPT_WA | EPT_EA |
1073  				(2 << EPT_MEM_TYPE_SHIFT));
1074 			invept(INVEPT_SINGLE, eptp);
1075 			break;
1076 		case 3:
1077 			data_page1_pte = get_ept_pte(pml4,
1078 				(unsigned long)data_page1, 1);
1079 			set_ept_pte(pml4, (unsigned long)data_page1,
1080 				1, data_page1_pte & (~EPT_PRESENT));
1081 			invept(INVEPT_SINGLE, eptp);
1082 			break;
1083 		case 4:
1084 			data_page1_pte = get_ept_pte(pml4,
1085 				(unsigned long)data_page1, 2);
1086 			data_page1_pte &= PAGE_MASK;
1087 			data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2);
1088 			set_ept_pte(pml4, data_page1_pte, 2,
1089 				data_page1_pte_pte & (~EPT_PRESENT));
1090 			invept(INVEPT_SINGLE, eptp);
1091 			break;
1092 		// Should not reach here
1093 		default:
1094 			printf("ERROR - unexpected stage, %d.\n", get_stage());
1095 			print_vmexit_info();
1096 			return VMX_TEST_VMEXIT;
1097 		}
1098 		vmcs_write(GUEST_RIP, guest_rip + insn_len);
1099 		return VMX_TEST_RESUME;
1100 	case VMX_EPT_MISCONFIG:
1101 		switch (get_stage()) {
1102 		case 1:
1103 		case 2:
1104 			set_stage(get_stage() + 1);
1105 			install_ept(pml4, (unsigned long)data_page1,
1106  				(unsigned long)data_page1,
1107  				EPT_RA | EPT_WA | EPT_EA);
1108 			invept(INVEPT_SINGLE, eptp);
1109 			break;
1110 		// Should not reach here
1111 		default:
1112 			printf("ERROR - unexpected stage, %d.\n", get_stage());
1113 			print_vmexit_info();
1114 			return VMX_TEST_VMEXIT;
1115 		}
1116 		return VMX_TEST_RESUME;
1117 	case VMX_EPT_VIOLATION:
1118 		switch(get_stage()) {
1119 		case 3:
1120 			if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD |
1121 					EPT_VLT_PADDR))
1122 				set_stage(get_stage() + 1);
1123 			set_ept_pte(pml4, (unsigned long)data_page1,
1124 				1, data_page1_pte | (EPT_PRESENT));
1125 			invept(INVEPT_SINGLE, eptp);
1126 			break;
1127 		case 4:
1128 			if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD))
1129 				set_stage(get_stage() + 1);
1130 			set_ept_pte(pml4, data_page1_pte, 2,
1131 				data_page1_pte_pte | (EPT_PRESENT));
1132 			invept(INVEPT_SINGLE, eptp);
1133 			break;
1134 		default:
1135 			// Should not reach here
1136 			printf("ERROR : unexpected stage, %d\n", get_stage());
1137 			print_vmexit_info();
1138 			return VMX_TEST_VMEXIT;
1139 		}
1140 		return VMX_TEST_RESUME;
1141 	default:
1142 		printf("Unknown exit reason, %d\n", reason);
1143 		print_vmexit_info();
1144 	}
1145 	return VMX_TEST_VMEXIT;
1146 }
1147 
1148 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs
1149    basic_* just implement some basic functions */
1150 struct vmx_test vmx_tests[] = {
1151 	{ "null", basic_init, basic_guest_main, basic_exit_handler,
1152 		basic_syscall_handler, {0} },
1153 	{ "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
1154 		basic_syscall_handler, {0} },
1155 	{ "preemption timer", preemption_timer_init, preemption_timer_main,
1156 		preemption_timer_exit_handler, basic_syscall_handler, {0} },
1157 	{ "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main,
1158 		test_ctrl_pat_exit_handler, basic_syscall_handler, {0} },
1159 	{ "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main,
1160 		test_ctrl_efer_exit_handler, basic_syscall_handler, {0} },
1161 	{ "CR shadowing", basic_init, cr_shadowing_main,
1162 		cr_shadowing_exit_handler, basic_syscall_handler, {0} },
1163 	{ "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler,
1164 		basic_syscall_handler, {0} },
1165 	{ "instruction intercept", insn_intercept_init, insn_intercept_main,
1166 		insn_intercept_exit_handler, basic_syscall_handler, {0} },
1167 	{ "EPT framework", ept_init, ept_main, ept_exit_handler,
1168 		basic_syscall_handler, {0} },
1169 	{ NULL, NULL, NULL, NULL, NULL, {0} },
1170 };
1171