1*ad879127SKrish Sadhukhan /* 2*ad879127SKrish Sadhukhan * Framework for testing nested virtualization 3*ad879127SKrish Sadhukhan */ 4*ad879127SKrish Sadhukhan 57d36db35SAvi Kivity #include "svm.h" 67d36db35SAvi Kivity #include "libcflat.h" 77d36db35SAvi Kivity #include "processor.h" 8b46094b4SPaolo Bonzini #include "desc.h" 97d36db35SAvi Kivity #include "msr.h" 107d36db35SAvi Kivity #include "vm.h" 117d36db35SAvi Kivity #include "smp.h" 127d36db35SAvi Kivity #include "types.h" 135aca024eSPaolo Bonzini #include "alloc_page.h" 14306bb7dbSCathy Avery #include "isr.h" 15306bb7dbSCathy Avery #include "apic.h" 167d36db35SAvi Kivity 171535bf0fSJoerg Roedel /* for the nested page table*/ 181535bf0fSJoerg Roedel u64 *pte[2048]; 19*ad879127SKrish Sadhukhan u64 *pde[4]; 20*ad879127SKrish Sadhukhan u64 *pdpe; 21*ad879127SKrish Sadhukhan u64 *pml4e; 221535bf0fSJoerg Roedel 23*ad879127SKrish Sadhukhan u64 *npt_get_pte(u64 address) 241535bf0fSJoerg Roedel { 25*ad879127SKrish Sadhukhan int i1, i2; 26*ad879127SKrish Sadhukhan 27*ad879127SKrish Sadhukhan address >>= 12; 28*ad879127SKrish Sadhukhan i1 = (address >> 9) & 0x7ff; 29*ad879127SKrish Sadhukhan i2 = address & 0x1ff; 30*ad879127SKrish Sadhukhan 31*ad879127SKrish Sadhukhan return &pte[i1][i2]; 321535bf0fSJoerg Roedel } 331535bf0fSJoerg Roedel 34*ad879127SKrish Sadhukhan u64 *npt_get_pde(u64 address) 35f6a2ca45SPaolo Bonzini { 36f6a2ca45SPaolo Bonzini int i1, i2; 37f6a2ca45SPaolo Bonzini 38f6a2ca45SPaolo Bonzini address >>= 21; 39f6a2ca45SPaolo Bonzini i1 = (address >> 9) & 0x3; 40f6a2ca45SPaolo Bonzini i2 = address & 0x1ff; 41f6a2ca45SPaolo Bonzini 42f6a2ca45SPaolo Bonzini return &pde[i1][i2]; 43f6a2ca45SPaolo Bonzini } 44f6a2ca45SPaolo Bonzini 45*ad879127SKrish Sadhukhan u64 *npt_get_pdpe(void) 468594b943SJoerg Roedel { 47*ad879127SKrish Sadhukhan return pdpe; 48*ad879127SKrish Sadhukhan } 498594b943SJoerg Roedel 50*ad879127SKrish Sadhukhan bool smp_supported(void) 51*ad879127SKrish Sadhukhan { 52*ad879127SKrish Sadhukhan return cpu_count() > 1; 53*ad879127SKrish Sadhukhan } 548594b943SJoerg Roedel 55*ad879127SKrish Sadhukhan bool default_supported(void) 56*ad879127SKrish Sadhukhan { 57*ad879127SKrish Sadhukhan return true; 58*ad879127SKrish Sadhukhan } 59*ad879127SKrish Sadhukhan 60*ad879127SKrish Sadhukhan void default_prepare(struct svm_test *test) 61*ad879127SKrish Sadhukhan { 62*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 63*ad879127SKrish Sadhukhan } 64*ad879127SKrish Sadhukhan 65*ad879127SKrish Sadhukhan void default_prepare_gif_clear(struct svm_test *test) 66*ad879127SKrish Sadhukhan { 67*ad879127SKrish Sadhukhan } 68*ad879127SKrish Sadhukhan 69*ad879127SKrish Sadhukhan bool default_finished(struct svm_test *test) 70*ad879127SKrish Sadhukhan { 71*ad879127SKrish Sadhukhan return true; /* one vmexit */ 72*ad879127SKrish Sadhukhan } 73*ad879127SKrish Sadhukhan 74*ad879127SKrish Sadhukhan bool npt_supported(void) 75*ad879127SKrish Sadhukhan { 76*ad879127SKrish Sadhukhan return this_cpu_has(X86_FEATURE_NPT); 77*ad879127SKrish Sadhukhan } 78*ad879127SKrish Sadhukhan 79*ad879127SKrish Sadhukhan int get_test_stage(struct svm_test *test) 80*ad879127SKrish Sadhukhan { 81*ad879127SKrish Sadhukhan barrier(); 82*ad879127SKrish Sadhukhan return test->scratch; 83*ad879127SKrish Sadhukhan } 84*ad879127SKrish Sadhukhan 85*ad879127SKrish Sadhukhan void set_test_stage(struct svm_test *test, int s) 86*ad879127SKrish Sadhukhan { 87*ad879127SKrish Sadhukhan barrier(); 88*ad879127SKrish Sadhukhan test->scratch = s; 89*ad879127SKrish Sadhukhan barrier(); 90*ad879127SKrish Sadhukhan } 91*ad879127SKrish Sadhukhan 92*ad879127SKrish Sadhukhan void inc_test_stage(struct svm_test *test) 93*ad879127SKrish Sadhukhan { 94*ad879127SKrish Sadhukhan barrier(); 95*ad879127SKrish Sadhukhan test->scratch++; 96*ad879127SKrish Sadhukhan barrier(); 978594b943SJoerg Roedel } 988594b943SJoerg Roedel 997d36db35SAvi Kivity static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, 1007d36db35SAvi Kivity u64 base, u32 limit, u32 attr) 1017d36db35SAvi Kivity { 1027d36db35SAvi Kivity seg->selector = selector; 1037d36db35SAvi Kivity seg->attrib = attr; 1047d36db35SAvi Kivity seg->limit = limit; 1057d36db35SAvi Kivity seg->base = base; 1067d36db35SAvi Kivity } 1077d36db35SAvi Kivity 108*ad879127SKrish Sadhukhan inline void vmmcall(void) 109*ad879127SKrish Sadhukhan { 110*ad879127SKrish Sadhukhan asm volatile ("vmmcall" : : : "memory"); 111*ad879127SKrish Sadhukhan } 112*ad879127SKrish Sadhukhan 113*ad879127SKrish Sadhukhan static void test_thunk(struct svm_test *test) 114*ad879127SKrish Sadhukhan { 115*ad879127SKrish Sadhukhan test->guest_func(test); 116*ad879127SKrish Sadhukhan vmmcall(); 117*ad879127SKrish Sadhukhan } 118*ad879127SKrish Sadhukhan 119*ad879127SKrish Sadhukhan u8 *io_bitmap; 120*ad879127SKrish Sadhukhan u8 io_bitmap_area[16384]; 121*ad879127SKrish Sadhukhan 122*ad879127SKrish Sadhukhan u8 *msr_bitmap; 123*ad879127SKrish Sadhukhan u8 msr_bitmap_area[MSR_BITMAP_SIZE + PAGE_SIZE]; 124*ad879127SKrish Sadhukhan 125*ad879127SKrish Sadhukhan void vmcb_ident(struct vmcb *vmcb) 1267d36db35SAvi Kivity { 1277d36db35SAvi Kivity u64 vmcb_phys = virt_to_phys(vmcb); 1287d36db35SAvi Kivity struct vmcb_save_area *save = &vmcb->save; 1297d36db35SAvi Kivity struct vmcb_control_area *ctrl = &vmcb->control; 1307d36db35SAvi Kivity u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 1317d36db35SAvi Kivity | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; 1327d36db35SAvi Kivity u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 1337d36db35SAvi Kivity | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; 1347d36db35SAvi Kivity struct descriptor_table_ptr desc_table_ptr; 1357d36db35SAvi Kivity 1367d36db35SAvi Kivity memset(vmcb, 0, sizeof(*vmcb)); 1372c6589bcSPeter Shier asm volatile ("vmsave %0" : : "a"(vmcb_phys) : "memory"); 1387d36db35SAvi Kivity vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr); 1397d36db35SAvi Kivity vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr); 1407d36db35SAvi Kivity vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr); 1417d36db35SAvi Kivity vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr); 1427d36db35SAvi Kivity sgdt(&desc_table_ptr); 1437d36db35SAvi Kivity vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 1447d36db35SAvi Kivity sidt(&desc_table_ptr); 1457d36db35SAvi Kivity vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 1467d36db35SAvi Kivity ctrl->asid = 1; 1477d36db35SAvi Kivity save->cpl = 0; 1487d36db35SAvi Kivity save->efer = rdmsr(MSR_EFER); 1497d36db35SAvi Kivity save->cr4 = read_cr4(); 1507d36db35SAvi Kivity save->cr3 = read_cr3(); 1517d36db35SAvi Kivity save->cr0 = read_cr0(); 1527d36db35SAvi Kivity save->dr7 = read_dr7(); 1537d36db35SAvi Kivity save->dr6 = read_dr6(); 1547d36db35SAvi Kivity save->cr2 = read_cr2(); 1557d36db35SAvi Kivity save->g_pat = rdmsr(MSR_IA32_CR_PAT); 1567d36db35SAvi Kivity save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); 1577d36db35SAvi Kivity ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL); 1583d46571bSPaolo Bonzini ctrl->iopm_base_pa = virt_to_phys(io_bitmap); 15906a8c023STambe, William ctrl->msrpm_base_pa = virt_to_phys(msr_bitmap); 1601535bf0fSJoerg Roedel 1611535bf0fSJoerg Roedel if (npt_supported()) { 1621535bf0fSJoerg Roedel ctrl->nested_ctl = 1; 1631535bf0fSJoerg Roedel ctrl->nested_cr3 = (u64)pml4e; 1641535bf0fSJoerg Roedel } 1657d36db35SAvi Kivity } 1667d36db35SAvi Kivity 167a43baea0SPaolo Bonzini struct regs regs; 168a43baea0SPaolo Bonzini 169*ad879127SKrish Sadhukhan struct regs get_regs(void) 170*ad879127SKrish Sadhukhan { 171*ad879127SKrish Sadhukhan return regs; 172*ad879127SKrish Sadhukhan } 173*ad879127SKrish Sadhukhan 174a43baea0SPaolo Bonzini // rax handled specially below 175a43baea0SPaolo Bonzini 176a43baea0SPaolo Bonzini #define SAVE_GPR_C \ 177a43baea0SPaolo Bonzini "xchg %%rbx, regs+0x8\n\t" \ 178a43baea0SPaolo Bonzini "xchg %%rcx, regs+0x10\n\t" \ 179a43baea0SPaolo Bonzini "xchg %%rdx, regs+0x18\n\t" \ 180a43baea0SPaolo Bonzini "xchg %%rbp, regs+0x28\n\t" \ 181a43baea0SPaolo Bonzini "xchg %%rsi, regs+0x30\n\t" \ 182a43baea0SPaolo Bonzini "xchg %%rdi, regs+0x38\n\t" \ 183a43baea0SPaolo Bonzini "xchg %%r8, regs+0x40\n\t" \ 184a43baea0SPaolo Bonzini "xchg %%r9, regs+0x48\n\t" \ 185a43baea0SPaolo Bonzini "xchg %%r10, regs+0x50\n\t" \ 186a43baea0SPaolo Bonzini "xchg %%r11, regs+0x58\n\t" \ 187a43baea0SPaolo Bonzini "xchg %%r12, regs+0x60\n\t" \ 188a43baea0SPaolo Bonzini "xchg %%r13, regs+0x68\n\t" \ 189a43baea0SPaolo Bonzini "xchg %%r14, regs+0x70\n\t" \ 190a43baea0SPaolo Bonzini "xchg %%r15, regs+0x78\n\t" 191a43baea0SPaolo Bonzini 192a43baea0SPaolo Bonzini #define LOAD_GPR_C SAVE_GPR_C 193a43baea0SPaolo Bonzini 194*ad879127SKrish Sadhukhan static void test_run(struct svm_test *test, struct vmcb *vmcb) 1957d36db35SAvi Kivity { 1967d36db35SAvi Kivity u64 vmcb_phys = virt_to_phys(vmcb); 1977d36db35SAvi Kivity u64 guest_stack[10000]; 1987d36db35SAvi Kivity 1991500aca4SPaolo Bonzini irq_disable(); 2007d36db35SAvi Kivity test->vmcb = vmcb; 2017d36db35SAvi Kivity test->prepare(test); 2027d36db35SAvi Kivity vmcb->save.rip = (ulong)test_thunk; 2037d36db35SAvi Kivity vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); 204a43baea0SPaolo Bonzini regs.rdi = (ulong)test; 2057d36db35SAvi Kivity do { 206*ad879127SKrish Sadhukhan struct svm_test *the_test = test; 207e7bce343SPaolo Bonzini u64 the_vmcb = vmcb_phys; 2087d36db35SAvi Kivity asm volatile ( 2092c6589bcSPeter Shier "clgi;\n\t" // semi-colon needed for LLVM compatibility 2102e7dd780SCathy Avery "sti \n\t" 211e7bce343SPaolo Bonzini "call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t" 212e7bce343SPaolo Bonzini "mov %[vmcb_phys], %%rax \n\t" 213e7bce343SPaolo Bonzini "vmload %%rax\n\t" 214a43baea0SPaolo Bonzini "mov regs+0x80, %%r15\n\t" // rflags 215e7bce343SPaolo Bonzini "mov %%r15, 0x170(%%rax)\n\t" 216a43baea0SPaolo Bonzini "mov regs, %%r15\n\t" // rax 217e7bce343SPaolo Bonzini "mov %%r15, 0x1f8(%%rax)\n\t" 218a43baea0SPaolo Bonzini LOAD_GPR_C 219e7bce343SPaolo Bonzini "vmrun %%rax\n\t" 220a43baea0SPaolo Bonzini SAVE_GPR_C 221e7bce343SPaolo Bonzini "mov 0x170(%%rax), %%r15\n\t" // rflags 222a43baea0SPaolo Bonzini "mov %%r15, regs+0x80\n\t" 223e7bce343SPaolo Bonzini "mov 0x1f8(%%rax), %%r15\n\t" // rax 224a43baea0SPaolo Bonzini "mov %%r15, regs\n\t" 225e7bce343SPaolo Bonzini "vmsave %%rax\n\t" 2262e7dd780SCathy Avery "cli \n\t" 2277d36db35SAvi Kivity "stgi" 228e7bce343SPaolo Bonzini : // inputs clobbered by the guest: 229e7bce343SPaolo Bonzini "+D" (the_test), // first argument register 230e7bce343SPaolo Bonzini "+b" (the_vmcb) // callee save register! 231e7bce343SPaolo Bonzini : [test] "0" (the_test), 232e7bce343SPaolo Bonzini [vmcb_phys] "1"(the_vmcb), 233*ad879127SKrish Sadhukhan [PREPARE_GIF_CLEAR] "i" (offsetof(struct svm_test, prepare_gif_clear)) 234e7bce343SPaolo Bonzini : "rax", "rcx", "rdx", "rsi", 2357d36db35SAvi Kivity "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15", 2367d36db35SAvi Kivity "memory"); 2377d36db35SAvi Kivity ++test->exits; 2387d36db35SAvi Kivity } while (!test->finished(test)); 2391500aca4SPaolo Bonzini irq_enable(); 2407d36db35SAvi Kivity 241a299895bSThomas Huth report(test->succeeded(test), "%s", test->name); 2427d36db35SAvi Kivity } 2437d36db35SAvi Kivity 244*ad879127SKrish Sadhukhan static void setup_svm(void) 245095274b4SPrasad Joshi { 246*ad879127SKrish Sadhukhan void *hsave = alloc_page(); 247*ad879127SKrish Sadhukhan u64 *page, address; 248*ad879127SKrish Sadhukhan int i,j; 249095274b4SPrasad Joshi 250*ad879127SKrish Sadhukhan wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); 251*ad879127SKrish Sadhukhan wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); 252*ad879127SKrish Sadhukhan wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX); 2537d36db35SAvi Kivity 254*ad879127SKrish Sadhukhan io_bitmap = (void *) (((ulong)io_bitmap_area + 4095) & ~4095); 2557d36db35SAvi Kivity 256*ad879127SKrish Sadhukhan msr_bitmap = (void *) ALIGN((ulong)msr_bitmap_area, PAGE_SIZE); 257e7bce343SPaolo Bonzini 258*ad879127SKrish Sadhukhan if (!npt_supported()) 259bcd9774aSPaolo Bonzini return; 260bcd9774aSPaolo Bonzini 261*ad879127SKrish Sadhukhan printf("NPT detected - running all tests with NPT enabled\n"); 2624c8eb156SJoerg Roedel 2634c8eb156SJoerg Roedel /* 264*ad879127SKrish Sadhukhan * Nested paging supported - Build a nested page table 265*ad879127SKrish Sadhukhan * Build the page-table bottom-up and map everything with 4k 266*ad879127SKrish Sadhukhan * pages to get enough granularity for the NPT unit-tests. 2674c8eb156SJoerg Roedel */ 268*ad879127SKrish Sadhukhan 269*ad879127SKrish Sadhukhan address = 0; 270*ad879127SKrish Sadhukhan 271*ad879127SKrish Sadhukhan /* PTE level */ 272*ad879127SKrish Sadhukhan for (i = 0; i < 2048; ++i) { 273*ad879127SKrish Sadhukhan page = alloc_page(); 274*ad879127SKrish Sadhukhan 275*ad879127SKrish Sadhukhan for (j = 0; j < 512; ++j, address += 4096) 276*ad879127SKrish Sadhukhan page[j] = address | 0x067ULL; 277*ad879127SKrish Sadhukhan 278*ad879127SKrish Sadhukhan pte[i] = page; 2794c8eb156SJoerg Roedel } 2804c8eb156SJoerg Roedel 281*ad879127SKrish Sadhukhan /* PDE level */ 282*ad879127SKrish Sadhukhan for (i = 0; i < 4; ++i) { 283*ad879127SKrish Sadhukhan page = alloc_page(); 284*ad879127SKrish Sadhukhan 285*ad879127SKrish Sadhukhan for (j = 0; j < 512; ++j) 286*ad879127SKrish Sadhukhan page[j] = (u64)pte[(i * 512) + j] | 0x027ULL; 287*ad879127SKrish Sadhukhan 288*ad879127SKrish Sadhukhan pde[i] = page; 2894c8eb156SJoerg Roedel } 2904c8eb156SJoerg Roedel 291*ad879127SKrish Sadhukhan /* PDPe level */ 292*ad879127SKrish Sadhukhan pdpe = alloc_page(); 293*ad879127SKrish Sadhukhan for (i = 0; i < 4; ++i) 294*ad879127SKrish Sadhukhan pdpe[i] = ((u64)(pde[i])) | 0x27; 2958594b943SJoerg Roedel 296*ad879127SKrish Sadhukhan /* PML4e level */ 297*ad879127SKrish Sadhukhan pml4e = alloc_page(); 298*ad879127SKrish Sadhukhan pml4e[0] = ((u64)pdpe) | 0x27; 2998594b943SJoerg Roedel } 3008594b943SJoerg Roedel 301*ad879127SKrish Sadhukhan extern struct svm_test svm_tests[]; 3027d36db35SAvi Kivity 3037d36db35SAvi Kivity int main(int ac, char **av) 3047d36db35SAvi Kivity { 305*ad879127SKrish Sadhukhan int i = 0; 3067d36db35SAvi Kivity struct vmcb *vmcb; 3077d36db35SAvi Kivity 3087d36db35SAvi Kivity setup_vm(); 3097d36db35SAvi Kivity smp_init(); 3107d36db35SAvi Kivity 311badc98caSKrish Sadhukhan if (!this_cpu_has(X86_FEATURE_SVM)) { 3127d36db35SAvi Kivity printf("SVM not availble\n"); 31332b9603cSRadim Krčmář return report_summary(); 3147d36db35SAvi Kivity } 3157d36db35SAvi Kivity 3167d36db35SAvi Kivity setup_svm(); 3177d36db35SAvi Kivity 3187d36db35SAvi Kivity vmcb = alloc_page(); 3197d36db35SAvi Kivity 320*ad879127SKrish Sadhukhan for (; svm_tests[i].name != NULL; i++) { 321*ad879127SKrish Sadhukhan if (!svm_tests[i].supported()) 3227d36db35SAvi Kivity continue; 323*ad879127SKrish Sadhukhan test_run(&svm_tests[i], vmcb); 3247d36db35SAvi Kivity } 3257d36db35SAvi Kivity 326a43ed2acSAndrew Jones return report_summary(); 3277d36db35SAvi Kivity } 328