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