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