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