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