xref: /kvm-unit-tests/x86/hypercall.c (revision 22abdd3999b7c17ba976d31706852b92fb45cd5a)
1 #include "libcflat.h"
2 #include "vm.h"
3 #include "desc.h"
4 #include "alloc_page.h"
5 #include "fwcfg.h"
6 
7 #define KVM_HYPERCALL_INTEL ".byte 0x0f,0x01,0xc1"
8 #define KVM_HYPERCALL_AMD ".byte 0x0f,0x01,0xd9"
9 
kvm_hypercall0_intel(unsigned int nr)10 static inline long kvm_hypercall0_intel(unsigned int nr)
11 {
12 	long ret;
13 	asm volatile(KVM_HYPERCALL_INTEL
14 		     : "=a"(ret)
15 		     : "a"(nr));
16 	return ret;
17 }
18 
kvm_hypercall0_amd(unsigned int nr)19 static inline long kvm_hypercall0_amd(unsigned int nr)
20 {
21 	long ret;
22 	asm volatile(KVM_HYPERCALL_AMD
23 		     : "=a"(ret)
24 		     : "a"(nr));
25 	return ret;
26 }
27 
28 
29 volatile unsigned long test_rip;
30 #ifdef __x86_64__
31 extern void gp_tss(void);
32 asm ("gp_tss: \n\t"
33 	"add $8, %rsp\n\t"            // discard error code
34 	"popq test_rip(%rip)\n\t"     // pop return address
35 	"pushq %rsi\n\t"              // new return address
36 	"iretq\n\t"
37 	"jmp gp_tss\n\t"
38     );
39 
40 static inline int
test_edge(void)41 test_edge(void)
42 {
43 	test_rip = 0;
44 	asm volatile ("movq $-1, %%rax\n\t"			// prepare for vmcall
45 		      "leaq 1f(%%rip), %%rsi\n\t"		// save return address for gp_tss
46 		      "movabsq $0x7ffffffffffd, %%rbx\n\t"
47 		      "jmp *%%rbx; 1:" : : : "rax", "rbx", "rsi");
48 	printf("Return from int 13, test_rip = %lx\n", test_rip);
49 	return test_rip == (1ul << 47);
50 }
51 #endif
52 
main(int ac,char ** av)53 int main(int ac, char **av)
54 {
55 	bool test_vmcall = !no_test_device || is_intel();
56 	bool test_vmmcall = !no_test_device || !is_intel();
57 
58 	if (test_vmcall) {
59 		kvm_hypercall0_intel(-1u);
60 		printf("Hypercall via VMCALL: OK\n");
61 	}
62 
63 	if (test_vmmcall) {
64 		kvm_hypercall0_amd(-1u);
65 		printf("Hypercall via VMMCALL: OK\n");
66 	}
67 
68 #ifdef __x86_64__
69 	setup_vm();
70 	setup_alt_stack();
71 	set_intr_alt_stack(13, gp_tss);
72 
73 	u8 *data1 = alloc_page();
74 	u8 *topmost = (void *) ((1ul << 47) - PAGE_SIZE);
75 
76 	install_pte(phys_to_virt(read_cr3()), 1, topmost,
77 		    virt_to_phys(data1) | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0);
78 	memset(topmost, 0xcc, PAGE_SIZE);
79 	topmost[4093] = 0x0f;
80 	topmost[4094] = 0x01;
81 	topmost[4095] = 0xc1;
82 
83 	if (test_vmcall) {
84 		report(test_edge(),
85 		       "VMCALL on edge of canonical address space (intel)");
86 	}
87 
88 	topmost[4095] = 0xd9;
89 
90 	if (test_vmmcall) {
91 		report(test_edge(),
92 		       "VMMCALL on edge of canonical address space (AMD)");
93 	}
94 #endif
95 
96 	return report_summary();
97 }
98