1 /* 2 * Framework for testing nested virtualization 3 */ 4 5 #include "svm.h" 6 #include "libcflat.h" 7 #include "processor.h" 8 #include "desc.h" 9 #include "msr.h" 10 #include "vm.h" 11 #include "smp.h" 12 #include "types.h" 13 #include "alloc_page.h" 14 #include "isr.h" 15 #include "apic.h" 16 #include "vmalloc.h" 17 18 /* for the nested page table*/ 19 u64 *pte[2048]; 20 u64 *pde[4]; 21 u64 *pdpe; 22 u64 *pml4e; 23 24 struct vmcb *vmcb; 25 26 u64 *npt_get_pte(u64 address) 27 { 28 int i1, i2; 29 30 address >>= 12; 31 i1 = (address >> 9) & 0x7ff; 32 i2 = address & 0x1ff; 33 34 return &pte[i1][i2]; 35 } 36 37 u64 *npt_get_pde(u64 address) 38 { 39 int i1, i2; 40 41 address >>= 21; 42 i1 = (address >> 9) & 0x3; 43 i2 = address & 0x1ff; 44 45 return &pde[i1][i2]; 46 } 47 48 u64 *npt_get_pdpe(void) 49 { 50 return pdpe; 51 } 52 53 u64 *npt_get_pml4e(void) 54 { 55 return pml4e; 56 } 57 58 bool smp_supported(void) 59 { 60 return cpu_count() > 1; 61 } 62 63 bool default_supported(void) 64 { 65 return true; 66 } 67 68 bool vgif_supported(void) 69 { 70 return this_cpu_has(X86_FEATURE_VGIF); 71 } 72 73 bool lbrv_supported(void) 74 { 75 return this_cpu_has(X86_FEATURE_LBRV); 76 } 77 78 void default_prepare(struct svm_test *test) 79 { 80 vmcb_ident(vmcb); 81 } 82 83 void default_prepare_gif_clear(struct svm_test *test) 84 { 85 } 86 87 bool default_finished(struct svm_test *test) 88 { 89 return true; /* one vmexit */ 90 } 91 92 bool npt_supported(void) 93 { 94 return this_cpu_has(X86_FEATURE_NPT); 95 } 96 97 int get_test_stage(struct svm_test *test) 98 { 99 barrier(); 100 return test->scratch; 101 } 102 103 void set_test_stage(struct svm_test *test, int s) 104 { 105 barrier(); 106 test->scratch = s; 107 barrier(); 108 } 109 110 void inc_test_stage(struct svm_test *test) 111 { 112 barrier(); 113 test->scratch++; 114 barrier(); 115 } 116 117 static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, 118 u64 base, u32 limit, u32 attr) 119 { 120 seg->selector = selector; 121 seg->attrib = attr; 122 seg->limit = limit; 123 seg->base = base; 124 } 125 126 inline void vmmcall(void) 127 { 128 asm volatile ("vmmcall" : : : "memory"); 129 } 130 131 static test_guest_func guest_main; 132 133 void test_set_guest(test_guest_func func) 134 { 135 guest_main = func; 136 } 137 138 static void test_thunk(struct svm_test *test) 139 { 140 guest_main(test); 141 vmmcall(); 142 } 143 144 u8 *io_bitmap; 145 u8 io_bitmap_area[16384]; 146 147 u8 *msr_bitmap; 148 u8 msr_bitmap_area[MSR_BITMAP_SIZE + PAGE_SIZE]; 149 150 void vmcb_ident(struct vmcb *vmcb) 151 { 152 u64 vmcb_phys = virt_to_phys(vmcb); 153 struct vmcb_save_area *save = &vmcb->save; 154 struct vmcb_control_area *ctrl = &vmcb->control; 155 u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 156 | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; 157 u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 158 | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; 159 struct descriptor_table_ptr desc_table_ptr; 160 161 memset(vmcb, 0, sizeof(*vmcb)); 162 asm volatile ("vmsave %0" : : "a"(vmcb_phys) : "memory"); 163 vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr); 164 vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr); 165 vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr); 166 vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr); 167 sgdt(&desc_table_ptr); 168 vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 169 sidt(&desc_table_ptr); 170 vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 171 ctrl->asid = 1; 172 save->cpl = 0; 173 save->efer = rdmsr(MSR_EFER); 174 save->cr4 = read_cr4(); 175 save->cr3 = read_cr3(); 176 save->cr0 = read_cr0(); 177 save->dr7 = read_dr7(); 178 save->dr6 = read_dr6(); 179 save->cr2 = read_cr2(); 180 save->g_pat = rdmsr(MSR_IA32_CR_PAT); 181 save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); 182 ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | 183 (1ULL << INTERCEPT_VMMCALL) | 184 (1ULL << INTERCEPT_SHUTDOWN); 185 ctrl->iopm_base_pa = virt_to_phys(io_bitmap); 186 ctrl->msrpm_base_pa = virt_to_phys(msr_bitmap); 187 188 if (npt_supported()) { 189 ctrl->nested_ctl = 1; 190 ctrl->nested_cr3 = (u64)pml4e; 191 ctrl->tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; 192 } 193 } 194 195 struct regs regs; 196 197 struct regs get_regs(void) 198 { 199 return regs; 200 } 201 202 // rax handled specially below 203 204 205 struct svm_test *v2_test; 206 207 208 u64 guest_stack[10000]; 209 210 int __svm_vmrun(u64 rip) 211 { 212 vmcb->save.rip = (ulong)rip; 213 vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); 214 regs.rdi = (ulong)v2_test; 215 216 asm volatile ( 217 ASM_PRE_VMRUN_CMD 218 "vmrun %%rax\n\t" \ 219 ASM_POST_VMRUN_CMD 220 : 221 : "a" (virt_to_phys(vmcb)) 222 : "memory", "r15"); 223 224 return (vmcb->control.exit_code); 225 } 226 227 int svm_vmrun(void) 228 { 229 return __svm_vmrun((u64)test_thunk); 230 } 231 232 extern u8 vmrun_rip; 233 234 static noinline void test_run(struct svm_test *test) 235 { 236 u64 vmcb_phys = virt_to_phys(vmcb); 237 238 irq_disable(); 239 vmcb_ident(vmcb); 240 241 test->prepare(test); 242 guest_main = test->guest_func; 243 vmcb->save.rip = (ulong)test_thunk; 244 vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); 245 regs.rdi = (ulong)test; 246 do { 247 struct svm_test *the_test = test; 248 u64 the_vmcb = vmcb_phys; 249 asm volatile ( 250 "clgi;\n\t" // semi-colon needed for LLVM compatibility 251 "sti \n\t" 252 "call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t" 253 "mov %[vmcb_phys], %%rax \n\t" 254 ASM_PRE_VMRUN_CMD 255 ".global vmrun_rip\n\t" \ 256 "vmrun_rip: vmrun %%rax\n\t" \ 257 ASM_POST_VMRUN_CMD 258 "cli \n\t" 259 "stgi" 260 : // inputs clobbered by the guest: 261 "=D" (the_test), // first argument register 262 "=b" (the_vmcb) // callee save register! 263 : [test] "0" (the_test), 264 [vmcb_phys] "1"(the_vmcb), 265 [PREPARE_GIF_CLEAR] "i" (offsetof(struct svm_test, prepare_gif_clear)) 266 : "rax", "rcx", "rdx", "rsi", 267 "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15", 268 "memory"); 269 ++test->exits; 270 } while (!test->finished(test)); 271 irq_enable(); 272 273 report(test->succeeded(test), "%s", test->name); 274 275 if (test->on_vcpu) 276 test->on_vcpu_done = true; 277 } 278 279 static void set_additional_vcpu_msr(void *msr_efer) 280 { 281 void *hsave = alloc_page(); 282 283 wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); 284 wrmsr(MSR_EFER, (ulong)msr_efer | EFER_SVME); 285 } 286 287 static void setup_svm(void) 288 { 289 void *hsave = alloc_page(); 290 u64 *page, address; 291 int i,j; 292 293 wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); 294 wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); 295 296 io_bitmap = (void *) ALIGN((ulong)io_bitmap_area, PAGE_SIZE); 297 298 msr_bitmap = (void *) ALIGN((ulong)msr_bitmap_area, PAGE_SIZE); 299 300 if (!npt_supported()) 301 return; 302 303 for (i = 1; i < cpu_count(); i++) 304 on_cpu(i, (void *)set_additional_vcpu_msr, (void *)rdmsr(MSR_EFER)); 305 306 printf("NPT detected - running all tests with NPT enabled\n"); 307 308 /* 309 * Nested paging supported - Build a nested page table 310 * Build the page-table bottom-up and map everything with 4k 311 * pages to get enough granularity for the NPT unit-tests. 312 */ 313 314 address = 0; 315 316 /* PTE level */ 317 for (i = 0; i < 2048; ++i) { 318 page = alloc_page(); 319 320 for (j = 0; j < 512; ++j, address += 4096) 321 page[j] = address | 0x067ULL; 322 323 pte[i] = page; 324 } 325 326 /* PDE level */ 327 for (i = 0; i < 4; ++i) { 328 page = alloc_page(); 329 330 for (j = 0; j < 512; ++j) 331 page[j] = (u64)pte[(i * 512) + j] | 0x027ULL; 332 333 pde[i] = page; 334 } 335 336 /* PDPe level */ 337 pdpe = alloc_page(); 338 for (i = 0; i < 4; ++i) 339 pdpe[i] = ((u64)(pde[i])) | 0x27; 340 341 /* PML4e level */ 342 pml4e = alloc_page(); 343 pml4e[0] = ((u64)pdpe) | 0x27; 344 } 345 346 int matched; 347 348 static bool 349 test_wanted(const char *name, char *filters[], int filter_count) 350 { 351 int i; 352 bool positive = false; 353 bool match = false; 354 char clean_name[strlen(name) + 1]; 355 char *c; 356 const char *n; 357 358 /* Replace spaces with underscores. */ 359 n = name; 360 c = &clean_name[0]; 361 do *c++ = (*n == ' ') ? '_' : *n; 362 while (*n++); 363 364 for (i = 0; i < filter_count; i++) { 365 const char *filter = filters[i]; 366 367 if (filter[0] == '-') { 368 if (simple_glob(clean_name, filter + 1)) 369 return false; 370 } else { 371 positive = true; 372 match |= simple_glob(clean_name, filter); 373 } 374 } 375 376 if (!positive || match) { 377 matched++; 378 return true; 379 } else { 380 return false; 381 } 382 } 383 384 int main(int ac, char **av) 385 { 386 /* Omit PT_USER_MASK to allow tested host.CR4.SMEP=1. */ 387 pteval_t opt_mask = 0; 388 int i = 0; 389 390 ac--; 391 av++; 392 393 __setup_vm(&opt_mask); 394 395 if (!this_cpu_has(X86_FEATURE_SVM)) { 396 printf("SVM not availble\n"); 397 return report_summary(); 398 } 399 400 setup_svm(); 401 402 vmcb = alloc_page(); 403 404 for (; svm_tests[i].name != NULL; i++) { 405 if (!test_wanted(svm_tests[i].name, av, ac)) 406 continue; 407 if (svm_tests[i].supported && !svm_tests[i].supported()) 408 continue; 409 if (svm_tests[i].v2 == NULL) { 410 if (svm_tests[i].on_vcpu) { 411 if (cpu_count() <= svm_tests[i].on_vcpu) 412 continue; 413 on_cpu_async(svm_tests[i].on_vcpu, (void *)test_run, &svm_tests[i]); 414 while (!svm_tests[i].on_vcpu_done) 415 cpu_relax(); 416 } 417 else 418 test_run(&svm_tests[i]); 419 } else { 420 vmcb_ident(vmcb); 421 v2_test = &(svm_tests[i]); 422 svm_tests[i].v2(); 423 } 424 } 425 426 if (!matched) 427 report(matched, "command line didn't match any tests!"); 428 429 return report_summary(); 430 } 431