1*ad879127SKrish Sadhukhan #include "svm.h" 2*ad879127SKrish Sadhukhan #include "libcflat.h" 3*ad879127SKrish Sadhukhan #include "processor.h" 4*ad879127SKrish Sadhukhan #include "desc.h" 5*ad879127SKrish Sadhukhan #include "msr.h" 6*ad879127SKrish Sadhukhan #include "vm.h" 7*ad879127SKrish Sadhukhan #include "smp.h" 8*ad879127SKrish Sadhukhan #include "types.h" 9*ad879127SKrish Sadhukhan #include "alloc_page.h" 10*ad879127SKrish Sadhukhan #include "isr.h" 11*ad879127SKrish Sadhukhan #include "apic.h" 12*ad879127SKrish Sadhukhan 13*ad879127SKrish Sadhukhan #define SVM_EXIT_MAX_DR_INTERCEPT 0x3f 14*ad879127SKrish Sadhukhan 15*ad879127SKrish Sadhukhan static void *scratch_page; 16*ad879127SKrish Sadhukhan 17*ad879127SKrish Sadhukhan #define LATENCY_RUNS 1000000 18*ad879127SKrish Sadhukhan 19*ad879127SKrish Sadhukhan u64 tsc_start; 20*ad879127SKrish Sadhukhan u64 tsc_end; 21*ad879127SKrish Sadhukhan 22*ad879127SKrish Sadhukhan u64 vmrun_sum, vmexit_sum; 23*ad879127SKrish Sadhukhan u64 vmsave_sum, vmload_sum; 24*ad879127SKrish Sadhukhan u64 stgi_sum, clgi_sum; 25*ad879127SKrish Sadhukhan u64 latvmrun_max; 26*ad879127SKrish Sadhukhan u64 latvmrun_min; 27*ad879127SKrish Sadhukhan u64 latvmexit_max; 28*ad879127SKrish Sadhukhan u64 latvmexit_min; 29*ad879127SKrish Sadhukhan u64 latvmload_max; 30*ad879127SKrish Sadhukhan u64 latvmload_min; 31*ad879127SKrish Sadhukhan u64 latvmsave_max; 32*ad879127SKrish Sadhukhan u64 latvmsave_min; 33*ad879127SKrish Sadhukhan u64 latstgi_max; 34*ad879127SKrish Sadhukhan u64 latstgi_min; 35*ad879127SKrish Sadhukhan u64 latclgi_max; 36*ad879127SKrish Sadhukhan u64 latclgi_min; 37*ad879127SKrish Sadhukhan u64 runs; 38*ad879127SKrish Sadhukhan 39*ad879127SKrish Sadhukhan static void null_test(struct svm_test *test) 40*ad879127SKrish Sadhukhan { 41*ad879127SKrish Sadhukhan } 42*ad879127SKrish Sadhukhan 43*ad879127SKrish Sadhukhan static bool null_check(struct svm_test *test) 44*ad879127SKrish Sadhukhan { 45*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_VMMCALL; 46*ad879127SKrish Sadhukhan } 47*ad879127SKrish Sadhukhan 48*ad879127SKrish Sadhukhan static void prepare_no_vmrun_int(struct svm_test *test) 49*ad879127SKrish Sadhukhan { 50*ad879127SKrish Sadhukhan test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN); 51*ad879127SKrish Sadhukhan } 52*ad879127SKrish Sadhukhan 53*ad879127SKrish Sadhukhan static bool check_no_vmrun_int(struct svm_test *test) 54*ad879127SKrish Sadhukhan { 55*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_ERR; 56*ad879127SKrish Sadhukhan } 57*ad879127SKrish Sadhukhan 58*ad879127SKrish Sadhukhan static void test_vmrun(struct svm_test *test) 59*ad879127SKrish Sadhukhan { 60*ad879127SKrish Sadhukhan asm volatile ("vmrun %0" : : "a"(virt_to_phys(test->vmcb))); 61*ad879127SKrish Sadhukhan } 62*ad879127SKrish Sadhukhan 63*ad879127SKrish Sadhukhan static bool check_vmrun(struct svm_test *test) 64*ad879127SKrish Sadhukhan { 65*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_VMRUN; 66*ad879127SKrish Sadhukhan } 67*ad879127SKrish Sadhukhan 68*ad879127SKrish Sadhukhan static void prepare_cr3_intercept(struct svm_test *test) 69*ad879127SKrish Sadhukhan { 70*ad879127SKrish Sadhukhan default_prepare(test); 71*ad879127SKrish Sadhukhan test->vmcb->control.intercept_cr_read |= 1 << 3; 72*ad879127SKrish Sadhukhan } 73*ad879127SKrish Sadhukhan 74*ad879127SKrish Sadhukhan static void test_cr3_intercept(struct svm_test *test) 75*ad879127SKrish Sadhukhan { 76*ad879127SKrish Sadhukhan asm volatile ("mov %%cr3, %0" : "=r"(test->scratch) : : "memory"); 77*ad879127SKrish Sadhukhan } 78*ad879127SKrish Sadhukhan 79*ad879127SKrish Sadhukhan static bool check_cr3_intercept(struct svm_test *test) 80*ad879127SKrish Sadhukhan { 81*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_READ_CR3; 82*ad879127SKrish Sadhukhan } 83*ad879127SKrish Sadhukhan 84*ad879127SKrish Sadhukhan static bool check_cr3_nointercept(struct svm_test *test) 85*ad879127SKrish Sadhukhan { 86*ad879127SKrish Sadhukhan return null_check(test) && test->scratch == read_cr3(); 87*ad879127SKrish Sadhukhan } 88*ad879127SKrish Sadhukhan 89*ad879127SKrish Sadhukhan static void corrupt_cr3_intercept_bypass(void *_test) 90*ad879127SKrish Sadhukhan { 91*ad879127SKrish Sadhukhan struct svm_test *test = _test; 92*ad879127SKrish Sadhukhan extern volatile u32 mmio_insn; 93*ad879127SKrish Sadhukhan 94*ad879127SKrish Sadhukhan while (!__sync_bool_compare_and_swap(&test->scratch, 1, 2)) 95*ad879127SKrish Sadhukhan pause(); 96*ad879127SKrish Sadhukhan pause(); 97*ad879127SKrish Sadhukhan pause(); 98*ad879127SKrish Sadhukhan pause(); 99*ad879127SKrish Sadhukhan mmio_insn = 0x90d8200f; // mov %cr3, %rax; nop 100*ad879127SKrish Sadhukhan } 101*ad879127SKrish Sadhukhan 102*ad879127SKrish Sadhukhan static void prepare_cr3_intercept_bypass(struct svm_test *test) 103*ad879127SKrish Sadhukhan { 104*ad879127SKrish Sadhukhan default_prepare(test); 105*ad879127SKrish Sadhukhan test->vmcb->control.intercept_cr_read |= 1 << 3; 106*ad879127SKrish Sadhukhan on_cpu_async(1, corrupt_cr3_intercept_bypass, test); 107*ad879127SKrish Sadhukhan } 108*ad879127SKrish Sadhukhan 109*ad879127SKrish Sadhukhan static void test_cr3_intercept_bypass(struct svm_test *test) 110*ad879127SKrish Sadhukhan { 111*ad879127SKrish Sadhukhan ulong a = 0xa0000; 112*ad879127SKrish Sadhukhan 113*ad879127SKrish Sadhukhan test->scratch = 1; 114*ad879127SKrish Sadhukhan while (test->scratch != 2) 115*ad879127SKrish Sadhukhan barrier(); 116*ad879127SKrish Sadhukhan 117*ad879127SKrish Sadhukhan asm volatile ("mmio_insn: mov %0, (%0); nop" 118*ad879127SKrish Sadhukhan : "+a"(a) : : "memory"); 119*ad879127SKrish Sadhukhan test->scratch = a; 120*ad879127SKrish Sadhukhan } 121*ad879127SKrish Sadhukhan 122*ad879127SKrish Sadhukhan static void prepare_dr_intercept(struct svm_test *test) 123*ad879127SKrish Sadhukhan { 124*ad879127SKrish Sadhukhan default_prepare(test); 125*ad879127SKrish Sadhukhan test->vmcb->control.intercept_dr_read = 0xff; 126*ad879127SKrish Sadhukhan test->vmcb->control.intercept_dr_write = 0xff; 127*ad879127SKrish Sadhukhan } 128*ad879127SKrish Sadhukhan 129*ad879127SKrish Sadhukhan static void test_dr_intercept(struct svm_test *test) 130*ad879127SKrish Sadhukhan { 131*ad879127SKrish Sadhukhan unsigned int i, failcnt = 0; 132*ad879127SKrish Sadhukhan 133*ad879127SKrish Sadhukhan /* Loop testing debug register reads */ 134*ad879127SKrish Sadhukhan for (i = 0; i < 8; i++) { 135*ad879127SKrish Sadhukhan 136*ad879127SKrish Sadhukhan switch (i) { 137*ad879127SKrish Sadhukhan case 0: 138*ad879127SKrish Sadhukhan asm volatile ("mov %%dr0, %0" : "=r"(test->scratch) : : "memory"); 139*ad879127SKrish Sadhukhan break; 140*ad879127SKrish Sadhukhan case 1: 141*ad879127SKrish Sadhukhan asm volatile ("mov %%dr1, %0" : "=r"(test->scratch) : : "memory"); 142*ad879127SKrish Sadhukhan break; 143*ad879127SKrish Sadhukhan case 2: 144*ad879127SKrish Sadhukhan asm volatile ("mov %%dr2, %0" : "=r"(test->scratch) : : "memory"); 145*ad879127SKrish Sadhukhan break; 146*ad879127SKrish Sadhukhan case 3: 147*ad879127SKrish Sadhukhan asm volatile ("mov %%dr3, %0" : "=r"(test->scratch) : : "memory"); 148*ad879127SKrish Sadhukhan break; 149*ad879127SKrish Sadhukhan case 4: 150*ad879127SKrish Sadhukhan asm volatile ("mov %%dr4, %0" : "=r"(test->scratch) : : "memory"); 151*ad879127SKrish Sadhukhan break; 152*ad879127SKrish Sadhukhan case 5: 153*ad879127SKrish Sadhukhan asm volatile ("mov %%dr5, %0" : "=r"(test->scratch) : : "memory"); 154*ad879127SKrish Sadhukhan break; 155*ad879127SKrish Sadhukhan case 6: 156*ad879127SKrish Sadhukhan asm volatile ("mov %%dr6, %0" : "=r"(test->scratch) : : "memory"); 157*ad879127SKrish Sadhukhan break; 158*ad879127SKrish Sadhukhan case 7: 159*ad879127SKrish Sadhukhan asm volatile ("mov %%dr7, %0" : "=r"(test->scratch) : : "memory"); 160*ad879127SKrish Sadhukhan break; 161*ad879127SKrish Sadhukhan } 162*ad879127SKrish Sadhukhan 163*ad879127SKrish Sadhukhan if (test->scratch != i) { 164*ad879127SKrish Sadhukhan report(false, "dr%u read intercept", i); 165*ad879127SKrish Sadhukhan failcnt++; 166*ad879127SKrish Sadhukhan } 167*ad879127SKrish Sadhukhan } 168*ad879127SKrish Sadhukhan 169*ad879127SKrish Sadhukhan /* Loop testing debug register writes */ 170*ad879127SKrish Sadhukhan for (i = 0; i < 8; i++) { 171*ad879127SKrish Sadhukhan 172*ad879127SKrish Sadhukhan switch (i) { 173*ad879127SKrish Sadhukhan case 0: 174*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr0" : : "r"(test->scratch) : "memory"); 175*ad879127SKrish Sadhukhan break; 176*ad879127SKrish Sadhukhan case 1: 177*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr1" : : "r"(test->scratch) : "memory"); 178*ad879127SKrish Sadhukhan break; 179*ad879127SKrish Sadhukhan case 2: 180*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr2" : : "r"(test->scratch) : "memory"); 181*ad879127SKrish Sadhukhan break; 182*ad879127SKrish Sadhukhan case 3: 183*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr3" : : "r"(test->scratch) : "memory"); 184*ad879127SKrish Sadhukhan break; 185*ad879127SKrish Sadhukhan case 4: 186*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr4" : : "r"(test->scratch) : "memory"); 187*ad879127SKrish Sadhukhan break; 188*ad879127SKrish Sadhukhan case 5: 189*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr5" : : "r"(test->scratch) : "memory"); 190*ad879127SKrish Sadhukhan break; 191*ad879127SKrish Sadhukhan case 6: 192*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr6" : : "r"(test->scratch) : "memory"); 193*ad879127SKrish Sadhukhan break; 194*ad879127SKrish Sadhukhan case 7: 195*ad879127SKrish Sadhukhan asm volatile ("mov %0, %%dr7" : : "r"(test->scratch) : "memory"); 196*ad879127SKrish Sadhukhan break; 197*ad879127SKrish Sadhukhan } 198*ad879127SKrish Sadhukhan 199*ad879127SKrish Sadhukhan if (test->scratch != i) { 200*ad879127SKrish Sadhukhan report(false, "dr%u write intercept", i); 201*ad879127SKrish Sadhukhan failcnt++; 202*ad879127SKrish Sadhukhan } 203*ad879127SKrish Sadhukhan } 204*ad879127SKrish Sadhukhan 205*ad879127SKrish Sadhukhan test->scratch = failcnt; 206*ad879127SKrish Sadhukhan } 207*ad879127SKrish Sadhukhan 208*ad879127SKrish Sadhukhan static bool dr_intercept_finished(struct svm_test *test) 209*ad879127SKrish Sadhukhan { 210*ad879127SKrish Sadhukhan ulong n = (test->vmcb->control.exit_code - SVM_EXIT_READ_DR0); 211*ad879127SKrish Sadhukhan 212*ad879127SKrish Sadhukhan /* Only expect DR intercepts */ 213*ad879127SKrish Sadhukhan if (n > (SVM_EXIT_MAX_DR_INTERCEPT - SVM_EXIT_READ_DR0)) 214*ad879127SKrish Sadhukhan return true; 215*ad879127SKrish Sadhukhan 216*ad879127SKrish Sadhukhan /* 217*ad879127SKrish Sadhukhan * Compute debug register number. 218*ad879127SKrish Sadhukhan * Per Appendix C "SVM Intercept Exit Codes" of AMD64 Architecture 219*ad879127SKrish Sadhukhan * Programmer's Manual Volume 2 - System Programming: 220*ad879127SKrish Sadhukhan * http://support.amd.com/TechDocs/24593.pdf 221*ad879127SKrish Sadhukhan * there are 16 VMEXIT codes each for DR read and write. 222*ad879127SKrish Sadhukhan */ 223*ad879127SKrish Sadhukhan test->scratch = (n % 16); 224*ad879127SKrish Sadhukhan 225*ad879127SKrish Sadhukhan /* Jump over MOV instruction */ 226*ad879127SKrish Sadhukhan test->vmcb->save.rip += 3; 227*ad879127SKrish Sadhukhan 228*ad879127SKrish Sadhukhan return false; 229*ad879127SKrish Sadhukhan } 230*ad879127SKrish Sadhukhan 231*ad879127SKrish Sadhukhan static bool check_dr_intercept(struct svm_test *test) 232*ad879127SKrish Sadhukhan { 233*ad879127SKrish Sadhukhan return !test->scratch; 234*ad879127SKrish Sadhukhan } 235*ad879127SKrish Sadhukhan 236*ad879127SKrish Sadhukhan static bool next_rip_supported(void) 237*ad879127SKrish Sadhukhan { 238*ad879127SKrish Sadhukhan return this_cpu_has(X86_FEATURE_NRIPS); 239*ad879127SKrish Sadhukhan } 240*ad879127SKrish Sadhukhan 241*ad879127SKrish Sadhukhan static void prepare_next_rip(struct svm_test *test) 242*ad879127SKrish Sadhukhan { 243*ad879127SKrish Sadhukhan test->vmcb->control.intercept |= (1ULL << INTERCEPT_RDTSC); 244*ad879127SKrish Sadhukhan } 245*ad879127SKrish Sadhukhan 246*ad879127SKrish Sadhukhan 247*ad879127SKrish Sadhukhan static void test_next_rip(struct svm_test *test) 248*ad879127SKrish Sadhukhan { 249*ad879127SKrish Sadhukhan asm volatile ("rdtsc\n\t" 250*ad879127SKrish Sadhukhan ".globl exp_next_rip\n\t" 251*ad879127SKrish Sadhukhan "exp_next_rip:\n\t" ::: "eax", "edx"); 252*ad879127SKrish Sadhukhan } 253*ad879127SKrish Sadhukhan 254*ad879127SKrish Sadhukhan static bool check_next_rip(struct svm_test *test) 255*ad879127SKrish Sadhukhan { 256*ad879127SKrish Sadhukhan extern char exp_next_rip; 257*ad879127SKrish Sadhukhan unsigned long address = (unsigned long)&exp_next_rip; 258*ad879127SKrish Sadhukhan 259*ad879127SKrish Sadhukhan return address == test->vmcb->control.next_rip; 260*ad879127SKrish Sadhukhan } 261*ad879127SKrish Sadhukhan 262*ad879127SKrish Sadhukhan extern u8 *msr_bitmap; 263*ad879127SKrish Sadhukhan 264*ad879127SKrish Sadhukhan static void prepare_msr_intercept(struct svm_test *test) 265*ad879127SKrish Sadhukhan { 266*ad879127SKrish Sadhukhan default_prepare(test); 267*ad879127SKrish Sadhukhan test->vmcb->control.intercept |= (1ULL << INTERCEPT_MSR_PROT); 268*ad879127SKrish Sadhukhan test->vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR); 269*ad879127SKrish Sadhukhan memset(msr_bitmap, 0xff, MSR_BITMAP_SIZE); 270*ad879127SKrish Sadhukhan } 271*ad879127SKrish Sadhukhan 272*ad879127SKrish Sadhukhan static void test_msr_intercept(struct svm_test *test) 273*ad879127SKrish Sadhukhan { 274*ad879127SKrish Sadhukhan unsigned long msr_value = 0xef8056791234abcd; /* Arbitrary value */ 275*ad879127SKrish Sadhukhan unsigned long msr_index; 276*ad879127SKrish Sadhukhan 277*ad879127SKrish Sadhukhan for (msr_index = 0; msr_index <= 0xc0011fff; msr_index++) { 278*ad879127SKrish Sadhukhan if (msr_index == 0xC0010131 /* MSR_SEV_STATUS */) { 279*ad879127SKrish Sadhukhan /* 280*ad879127SKrish Sadhukhan * Per section 15.34.10 "SEV_STATUS MSR" of AMD64 Architecture 281*ad879127SKrish Sadhukhan * Programmer's Manual volume 2 - System Programming: 282*ad879127SKrish Sadhukhan * http://support.amd.com/TechDocs/24593.pdf 283*ad879127SKrish Sadhukhan * SEV_STATUS MSR (C001_0131) is a non-interceptable MSR. 284*ad879127SKrish Sadhukhan */ 285*ad879127SKrish Sadhukhan continue; 286*ad879127SKrish Sadhukhan } 287*ad879127SKrish Sadhukhan 288*ad879127SKrish Sadhukhan /* Skips gaps between supported MSR ranges */ 289*ad879127SKrish Sadhukhan if (msr_index == 0x2000) 290*ad879127SKrish Sadhukhan msr_index = 0xc0000000; 291*ad879127SKrish Sadhukhan else if (msr_index == 0xc0002000) 292*ad879127SKrish Sadhukhan msr_index = 0xc0010000; 293*ad879127SKrish Sadhukhan 294*ad879127SKrish Sadhukhan test->scratch = -1; 295*ad879127SKrish Sadhukhan 296*ad879127SKrish Sadhukhan rdmsr(msr_index); 297*ad879127SKrish Sadhukhan 298*ad879127SKrish Sadhukhan /* Check that a read intercept occurred for MSR at msr_index */ 299*ad879127SKrish Sadhukhan if (test->scratch != msr_index) 300*ad879127SKrish Sadhukhan report(false, "MSR 0x%lx read intercept", msr_index); 301*ad879127SKrish Sadhukhan 302*ad879127SKrish Sadhukhan /* 303*ad879127SKrish Sadhukhan * Poor man approach to generate a value that 304*ad879127SKrish Sadhukhan * seems arbitrary each time around the loop. 305*ad879127SKrish Sadhukhan */ 306*ad879127SKrish Sadhukhan msr_value += (msr_value << 1); 307*ad879127SKrish Sadhukhan 308*ad879127SKrish Sadhukhan wrmsr(msr_index, msr_value); 309*ad879127SKrish Sadhukhan 310*ad879127SKrish Sadhukhan /* Check that a write intercept occurred for MSR with msr_value */ 311*ad879127SKrish Sadhukhan if (test->scratch != msr_value) 312*ad879127SKrish Sadhukhan report(false, "MSR 0x%lx write intercept", msr_index); 313*ad879127SKrish Sadhukhan } 314*ad879127SKrish Sadhukhan 315*ad879127SKrish Sadhukhan test->scratch = -2; 316*ad879127SKrish Sadhukhan } 317*ad879127SKrish Sadhukhan 318*ad879127SKrish Sadhukhan static bool msr_intercept_finished(struct svm_test *test) 319*ad879127SKrish Sadhukhan { 320*ad879127SKrish Sadhukhan u32 exit_code = test->vmcb->control.exit_code; 321*ad879127SKrish Sadhukhan u64 exit_info_1; 322*ad879127SKrish Sadhukhan u8 *opcode; 323*ad879127SKrish Sadhukhan 324*ad879127SKrish Sadhukhan if (exit_code == SVM_EXIT_MSR) { 325*ad879127SKrish Sadhukhan exit_info_1 = test->vmcb->control.exit_info_1; 326*ad879127SKrish Sadhukhan } else { 327*ad879127SKrish Sadhukhan /* 328*ad879127SKrish Sadhukhan * If #GP exception occurs instead, check that it was 329*ad879127SKrish Sadhukhan * for RDMSR/WRMSR and set exit_info_1 accordingly. 330*ad879127SKrish Sadhukhan */ 331*ad879127SKrish Sadhukhan 332*ad879127SKrish Sadhukhan if (exit_code != (SVM_EXIT_EXCP_BASE + GP_VECTOR)) 333*ad879127SKrish Sadhukhan return true; 334*ad879127SKrish Sadhukhan 335*ad879127SKrish Sadhukhan opcode = (u8 *)test->vmcb->save.rip; 336*ad879127SKrish Sadhukhan if (opcode[0] != 0x0f) 337*ad879127SKrish Sadhukhan return true; 338*ad879127SKrish Sadhukhan 339*ad879127SKrish Sadhukhan switch (opcode[1]) { 340*ad879127SKrish Sadhukhan case 0x30: /* WRMSR */ 341*ad879127SKrish Sadhukhan exit_info_1 = 1; 342*ad879127SKrish Sadhukhan break; 343*ad879127SKrish Sadhukhan case 0x32: /* RDMSR */ 344*ad879127SKrish Sadhukhan exit_info_1 = 0; 345*ad879127SKrish Sadhukhan break; 346*ad879127SKrish Sadhukhan default: 347*ad879127SKrish Sadhukhan return true; 348*ad879127SKrish Sadhukhan } 349*ad879127SKrish Sadhukhan 350*ad879127SKrish Sadhukhan /* 351*ad879127SKrish Sadhukhan * Warn that #GP exception occured instead. 352*ad879127SKrish Sadhukhan * RCX holds the MSR index. 353*ad879127SKrish Sadhukhan */ 354*ad879127SKrish Sadhukhan printf("%s 0x%lx #GP exception\n", 355*ad879127SKrish Sadhukhan exit_info_1 ? "WRMSR" : "RDMSR", get_regs().rcx); 356*ad879127SKrish Sadhukhan } 357*ad879127SKrish Sadhukhan 358*ad879127SKrish Sadhukhan /* Jump over RDMSR/WRMSR instruction */ 359*ad879127SKrish Sadhukhan test->vmcb->save.rip += 2; 360*ad879127SKrish Sadhukhan 361*ad879127SKrish Sadhukhan /* 362*ad879127SKrish Sadhukhan * Test whether the intercept was for RDMSR/WRMSR. 363*ad879127SKrish Sadhukhan * For RDMSR, test->scratch is set to the MSR index; 364*ad879127SKrish Sadhukhan * RCX holds the MSR index. 365*ad879127SKrish Sadhukhan * For WRMSR, test->scratch is set to the MSR value; 366*ad879127SKrish Sadhukhan * RDX holds the upper 32 bits of the MSR value, 367*ad879127SKrish Sadhukhan * while RAX hold its lower 32 bits. 368*ad879127SKrish Sadhukhan */ 369*ad879127SKrish Sadhukhan if (exit_info_1) 370*ad879127SKrish Sadhukhan test->scratch = 371*ad879127SKrish Sadhukhan ((get_regs().rdx << 32) | (test->vmcb->save.rax & 0xffffffff)); 372*ad879127SKrish Sadhukhan else 373*ad879127SKrish Sadhukhan test->scratch = get_regs().rcx; 374*ad879127SKrish Sadhukhan 375*ad879127SKrish Sadhukhan return false; 376*ad879127SKrish Sadhukhan } 377*ad879127SKrish Sadhukhan 378*ad879127SKrish Sadhukhan static bool check_msr_intercept(struct svm_test *test) 379*ad879127SKrish Sadhukhan { 380*ad879127SKrish Sadhukhan memset(msr_bitmap, 0, MSR_BITMAP_SIZE); 381*ad879127SKrish Sadhukhan return (test->scratch == -2); 382*ad879127SKrish Sadhukhan } 383*ad879127SKrish Sadhukhan 384*ad879127SKrish Sadhukhan static void prepare_mode_switch(struct svm_test *test) 385*ad879127SKrish Sadhukhan { 386*ad879127SKrish Sadhukhan test->vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR) 387*ad879127SKrish Sadhukhan | (1ULL << UD_VECTOR) 388*ad879127SKrish Sadhukhan | (1ULL << DF_VECTOR) 389*ad879127SKrish Sadhukhan | (1ULL << PF_VECTOR); 390*ad879127SKrish Sadhukhan test->scratch = 0; 391*ad879127SKrish Sadhukhan } 392*ad879127SKrish Sadhukhan 393*ad879127SKrish Sadhukhan static void test_mode_switch(struct svm_test *test) 394*ad879127SKrish Sadhukhan { 395*ad879127SKrish Sadhukhan asm volatile(" cli\n" 396*ad879127SKrish Sadhukhan " ljmp *1f\n" /* jump to 32-bit code segment */ 397*ad879127SKrish Sadhukhan "1:\n" 398*ad879127SKrish Sadhukhan " .long 2f\n" 399*ad879127SKrish Sadhukhan " .long " xstr(KERNEL_CS32) "\n" 400*ad879127SKrish Sadhukhan ".code32\n" 401*ad879127SKrish Sadhukhan "2:\n" 402*ad879127SKrish Sadhukhan " movl %%cr0, %%eax\n" 403*ad879127SKrish Sadhukhan " btcl $31, %%eax\n" /* clear PG */ 404*ad879127SKrish Sadhukhan " movl %%eax, %%cr0\n" 405*ad879127SKrish Sadhukhan " movl $0xc0000080, %%ecx\n" /* EFER */ 406*ad879127SKrish Sadhukhan " rdmsr\n" 407*ad879127SKrish Sadhukhan " btcl $8, %%eax\n" /* clear LME */ 408*ad879127SKrish Sadhukhan " wrmsr\n" 409*ad879127SKrish Sadhukhan " movl %%cr4, %%eax\n" 410*ad879127SKrish Sadhukhan " btcl $5, %%eax\n" /* clear PAE */ 411*ad879127SKrish Sadhukhan " movl %%eax, %%cr4\n" 412*ad879127SKrish Sadhukhan " movw %[ds16], %%ax\n" 413*ad879127SKrish Sadhukhan " movw %%ax, %%ds\n" 414*ad879127SKrish Sadhukhan " ljmpl %[cs16], $3f\n" /* jump to 16 bit protected-mode */ 415*ad879127SKrish Sadhukhan ".code16\n" 416*ad879127SKrish Sadhukhan "3:\n" 417*ad879127SKrish Sadhukhan " movl %%cr0, %%eax\n" 418*ad879127SKrish Sadhukhan " btcl $0, %%eax\n" /* clear PE */ 419*ad879127SKrish Sadhukhan " movl %%eax, %%cr0\n" 420*ad879127SKrish Sadhukhan " ljmpl $0, $4f\n" /* jump to real-mode */ 421*ad879127SKrish Sadhukhan "4:\n" 422*ad879127SKrish Sadhukhan " vmmcall\n" 423*ad879127SKrish Sadhukhan " movl %%cr0, %%eax\n" 424*ad879127SKrish Sadhukhan " btsl $0, %%eax\n" /* set PE */ 425*ad879127SKrish Sadhukhan " movl %%eax, %%cr0\n" 426*ad879127SKrish Sadhukhan " ljmpl %[cs32], $5f\n" /* back to protected mode */ 427*ad879127SKrish Sadhukhan ".code32\n" 428*ad879127SKrish Sadhukhan "5:\n" 429*ad879127SKrish Sadhukhan " movl %%cr4, %%eax\n" 430*ad879127SKrish Sadhukhan " btsl $5, %%eax\n" /* set PAE */ 431*ad879127SKrish Sadhukhan " movl %%eax, %%cr4\n" 432*ad879127SKrish Sadhukhan " movl $0xc0000080, %%ecx\n" /* EFER */ 433*ad879127SKrish Sadhukhan " rdmsr\n" 434*ad879127SKrish Sadhukhan " btsl $8, %%eax\n" /* set LME */ 435*ad879127SKrish Sadhukhan " wrmsr\n" 436*ad879127SKrish Sadhukhan " movl %%cr0, %%eax\n" 437*ad879127SKrish Sadhukhan " btsl $31, %%eax\n" /* set PG */ 438*ad879127SKrish Sadhukhan " movl %%eax, %%cr0\n" 439*ad879127SKrish Sadhukhan " ljmpl %[cs64], $6f\n" /* back to long mode */ 440*ad879127SKrish Sadhukhan ".code64\n\t" 441*ad879127SKrish Sadhukhan "6:\n" 442*ad879127SKrish Sadhukhan " vmmcall\n" 443*ad879127SKrish Sadhukhan :: [cs16] "i"(KERNEL_CS16), [ds16] "i"(KERNEL_DS16), 444*ad879127SKrish Sadhukhan [cs32] "i"(KERNEL_CS32), [cs64] "i"(KERNEL_CS64) 445*ad879127SKrish Sadhukhan : "rax", "rbx", "rcx", "rdx", "memory"); 446*ad879127SKrish Sadhukhan } 447*ad879127SKrish Sadhukhan 448*ad879127SKrish Sadhukhan static bool mode_switch_finished(struct svm_test *test) 449*ad879127SKrish Sadhukhan { 450*ad879127SKrish Sadhukhan u64 cr0, cr4, efer; 451*ad879127SKrish Sadhukhan 452*ad879127SKrish Sadhukhan cr0 = test->vmcb->save.cr0; 453*ad879127SKrish Sadhukhan cr4 = test->vmcb->save.cr4; 454*ad879127SKrish Sadhukhan efer = test->vmcb->save.efer; 455*ad879127SKrish Sadhukhan 456*ad879127SKrish Sadhukhan /* Only expect VMMCALL intercepts */ 457*ad879127SKrish Sadhukhan if (test->vmcb->control.exit_code != SVM_EXIT_VMMCALL) 458*ad879127SKrish Sadhukhan return true; 459*ad879127SKrish Sadhukhan 460*ad879127SKrish Sadhukhan /* Jump over VMMCALL instruction */ 461*ad879127SKrish Sadhukhan test->vmcb->save.rip += 3; 462*ad879127SKrish Sadhukhan 463*ad879127SKrish Sadhukhan /* Do sanity checks */ 464*ad879127SKrish Sadhukhan switch (test->scratch) { 465*ad879127SKrish Sadhukhan case 0: 466*ad879127SKrish Sadhukhan /* Test should be in real mode now - check for this */ 467*ad879127SKrish Sadhukhan if ((cr0 & 0x80000001) || /* CR0.PG, CR0.PE */ 468*ad879127SKrish Sadhukhan (cr4 & 0x00000020) || /* CR4.PAE */ 469*ad879127SKrish Sadhukhan (efer & 0x00000500)) /* EFER.LMA, EFER.LME */ 470*ad879127SKrish Sadhukhan return true; 471*ad879127SKrish Sadhukhan break; 472*ad879127SKrish Sadhukhan case 2: 473*ad879127SKrish Sadhukhan /* Test should be back in long-mode now - check for this */ 474*ad879127SKrish Sadhukhan if (((cr0 & 0x80000001) != 0x80000001) || /* CR0.PG, CR0.PE */ 475*ad879127SKrish Sadhukhan ((cr4 & 0x00000020) != 0x00000020) || /* CR4.PAE */ 476*ad879127SKrish Sadhukhan ((efer & 0x00000500) != 0x00000500)) /* EFER.LMA, EFER.LME */ 477*ad879127SKrish Sadhukhan return true; 478*ad879127SKrish Sadhukhan break; 479*ad879127SKrish Sadhukhan } 480*ad879127SKrish Sadhukhan 481*ad879127SKrish Sadhukhan /* one step forward */ 482*ad879127SKrish Sadhukhan test->scratch += 1; 483*ad879127SKrish Sadhukhan 484*ad879127SKrish Sadhukhan return test->scratch == 2; 485*ad879127SKrish Sadhukhan } 486*ad879127SKrish Sadhukhan 487*ad879127SKrish Sadhukhan static bool check_mode_switch(struct svm_test *test) 488*ad879127SKrish Sadhukhan { 489*ad879127SKrish Sadhukhan return test->scratch == 2; 490*ad879127SKrish Sadhukhan } 491*ad879127SKrish Sadhukhan 492*ad879127SKrish Sadhukhan extern u8 *io_bitmap; 493*ad879127SKrish Sadhukhan 494*ad879127SKrish Sadhukhan static void prepare_ioio(struct svm_test *test) 495*ad879127SKrish Sadhukhan { 496*ad879127SKrish Sadhukhan test->vmcb->control.intercept |= (1ULL << INTERCEPT_IOIO_PROT); 497*ad879127SKrish Sadhukhan test->scratch = 0; 498*ad879127SKrish Sadhukhan memset(io_bitmap, 0, 8192); 499*ad879127SKrish Sadhukhan io_bitmap[8192] = 0xFF; 500*ad879127SKrish Sadhukhan } 501*ad879127SKrish Sadhukhan 502*ad879127SKrish Sadhukhan static void test_ioio(struct svm_test *test) 503*ad879127SKrish Sadhukhan { 504*ad879127SKrish Sadhukhan // stage 0, test IO pass 505*ad879127SKrish Sadhukhan inb(0x5000); 506*ad879127SKrish Sadhukhan outb(0x0, 0x5000); 507*ad879127SKrish Sadhukhan if (get_test_stage(test) != 0) 508*ad879127SKrish Sadhukhan goto fail; 509*ad879127SKrish Sadhukhan 510*ad879127SKrish Sadhukhan // test IO width, in/out 511*ad879127SKrish Sadhukhan io_bitmap[0] = 0xFF; 512*ad879127SKrish Sadhukhan inc_test_stage(test); 513*ad879127SKrish Sadhukhan inb(0x0); 514*ad879127SKrish Sadhukhan if (get_test_stage(test) != 2) 515*ad879127SKrish Sadhukhan goto fail; 516*ad879127SKrish Sadhukhan 517*ad879127SKrish Sadhukhan outw(0x0, 0x0); 518*ad879127SKrish Sadhukhan if (get_test_stage(test) != 3) 519*ad879127SKrish Sadhukhan goto fail; 520*ad879127SKrish Sadhukhan 521*ad879127SKrish Sadhukhan inl(0x0); 522*ad879127SKrish Sadhukhan if (get_test_stage(test) != 4) 523*ad879127SKrish Sadhukhan goto fail; 524*ad879127SKrish Sadhukhan 525*ad879127SKrish Sadhukhan // test low/high IO port 526*ad879127SKrish Sadhukhan io_bitmap[0x5000 / 8] = (1 << (0x5000 % 8)); 527*ad879127SKrish Sadhukhan inb(0x5000); 528*ad879127SKrish Sadhukhan if (get_test_stage(test) != 5) 529*ad879127SKrish Sadhukhan goto fail; 530*ad879127SKrish Sadhukhan 531*ad879127SKrish Sadhukhan io_bitmap[0x9000 / 8] = (1 << (0x9000 % 8)); 532*ad879127SKrish Sadhukhan inw(0x9000); 533*ad879127SKrish Sadhukhan if (get_test_stage(test) != 6) 534*ad879127SKrish Sadhukhan goto fail; 535*ad879127SKrish Sadhukhan 536*ad879127SKrish Sadhukhan // test partial pass 537*ad879127SKrish Sadhukhan io_bitmap[0x5000 / 8] = (1 << (0x5000 % 8)); 538*ad879127SKrish Sadhukhan inl(0x4FFF); 539*ad879127SKrish Sadhukhan if (get_test_stage(test) != 7) 540*ad879127SKrish Sadhukhan goto fail; 541*ad879127SKrish Sadhukhan 542*ad879127SKrish Sadhukhan // test across pages 543*ad879127SKrish Sadhukhan inc_test_stage(test); 544*ad879127SKrish Sadhukhan inl(0x7FFF); 545*ad879127SKrish Sadhukhan if (get_test_stage(test) != 8) 546*ad879127SKrish Sadhukhan goto fail; 547*ad879127SKrish Sadhukhan 548*ad879127SKrish Sadhukhan inc_test_stage(test); 549*ad879127SKrish Sadhukhan io_bitmap[0x8000 / 8] = 1 << (0x8000 % 8); 550*ad879127SKrish Sadhukhan inl(0x7FFF); 551*ad879127SKrish Sadhukhan if (get_test_stage(test) != 10) 552*ad879127SKrish Sadhukhan goto fail; 553*ad879127SKrish Sadhukhan 554*ad879127SKrish Sadhukhan io_bitmap[0] = 0; 555*ad879127SKrish Sadhukhan inl(0xFFFF); 556*ad879127SKrish Sadhukhan if (get_test_stage(test) != 11) 557*ad879127SKrish Sadhukhan goto fail; 558*ad879127SKrish Sadhukhan 559*ad879127SKrish Sadhukhan io_bitmap[0] = 0xFF; 560*ad879127SKrish Sadhukhan io_bitmap[8192] = 0; 561*ad879127SKrish Sadhukhan inl(0xFFFF); 562*ad879127SKrish Sadhukhan inc_test_stage(test); 563*ad879127SKrish Sadhukhan if (get_test_stage(test) != 12) 564*ad879127SKrish Sadhukhan goto fail; 565*ad879127SKrish Sadhukhan 566*ad879127SKrish Sadhukhan return; 567*ad879127SKrish Sadhukhan 568*ad879127SKrish Sadhukhan fail: 569*ad879127SKrish Sadhukhan report(false, "stage %d", get_test_stage(test)); 570*ad879127SKrish Sadhukhan test->scratch = -1; 571*ad879127SKrish Sadhukhan } 572*ad879127SKrish Sadhukhan 573*ad879127SKrish Sadhukhan static bool ioio_finished(struct svm_test *test) 574*ad879127SKrish Sadhukhan { 575*ad879127SKrish Sadhukhan unsigned port, size; 576*ad879127SKrish Sadhukhan 577*ad879127SKrish Sadhukhan /* Only expect IOIO intercepts */ 578*ad879127SKrish Sadhukhan if (test->vmcb->control.exit_code == SVM_EXIT_VMMCALL) 579*ad879127SKrish Sadhukhan return true; 580*ad879127SKrish Sadhukhan 581*ad879127SKrish Sadhukhan if (test->vmcb->control.exit_code != SVM_EXIT_IOIO) 582*ad879127SKrish Sadhukhan return true; 583*ad879127SKrish Sadhukhan 584*ad879127SKrish Sadhukhan /* one step forward */ 585*ad879127SKrish Sadhukhan test->scratch += 1; 586*ad879127SKrish Sadhukhan 587*ad879127SKrish Sadhukhan port = test->vmcb->control.exit_info_1 >> 16; 588*ad879127SKrish Sadhukhan size = (test->vmcb->control.exit_info_1 >> SVM_IOIO_SIZE_SHIFT) & 7; 589*ad879127SKrish Sadhukhan 590*ad879127SKrish Sadhukhan while (size--) { 591*ad879127SKrish Sadhukhan io_bitmap[port / 8] &= ~(1 << (port & 7)); 592*ad879127SKrish Sadhukhan port++; 593*ad879127SKrish Sadhukhan } 594*ad879127SKrish Sadhukhan 595*ad879127SKrish Sadhukhan return false; 596*ad879127SKrish Sadhukhan } 597*ad879127SKrish Sadhukhan 598*ad879127SKrish Sadhukhan static bool check_ioio(struct svm_test *test) 599*ad879127SKrish Sadhukhan { 600*ad879127SKrish Sadhukhan memset(io_bitmap, 0, 8193); 601*ad879127SKrish Sadhukhan return test->scratch != -1; 602*ad879127SKrish Sadhukhan } 603*ad879127SKrish Sadhukhan 604*ad879127SKrish Sadhukhan static void prepare_asid_zero(struct svm_test *test) 605*ad879127SKrish Sadhukhan { 606*ad879127SKrish Sadhukhan test->vmcb->control.asid = 0; 607*ad879127SKrish Sadhukhan } 608*ad879127SKrish Sadhukhan 609*ad879127SKrish Sadhukhan static void test_asid_zero(struct svm_test *test) 610*ad879127SKrish Sadhukhan { 611*ad879127SKrish Sadhukhan asm volatile ("vmmcall\n\t"); 612*ad879127SKrish Sadhukhan } 613*ad879127SKrish Sadhukhan 614*ad879127SKrish Sadhukhan static bool check_asid_zero(struct svm_test *test) 615*ad879127SKrish Sadhukhan { 616*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_ERR; 617*ad879127SKrish Sadhukhan } 618*ad879127SKrish Sadhukhan 619*ad879127SKrish Sadhukhan static void sel_cr0_bug_prepare(struct svm_test *test) 620*ad879127SKrish Sadhukhan { 621*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 622*ad879127SKrish Sadhukhan test->vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0); 623*ad879127SKrish Sadhukhan } 624*ad879127SKrish Sadhukhan 625*ad879127SKrish Sadhukhan static bool sel_cr0_bug_finished(struct svm_test *test) 626*ad879127SKrish Sadhukhan { 627*ad879127SKrish Sadhukhan return true; 628*ad879127SKrish Sadhukhan } 629*ad879127SKrish Sadhukhan 630*ad879127SKrish Sadhukhan static void sel_cr0_bug_test(struct svm_test *test) 631*ad879127SKrish Sadhukhan { 632*ad879127SKrish Sadhukhan unsigned long cr0; 633*ad879127SKrish Sadhukhan 634*ad879127SKrish Sadhukhan /* read cr0, clear CD, and write back */ 635*ad879127SKrish Sadhukhan cr0 = read_cr0(); 636*ad879127SKrish Sadhukhan cr0 |= (1UL << 30); 637*ad879127SKrish Sadhukhan write_cr0(cr0); 638*ad879127SKrish Sadhukhan 639*ad879127SKrish Sadhukhan /* 640*ad879127SKrish Sadhukhan * If we are here the test failed, not sure what to do now because we 641*ad879127SKrish Sadhukhan * are not in guest-mode anymore so we can't trigger an intercept. 642*ad879127SKrish Sadhukhan * Trigger a tripple-fault for now. 643*ad879127SKrish Sadhukhan */ 644*ad879127SKrish Sadhukhan report(false, "sel_cr0 test. Can not recover from this - exiting"); 645*ad879127SKrish Sadhukhan exit(report_summary()); 646*ad879127SKrish Sadhukhan } 647*ad879127SKrish Sadhukhan 648*ad879127SKrish Sadhukhan static bool sel_cr0_bug_check(struct svm_test *test) 649*ad879127SKrish Sadhukhan { 650*ad879127SKrish Sadhukhan return test->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE; 651*ad879127SKrish Sadhukhan } 652*ad879127SKrish Sadhukhan 653*ad879127SKrish Sadhukhan static void npt_nx_prepare(struct svm_test *test) 654*ad879127SKrish Sadhukhan { 655*ad879127SKrish Sadhukhan 656*ad879127SKrish Sadhukhan u64 *pte; 657*ad879127SKrish Sadhukhan 658*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 659*ad879127SKrish Sadhukhan pte = npt_get_pte((u64)null_test); 660*ad879127SKrish Sadhukhan 661*ad879127SKrish Sadhukhan *pte |= (1ULL << 63); 662*ad879127SKrish Sadhukhan } 663*ad879127SKrish Sadhukhan 664*ad879127SKrish Sadhukhan static bool npt_nx_check(struct svm_test *test) 665*ad879127SKrish Sadhukhan { 666*ad879127SKrish Sadhukhan u64 *pte = npt_get_pte((u64)null_test); 667*ad879127SKrish Sadhukhan 668*ad879127SKrish Sadhukhan *pte &= ~(1ULL << 63); 669*ad879127SKrish Sadhukhan 670*ad879127SKrish Sadhukhan test->vmcb->save.efer |= (1 << 11); 671*ad879127SKrish Sadhukhan 672*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 673*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x100000015ULL); 674*ad879127SKrish Sadhukhan } 675*ad879127SKrish Sadhukhan 676*ad879127SKrish Sadhukhan static void npt_us_prepare(struct svm_test *test) 677*ad879127SKrish Sadhukhan { 678*ad879127SKrish Sadhukhan u64 *pte; 679*ad879127SKrish Sadhukhan 680*ad879127SKrish Sadhukhan scratch_page = alloc_page(); 681*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 682*ad879127SKrish Sadhukhan pte = npt_get_pte((u64)scratch_page); 683*ad879127SKrish Sadhukhan 684*ad879127SKrish Sadhukhan *pte &= ~(1ULL << 2); 685*ad879127SKrish Sadhukhan } 686*ad879127SKrish Sadhukhan 687*ad879127SKrish Sadhukhan static void npt_us_test(struct svm_test *test) 688*ad879127SKrish Sadhukhan { 689*ad879127SKrish Sadhukhan (void) *(volatile u64 *)scratch_page; 690*ad879127SKrish Sadhukhan } 691*ad879127SKrish Sadhukhan 692*ad879127SKrish Sadhukhan static bool npt_us_check(struct svm_test *test) 693*ad879127SKrish Sadhukhan { 694*ad879127SKrish Sadhukhan u64 *pte = npt_get_pte((u64)scratch_page); 695*ad879127SKrish Sadhukhan 696*ad879127SKrish Sadhukhan *pte |= (1ULL << 2); 697*ad879127SKrish Sadhukhan 698*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 699*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x100000005ULL); 700*ad879127SKrish Sadhukhan } 701*ad879127SKrish Sadhukhan 702*ad879127SKrish Sadhukhan u64 save_pde; 703*ad879127SKrish Sadhukhan 704*ad879127SKrish Sadhukhan static void npt_rsvd_prepare(struct svm_test *test) 705*ad879127SKrish Sadhukhan { 706*ad879127SKrish Sadhukhan u64 *pde; 707*ad879127SKrish Sadhukhan 708*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 709*ad879127SKrish Sadhukhan pde = npt_get_pde((u64) null_test); 710*ad879127SKrish Sadhukhan 711*ad879127SKrish Sadhukhan save_pde = *pde; 712*ad879127SKrish Sadhukhan *pde = (1ULL << 19) | (1ULL << 7) | 0x27; 713*ad879127SKrish Sadhukhan } 714*ad879127SKrish Sadhukhan 715*ad879127SKrish Sadhukhan static bool npt_rsvd_check(struct svm_test *test) 716*ad879127SKrish Sadhukhan { 717*ad879127SKrish Sadhukhan u64 *pde = npt_get_pde((u64) null_test); 718*ad879127SKrish Sadhukhan 719*ad879127SKrish Sadhukhan *pde = save_pde; 720*ad879127SKrish Sadhukhan 721*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 722*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x10000001dULL); 723*ad879127SKrish Sadhukhan } 724*ad879127SKrish Sadhukhan 725*ad879127SKrish Sadhukhan static void npt_rw_prepare(struct svm_test *test) 726*ad879127SKrish Sadhukhan { 727*ad879127SKrish Sadhukhan 728*ad879127SKrish Sadhukhan u64 *pte; 729*ad879127SKrish Sadhukhan 730*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 731*ad879127SKrish Sadhukhan pte = npt_get_pte(0x80000); 732*ad879127SKrish Sadhukhan 733*ad879127SKrish Sadhukhan *pte &= ~(1ULL << 1); 734*ad879127SKrish Sadhukhan } 735*ad879127SKrish Sadhukhan 736*ad879127SKrish Sadhukhan static void npt_rw_test(struct svm_test *test) 737*ad879127SKrish Sadhukhan { 738*ad879127SKrish Sadhukhan u64 *data = (void*)(0x80000); 739*ad879127SKrish Sadhukhan 740*ad879127SKrish Sadhukhan *data = 0; 741*ad879127SKrish Sadhukhan } 742*ad879127SKrish Sadhukhan 743*ad879127SKrish Sadhukhan static bool npt_rw_check(struct svm_test *test) 744*ad879127SKrish Sadhukhan { 745*ad879127SKrish Sadhukhan u64 *pte = npt_get_pte(0x80000); 746*ad879127SKrish Sadhukhan 747*ad879127SKrish Sadhukhan *pte |= (1ULL << 1); 748*ad879127SKrish Sadhukhan 749*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 750*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x100000007ULL); 751*ad879127SKrish Sadhukhan } 752*ad879127SKrish Sadhukhan 753*ad879127SKrish Sadhukhan static void npt_rw_pfwalk_prepare(struct svm_test *test) 754*ad879127SKrish Sadhukhan { 755*ad879127SKrish Sadhukhan 756*ad879127SKrish Sadhukhan u64 *pte; 757*ad879127SKrish Sadhukhan 758*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 759*ad879127SKrish Sadhukhan pte = npt_get_pte(read_cr3()); 760*ad879127SKrish Sadhukhan 761*ad879127SKrish Sadhukhan *pte &= ~(1ULL << 1); 762*ad879127SKrish Sadhukhan } 763*ad879127SKrish Sadhukhan 764*ad879127SKrish Sadhukhan static bool npt_rw_pfwalk_check(struct svm_test *test) 765*ad879127SKrish Sadhukhan { 766*ad879127SKrish Sadhukhan u64 *pte = npt_get_pte(read_cr3()); 767*ad879127SKrish Sadhukhan 768*ad879127SKrish Sadhukhan *pte |= (1ULL << 1); 769*ad879127SKrish Sadhukhan 770*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 771*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x200000006ULL) 772*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_2 == read_cr3()); 773*ad879127SKrish Sadhukhan } 774*ad879127SKrish Sadhukhan 775*ad879127SKrish Sadhukhan static void npt_rsvd_pfwalk_prepare(struct svm_test *test) 776*ad879127SKrish Sadhukhan { 777*ad879127SKrish Sadhukhan u64 *pdpe; 778*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 779*ad879127SKrish Sadhukhan 780*ad879127SKrish Sadhukhan pdpe = npt_get_pdpe(); 781*ad879127SKrish Sadhukhan pdpe[0] |= (1ULL << 8); 782*ad879127SKrish Sadhukhan } 783*ad879127SKrish Sadhukhan 784*ad879127SKrish Sadhukhan static bool npt_rsvd_pfwalk_check(struct svm_test *test) 785*ad879127SKrish Sadhukhan { 786*ad879127SKrish Sadhukhan u64 *pdpe = npt_get_pdpe(); 787*ad879127SKrish Sadhukhan pdpe[0] &= ~(1ULL << 8); 788*ad879127SKrish Sadhukhan 789*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 790*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x20000000eULL); 791*ad879127SKrish Sadhukhan } 792*ad879127SKrish Sadhukhan 793*ad879127SKrish Sadhukhan static void npt_l1mmio_prepare(struct svm_test *test) 794*ad879127SKrish Sadhukhan { 795*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 796*ad879127SKrish Sadhukhan } 797*ad879127SKrish Sadhukhan 798*ad879127SKrish Sadhukhan u32 nested_apic_version1; 799*ad879127SKrish Sadhukhan u32 nested_apic_version2; 800*ad879127SKrish Sadhukhan 801*ad879127SKrish Sadhukhan static void npt_l1mmio_test(struct svm_test *test) 802*ad879127SKrish Sadhukhan { 803*ad879127SKrish Sadhukhan volatile u32 *data = (volatile void*)(0xfee00030UL); 804*ad879127SKrish Sadhukhan 805*ad879127SKrish Sadhukhan nested_apic_version1 = *data; 806*ad879127SKrish Sadhukhan nested_apic_version2 = *data; 807*ad879127SKrish Sadhukhan } 808*ad879127SKrish Sadhukhan 809*ad879127SKrish Sadhukhan static bool npt_l1mmio_check(struct svm_test *test) 810*ad879127SKrish Sadhukhan { 811*ad879127SKrish Sadhukhan volatile u32 *data = (volatile void*)(0xfee00030); 812*ad879127SKrish Sadhukhan u32 lvr = *data; 813*ad879127SKrish Sadhukhan 814*ad879127SKrish Sadhukhan return nested_apic_version1 == lvr && nested_apic_version2 == lvr; 815*ad879127SKrish Sadhukhan } 816*ad879127SKrish Sadhukhan 817*ad879127SKrish Sadhukhan static void npt_rw_l1mmio_prepare(struct svm_test *test) 818*ad879127SKrish Sadhukhan { 819*ad879127SKrish Sadhukhan 820*ad879127SKrish Sadhukhan u64 *pte; 821*ad879127SKrish Sadhukhan 822*ad879127SKrish Sadhukhan vmcb_ident(test->vmcb); 823*ad879127SKrish Sadhukhan pte = npt_get_pte(0xfee00080); 824*ad879127SKrish Sadhukhan 825*ad879127SKrish Sadhukhan *pte &= ~(1ULL << 1); 826*ad879127SKrish Sadhukhan } 827*ad879127SKrish Sadhukhan 828*ad879127SKrish Sadhukhan static void npt_rw_l1mmio_test(struct svm_test *test) 829*ad879127SKrish Sadhukhan { 830*ad879127SKrish Sadhukhan volatile u32 *data = (volatile void*)(0xfee00080); 831*ad879127SKrish Sadhukhan 832*ad879127SKrish Sadhukhan *data = *data; 833*ad879127SKrish Sadhukhan } 834*ad879127SKrish Sadhukhan 835*ad879127SKrish Sadhukhan static bool npt_rw_l1mmio_check(struct svm_test *test) 836*ad879127SKrish Sadhukhan { 837*ad879127SKrish Sadhukhan u64 *pte = npt_get_pte(0xfee00080); 838*ad879127SKrish Sadhukhan 839*ad879127SKrish Sadhukhan *pte |= (1ULL << 1); 840*ad879127SKrish Sadhukhan 841*ad879127SKrish Sadhukhan return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 842*ad879127SKrish Sadhukhan && (test->vmcb->control.exit_info_1 == 0x100000007ULL); 843*ad879127SKrish Sadhukhan } 844*ad879127SKrish Sadhukhan 845*ad879127SKrish Sadhukhan #define TSC_ADJUST_VALUE (1ll << 32) 846*ad879127SKrish Sadhukhan #define TSC_OFFSET_VALUE (-1ll << 48) 847*ad879127SKrish Sadhukhan static bool ok; 848*ad879127SKrish Sadhukhan 849*ad879127SKrish Sadhukhan static void tsc_adjust_prepare(struct svm_test *test) 850*ad879127SKrish Sadhukhan { 851*ad879127SKrish Sadhukhan default_prepare(test); 852*ad879127SKrish Sadhukhan test->vmcb->control.tsc_offset = TSC_OFFSET_VALUE; 853*ad879127SKrish Sadhukhan 854*ad879127SKrish Sadhukhan wrmsr(MSR_IA32_TSC_ADJUST, -TSC_ADJUST_VALUE); 855*ad879127SKrish Sadhukhan int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); 856*ad879127SKrish Sadhukhan ok = adjust == -TSC_ADJUST_VALUE; 857*ad879127SKrish Sadhukhan } 858*ad879127SKrish Sadhukhan 859*ad879127SKrish Sadhukhan static void tsc_adjust_test(struct svm_test *test) 860*ad879127SKrish Sadhukhan { 861*ad879127SKrish Sadhukhan int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); 862*ad879127SKrish Sadhukhan ok &= adjust == -TSC_ADJUST_VALUE; 863*ad879127SKrish Sadhukhan 864*ad879127SKrish Sadhukhan uint64_t l1_tsc = rdtsc() - TSC_OFFSET_VALUE; 865*ad879127SKrish Sadhukhan wrmsr(MSR_IA32_TSC, l1_tsc - TSC_ADJUST_VALUE); 866*ad879127SKrish Sadhukhan 867*ad879127SKrish Sadhukhan adjust = rdmsr(MSR_IA32_TSC_ADJUST); 868*ad879127SKrish Sadhukhan ok &= adjust <= -2 * TSC_ADJUST_VALUE; 869*ad879127SKrish Sadhukhan 870*ad879127SKrish Sadhukhan uint64_t l1_tsc_end = rdtsc() - TSC_OFFSET_VALUE; 871*ad879127SKrish Sadhukhan ok &= (l1_tsc_end + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE; 872*ad879127SKrish Sadhukhan 873*ad879127SKrish Sadhukhan uint64_t l1_tsc_msr = rdmsr(MSR_IA32_TSC) - TSC_OFFSET_VALUE; 874*ad879127SKrish Sadhukhan ok &= (l1_tsc_msr + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE; 875*ad879127SKrish Sadhukhan } 876*ad879127SKrish Sadhukhan 877*ad879127SKrish Sadhukhan static bool tsc_adjust_check(struct svm_test *test) 878*ad879127SKrish Sadhukhan { 879*ad879127SKrish Sadhukhan int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); 880*ad879127SKrish Sadhukhan 881*ad879127SKrish Sadhukhan wrmsr(MSR_IA32_TSC_ADJUST, 0); 882*ad879127SKrish Sadhukhan return ok && adjust <= -2 * TSC_ADJUST_VALUE; 883*ad879127SKrish Sadhukhan } 884*ad879127SKrish Sadhukhan 885*ad879127SKrish Sadhukhan static void latency_prepare(struct svm_test *test) 886*ad879127SKrish Sadhukhan { 887*ad879127SKrish Sadhukhan default_prepare(test); 888*ad879127SKrish Sadhukhan runs = LATENCY_RUNS; 889*ad879127SKrish Sadhukhan latvmrun_min = latvmexit_min = -1ULL; 890*ad879127SKrish Sadhukhan latvmrun_max = latvmexit_max = 0; 891*ad879127SKrish Sadhukhan vmrun_sum = vmexit_sum = 0; 892*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 893*ad879127SKrish Sadhukhan } 894*ad879127SKrish Sadhukhan 895*ad879127SKrish Sadhukhan static void latency_test(struct svm_test *test) 896*ad879127SKrish Sadhukhan { 897*ad879127SKrish Sadhukhan u64 cycles; 898*ad879127SKrish Sadhukhan 899*ad879127SKrish Sadhukhan start: 900*ad879127SKrish Sadhukhan tsc_end = rdtsc(); 901*ad879127SKrish Sadhukhan 902*ad879127SKrish Sadhukhan cycles = tsc_end - tsc_start; 903*ad879127SKrish Sadhukhan 904*ad879127SKrish Sadhukhan if (cycles > latvmrun_max) 905*ad879127SKrish Sadhukhan latvmrun_max = cycles; 906*ad879127SKrish Sadhukhan 907*ad879127SKrish Sadhukhan if (cycles < latvmrun_min) 908*ad879127SKrish Sadhukhan latvmrun_min = cycles; 909*ad879127SKrish Sadhukhan 910*ad879127SKrish Sadhukhan vmrun_sum += cycles; 911*ad879127SKrish Sadhukhan 912*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 913*ad879127SKrish Sadhukhan 914*ad879127SKrish Sadhukhan asm volatile ("vmmcall" : : : "memory"); 915*ad879127SKrish Sadhukhan goto start; 916*ad879127SKrish Sadhukhan } 917*ad879127SKrish Sadhukhan 918*ad879127SKrish Sadhukhan static bool latency_finished(struct svm_test *test) 919*ad879127SKrish Sadhukhan { 920*ad879127SKrish Sadhukhan u64 cycles; 921*ad879127SKrish Sadhukhan 922*ad879127SKrish Sadhukhan tsc_end = rdtsc(); 923*ad879127SKrish Sadhukhan 924*ad879127SKrish Sadhukhan cycles = tsc_end - tsc_start; 925*ad879127SKrish Sadhukhan 926*ad879127SKrish Sadhukhan if (cycles > latvmexit_max) 927*ad879127SKrish Sadhukhan latvmexit_max = cycles; 928*ad879127SKrish Sadhukhan 929*ad879127SKrish Sadhukhan if (cycles < latvmexit_min) 930*ad879127SKrish Sadhukhan latvmexit_min = cycles; 931*ad879127SKrish Sadhukhan 932*ad879127SKrish Sadhukhan vmexit_sum += cycles; 933*ad879127SKrish Sadhukhan 934*ad879127SKrish Sadhukhan test->vmcb->save.rip += 3; 935*ad879127SKrish Sadhukhan 936*ad879127SKrish Sadhukhan runs -= 1; 937*ad879127SKrish Sadhukhan 938*ad879127SKrish Sadhukhan tsc_end = rdtsc(); 939*ad879127SKrish Sadhukhan 940*ad879127SKrish Sadhukhan return runs == 0; 941*ad879127SKrish Sadhukhan } 942*ad879127SKrish Sadhukhan 943*ad879127SKrish Sadhukhan static bool latency_check(struct svm_test *test) 944*ad879127SKrish Sadhukhan { 945*ad879127SKrish Sadhukhan printf(" Latency VMRUN : max: %ld min: %ld avg: %ld\n", latvmrun_max, 946*ad879127SKrish Sadhukhan latvmrun_min, vmrun_sum / LATENCY_RUNS); 947*ad879127SKrish Sadhukhan printf(" Latency VMEXIT: max: %ld min: %ld avg: %ld\n", latvmexit_max, 948*ad879127SKrish Sadhukhan latvmexit_min, vmexit_sum / LATENCY_RUNS); 949*ad879127SKrish Sadhukhan return true; 950*ad879127SKrish Sadhukhan } 951*ad879127SKrish Sadhukhan 952*ad879127SKrish Sadhukhan static void lat_svm_insn_prepare(struct svm_test *test) 953*ad879127SKrish Sadhukhan { 954*ad879127SKrish Sadhukhan default_prepare(test); 955*ad879127SKrish Sadhukhan runs = LATENCY_RUNS; 956*ad879127SKrish Sadhukhan latvmload_min = latvmsave_min = latstgi_min = latclgi_min = -1ULL; 957*ad879127SKrish Sadhukhan latvmload_max = latvmsave_max = latstgi_max = latclgi_max = 0; 958*ad879127SKrish Sadhukhan vmload_sum = vmsave_sum = stgi_sum = clgi_sum; 959*ad879127SKrish Sadhukhan } 960*ad879127SKrish Sadhukhan 961*ad879127SKrish Sadhukhan static bool lat_svm_insn_finished(struct svm_test *test) 962*ad879127SKrish Sadhukhan { 963*ad879127SKrish Sadhukhan u64 vmcb_phys = virt_to_phys(test->vmcb); 964*ad879127SKrish Sadhukhan u64 cycles; 965*ad879127SKrish Sadhukhan 966*ad879127SKrish Sadhukhan for ( ; runs != 0; runs--) { 967*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 968*ad879127SKrish Sadhukhan asm volatile("vmload %0\n\t" : : "a"(vmcb_phys) : "memory"); 969*ad879127SKrish Sadhukhan cycles = rdtsc() - tsc_start; 970*ad879127SKrish Sadhukhan if (cycles > latvmload_max) 971*ad879127SKrish Sadhukhan latvmload_max = cycles; 972*ad879127SKrish Sadhukhan if (cycles < latvmload_min) 973*ad879127SKrish Sadhukhan latvmload_min = cycles; 974*ad879127SKrish Sadhukhan vmload_sum += cycles; 975*ad879127SKrish Sadhukhan 976*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 977*ad879127SKrish Sadhukhan asm volatile("vmsave %0\n\t" : : "a"(vmcb_phys) : "memory"); 978*ad879127SKrish Sadhukhan cycles = rdtsc() - tsc_start; 979*ad879127SKrish Sadhukhan if (cycles > latvmsave_max) 980*ad879127SKrish Sadhukhan latvmsave_max = cycles; 981*ad879127SKrish Sadhukhan if (cycles < latvmsave_min) 982*ad879127SKrish Sadhukhan latvmsave_min = cycles; 983*ad879127SKrish Sadhukhan vmsave_sum += cycles; 984*ad879127SKrish Sadhukhan 985*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 986*ad879127SKrish Sadhukhan asm volatile("stgi\n\t"); 987*ad879127SKrish Sadhukhan cycles = rdtsc() - tsc_start; 988*ad879127SKrish Sadhukhan if (cycles > latstgi_max) 989*ad879127SKrish Sadhukhan latstgi_max = cycles; 990*ad879127SKrish Sadhukhan if (cycles < latstgi_min) 991*ad879127SKrish Sadhukhan latstgi_min = cycles; 992*ad879127SKrish Sadhukhan stgi_sum += cycles; 993*ad879127SKrish Sadhukhan 994*ad879127SKrish Sadhukhan tsc_start = rdtsc(); 995*ad879127SKrish Sadhukhan asm volatile("clgi\n\t"); 996*ad879127SKrish Sadhukhan cycles = rdtsc() - tsc_start; 997*ad879127SKrish Sadhukhan if (cycles > latclgi_max) 998*ad879127SKrish Sadhukhan latclgi_max = cycles; 999*ad879127SKrish Sadhukhan if (cycles < latclgi_min) 1000*ad879127SKrish Sadhukhan latclgi_min = cycles; 1001*ad879127SKrish Sadhukhan clgi_sum += cycles; 1002*ad879127SKrish Sadhukhan } 1003*ad879127SKrish Sadhukhan 1004*ad879127SKrish Sadhukhan tsc_end = rdtsc(); 1005*ad879127SKrish Sadhukhan 1006*ad879127SKrish Sadhukhan return true; 1007*ad879127SKrish Sadhukhan } 1008*ad879127SKrish Sadhukhan 1009*ad879127SKrish Sadhukhan static bool lat_svm_insn_check(struct svm_test *test) 1010*ad879127SKrish Sadhukhan { 1011*ad879127SKrish Sadhukhan printf(" Latency VMLOAD: max: %ld min: %ld avg: %ld\n", latvmload_max, 1012*ad879127SKrish Sadhukhan latvmload_min, vmload_sum / LATENCY_RUNS); 1013*ad879127SKrish Sadhukhan printf(" Latency VMSAVE: max: %ld min: %ld avg: %ld\n", latvmsave_max, 1014*ad879127SKrish Sadhukhan latvmsave_min, vmsave_sum / LATENCY_RUNS); 1015*ad879127SKrish Sadhukhan printf(" Latency STGI: max: %ld min: %ld avg: %ld\n", latstgi_max, 1016*ad879127SKrish Sadhukhan latstgi_min, stgi_sum / LATENCY_RUNS); 1017*ad879127SKrish Sadhukhan printf(" Latency CLGI: max: %ld min: %ld avg: %ld\n", latclgi_max, 1018*ad879127SKrish Sadhukhan latclgi_min, clgi_sum / LATENCY_RUNS); 1019*ad879127SKrish Sadhukhan return true; 1020*ad879127SKrish Sadhukhan } 1021*ad879127SKrish Sadhukhan 1022*ad879127SKrish Sadhukhan bool pending_event_ipi_fired; 1023*ad879127SKrish Sadhukhan bool pending_event_guest_run; 1024*ad879127SKrish Sadhukhan 1025*ad879127SKrish Sadhukhan static void pending_event_ipi_isr(isr_regs_t *regs) 1026*ad879127SKrish Sadhukhan { 1027*ad879127SKrish Sadhukhan pending_event_ipi_fired = true; 1028*ad879127SKrish Sadhukhan eoi(); 1029*ad879127SKrish Sadhukhan } 1030*ad879127SKrish Sadhukhan 1031*ad879127SKrish Sadhukhan static void pending_event_prepare(struct svm_test *test) 1032*ad879127SKrish Sadhukhan { 1033*ad879127SKrish Sadhukhan int ipi_vector = 0xf1; 1034*ad879127SKrish Sadhukhan 1035*ad879127SKrish Sadhukhan default_prepare(test); 1036*ad879127SKrish Sadhukhan 1037*ad879127SKrish Sadhukhan pending_event_ipi_fired = false; 1038*ad879127SKrish Sadhukhan 1039*ad879127SKrish Sadhukhan handle_irq(ipi_vector, pending_event_ipi_isr); 1040*ad879127SKrish Sadhukhan 1041*ad879127SKrish Sadhukhan pending_event_guest_run = false; 1042*ad879127SKrish Sadhukhan 1043*ad879127SKrish Sadhukhan test->vmcb->control.intercept |= (1ULL << INTERCEPT_INTR); 1044*ad879127SKrish Sadhukhan test->vmcb->control.int_ctl |= V_INTR_MASKING_MASK; 1045*ad879127SKrish Sadhukhan 1046*ad879127SKrish Sadhukhan apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | 1047*ad879127SKrish Sadhukhan APIC_DM_FIXED | ipi_vector, 0); 1048*ad879127SKrish Sadhukhan 1049*ad879127SKrish Sadhukhan set_test_stage(test, 0); 1050*ad879127SKrish Sadhukhan } 1051*ad879127SKrish Sadhukhan 1052*ad879127SKrish Sadhukhan static void pending_event_test(struct svm_test *test) 1053*ad879127SKrish Sadhukhan { 1054*ad879127SKrish Sadhukhan pending_event_guest_run = true; 1055*ad879127SKrish Sadhukhan } 1056*ad879127SKrish Sadhukhan 1057*ad879127SKrish Sadhukhan static bool pending_event_finished(struct svm_test *test) 1058*ad879127SKrish Sadhukhan { 1059*ad879127SKrish Sadhukhan switch (get_test_stage(test)) { 1060*ad879127SKrish Sadhukhan case 0: 1061*ad879127SKrish Sadhukhan if (test->vmcb->control.exit_code != SVM_EXIT_INTR) { 1062*ad879127SKrish Sadhukhan report(false, "VMEXIT not due to pending interrupt. Exit reason 0x%x", 1063*ad879127SKrish Sadhukhan test->vmcb->control.exit_code); 1064*ad879127SKrish Sadhukhan return true; 1065*ad879127SKrish Sadhukhan } 1066*ad879127SKrish Sadhukhan 1067*ad879127SKrish Sadhukhan test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR); 1068*ad879127SKrish Sadhukhan test->vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK; 1069*ad879127SKrish Sadhukhan 1070*ad879127SKrish Sadhukhan if (pending_event_guest_run) { 1071*ad879127SKrish Sadhukhan report(false, "Guest ran before host received IPI\n"); 1072*ad879127SKrish Sadhukhan return true; 1073*ad879127SKrish Sadhukhan } 1074*ad879127SKrish Sadhukhan 1075*ad879127SKrish Sadhukhan irq_enable(); 1076*ad879127SKrish Sadhukhan asm volatile ("nop"); 1077*ad879127SKrish Sadhukhan irq_disable(); 1078*ad879127SKrish Sadhukhan 1079*ad879127SKrish Sadhukhan if (!pending_event_ipi_fired) { 1080*ad879127SKrish Sadhukhan report(false, "Pending interrupt not dispatched after IRQ enabled\n"); 1081*ad879127SKrish Sadhukhan return true; 1082*ad879127SKrish Sadhukhan } 1083*ad879127SKrish Sadhukhan break; 1084*ad879127SKrish Sadhukhan 1085*ad879127SKrish Sadhukhan case 1: 1086*ad879127SKrish Sadhukhan if (!pending_event_guest_run) { 1087*ad879127SKrish Sadhukhan report(false, "Guest did not resume when no interrupt\n"); 1088*ad879127SKrish Sadhukhan return true; 1089*ad879127SKrish Sadhukhan } 1090*ad879127SKrish Sadhukhan break; 1091*ad879127SKrish Sadhukhan } 1092*ad879127SKrish Sadhukhan 1093*ad879127SKrish Sadhukhan inc_test_stage(test); 1094*ad879127SKrish Sadhukhan 1095*ad879127SKrish Sadhukhan return get_test_stage(test) == 2; 1096*ad879127SKrish Sadhukhan } 1097*ad879127SKrish Sadhukhan 1098*ad879127SKrish Sadhukhan static bool pending_event_check(struct svm_test *test) 1099*ad879127SKrish Sadhukhan { 1100*ad879127SKrish Sadhukhan return get_test_stage(test) == 2; 1101*ad879127SKrish Sadhukhan } 1102*ad879127SKrish Sadhukhan 1103*ad879127SKrish Sadhukhan static void pending_event_prepare_vmask(struct svm_test *test) 1104*ad879127SKrish Sadhukhan { 1105*ad879127SKrish Sadhukhan default_prepare(test); 1106*ad879127SKrish Sadhukhan 1107*ad879127SKrish Sadhukhan pending_event_ipi_fired = false; 1108*ad879127SKrish Sadhukhan 1109*ad879127SKrish Sadhukhan handle_irq(0xf1, pending_event_ipi_isr); 1110*ad879127SKrish Sadhukhan 1111*ad879127SKrish Sadhukhan apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | 1112*ad879127SKrish Sadhukhan APIC_DM_FIXED | 0xf1, 0); 1113*ad879127SKrish Sadhukhan 1114*ad879127SKrish Sadhukhan set_test_stage(test, 0); 1115*ad879127SKrish Sadhukhan } 1116*ad879127SKrish Sadhukhan 1117*ad879127SKrish Sadhukhan static void pending_event_prepare_gif_clear_vmask(struct svm_test *test) 1118*ad879127SKrish Sadhukhan { 1119*ad879127SKrish Sadhukhan asm("cli"); 1120*ad879127SKrish Sadhukhan } 1121*ad879127SKrish Sadhukhan 1122*ad879127SKrish Sadhukhan static void pending_event_test_vmask(struct svm_test *test) 1123*ad879127SKrish Sadhukhan { 1124*ad879127SKrish Sadhukhan if (pending_event_ipi_fired == true) { 1125*ad879127SKrish Sadhukhan set_test_stage(test, -1); 1126*ad879127SKrish Sadhukhan report(false, "Interrupt preceeded guest"); 1127*ad879127SKrish Sadhukhan vmmcall(); 1128*ad879127SKrish Sadhukhan } 1129*ad879127SKrish Sadhukhan 1130*ad879127SKrish Sadhukhan irq_enable(); 1131*ad879127SKrish Sadhukhan asm volatile ("nop"); 1132*ad879127SKrish Sadhukhan irq_disable(); 1133*ad879127SKrish Sadhukhan 1134*ad879127SKrish Sadhukhan if (pending_event_ipi_fired != true) { 1135*ad879127SKrish Sadhukhan set_test_stage(test, -1); 1136*ad879127SKrish Sadhukhan report(false, "Interrupt not triggered by guest"); 1137*ad879127SKrish Sadhukhan } 1138*ad879127SKrish Sadhukhan 1139*ad879127SKrish Sadhukhan vmmcall(); 1140*ad879127SKrish Sadhukhan 1141*ad879127SKrish Sadhukhan irq_enable(); 1142*ad879127SKrish Sadhukhan asm volatile ("nop"); 1143*ad879127SKrish Sadhukhan irq_disable(); 1144*ad879127SKrish Sadhukhan } 1145*ad879127SKrish Sadhukhan 1146*ad879127SKrish Sadhukhan static bool pending_event_finished_vmask(struct svm_test *test) 1147*ad879127SKrish Sadhukhan { 1148*ad879127SKrish Sadhukhan if ( test->vmcb->control.exit_code != SVM_EXIT_VMMCALL) { 1149*ad879127SKrish Sadhukhan report(false, "VM_EXIT return to host is not EXIT_VMMCALL exit reason 0x%x", 1150*ad879127SKrish Sadhukhan test->vmcb->control.exit_code); 1151*ad879127SKrish Sadhukhan return true; 1152*ad879127SKrish Sadhukhan } 1153*ad879127SKrish Sadhukhan 1154*ad879127SKrish Sadhukhan switch (get_test_stage(test)) { 1155*ad879127SKrish Sadhukhan case 0: 1156*ad879127SKrish Sadhukhan test->vmcb->save.rip += 3; 1157*ad879127SKrish Sadhukhan 1158*ad879127SKrish Sadhukhan pending_event_ipi_fired = false; 1159*ad879127SKrish Sadhukhan 1160*ad879127SKrish Sadhukhan test->vmcb->control.int_ctl |= V_INTR_MASKING_MASK; 1161*ad879127SKrish Sadhukhan 1162*ad879127SKrish Sadhukhan apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | 1163*ad879127SKrish Sadhukhan APIC_DM_FIXED | 0xf1, 0); 1164*ad879127SKrish Sadhukhan 1165*ad879127SKrish Sadhukhan break; 1166*ad879127SKrish Sadhukhan 1167*ad879127SKrish Sadhukhan case 1: 1168*ad879127SKrish Sadhukhan if (pending_event_ipi_fired == true) { 1169*ad879127SKrish Sadhukhan report(false, "Interrupt triggered by guest"); 1170*ad879127SKrish Sadhukhan return true; 1171*ad879127SKrish Sadhukhan } 1172*ad879127SKrish Sadhukhan 1173*ad879127SKrish Sadhukhan irq_enable(); 1174*ad879127SKrish Sadhukhan asm volatile ("nop"); 1175*ad879127SKrish Sadhukhan irq_disable(); 1176*ad879127SKrish Sadhukhan 1177*ad879127SKrish Sadhukhan if (pending_event_ipi_fired != true) { 1178*ad879127SKrish Sadhukhan report(false, "Interrupt not triggered by host"); 1179*ad879127SKrish Sadhukhan return true; 1180*ad879127SKrish Sadhukhan } 1181*ad879127SKrish Sadhukhan 1182*ad879127SKrish Sadhukhan break; 1183*ad879127SKrish Sadhukhan 1184*ad879127SKrish Sadhukhan default: 1185*ad879127SKrish Sadhukhan return true; 1186*ad879127SKrish Sadhukhan } 1187*ad879127SKrish Sadhukhan 1188*ad879127SKrish Sadhukhan inc_test_stage(test); 1189*ad879127SKrish Sadhukhan 1190*ad879127SKrish Sadhukhan return get_test_stage(test) == 2; 1191*ad879127SKrish Sadhukhan } 1192*ad879127SKrish Sadhukhan 1193*ad879127SKrish Sadhukhan static bool pending_event_check_vmask(struct svm_test *test) 1194*ad879127SKrish Sadhukhan { 1195*ad879127SKrish Sadhukhan return get_test_stage(test) == 2; 1196*ad879127SKrish Sadhukhan } 1197*ad879127SKrish Sadhukhan 1198*ad879127SKrish Sadhukhan struct svm_test svm_tests[] = { 1199*ad879127SKrish Sadhukhan { "null", default_supported, default_prepare, 1200*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1201*ad879127SKrish Sadhukhan default_finished, null_check }, 1202*ad879127SKrish Sadhukhan { "vmrun", default_supported, default_prepare, 1203*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_vmrun, 1204*ad879127SKrish Sadhukhan default_finished, check_vmrun }, 1205*ad879127SKrish Sadhukhan { "ioio", default_supported, prepare_ioio, 1206*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_ioio, 1207*ad879127SKrish Sadhukhan ioio_finished, check_ioio }, 1208*ad879127SKrish Sadhukhan { "vmrun intercept check", default_supported, prepare_no_vmrun_int, 1209*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, default_finished, 1210*ad879127SKrish Sadhukhan check_no_vmrun_int }, 1211*ad879127SKrish Sadhukhan { "cr3 read intercept", default_supported, 1212*ad879127SKrish Sadhukhan prepare_cr3_intercept, default_prepare_gif_clear, 1213*ad879127SKrish Sadhukhan test_cr3_intercept, default_finished, check_cr3_intercept }, 1214*ad879127SKrish Sadhukhan { "cr3 read nointercept", default_supported, default_prepare, 1215*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_cr3_intercept, default_finished, 1216*ad879127SKrish Sadhukhan check_cr3_nointercept }, 1217*ad879127SKrish Sadhukhan { "cr3 read intercept emulate", smp_supported, 1218*ad879127SKrish Sadhukhan prepare_cr3_intercept_bypass, default_prepare_gif_clear, 1219*ad879127SKrish Sadhukhan test_cr3_intercept_bypass, default_finished, check_cr3_intercept }, 1220*ad879127SKrish Sadhukhan { "dr intercept check", default_supported, prepare_dr_intercept, 1221*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_dr_intercept, dr_intercept_finished, 1222*ad879127SKrish Sadhukhan check_dr_intercept }, 1223*ad879127SKrish Sadhukhan { "next_rip", next_rip_supported, prepare_next_rip, 1224*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_next_rip, 1225*ad879127SKrish Sadhukhan default_finished, check_next_rip }, 1226*ad879127SKrish Sadhukhan { "msr intercept check", default_supported, prepare_msr_intercept, 1227*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_msr_intercept, 1228*ad879127SKrish Sadhukhan msr_intercept_finished, check_msr_intercept }, 1229*ad879127SKrish Sadhukhan { "mode_switch", default_supported, prepare_mode_switch, 1230*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_mode_switch, 1231*ad879127SKrish Sadhukhan mode_switch_finished, check_mode_switch }, 1232*ad879127SKrish Sadhukhan { "asid_zero", default_supported, prepare_asid_zero, 1233*ad879127SKrish Sadhukhan default_prepare_gif_clear, test_asid_zero, 1234*ad879127SKrish Sadhukhan default_finished, check_asid_zero }, 1235*ad879127SKrish Sadhukhan { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare, 1236*ad879127SKrish Sadhukhan default_prepare_gif_clear, sel_cr0_bug_test, 1237*ad879127SKrish Sadhukhan sel_cr0_bug_finished, sel_cr0_bug_check }, 1238*ad879127SKrish Sadhukhan { "npt_nx", npt_supported, npt_nx_prepare, 1239*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1240*ad879127SKrish Sadhukhan default_finished, npt_nx_check }, 1241*ad879127SKrish Sadhukhan { "npt_us", npt_supported, npt_us_prepare, 1242*ad879127SKrish Sadhukhan default_prepare_gif_clear, npt_us_test, 1243*ad879127SKrish Sadhukhan default_finished, npt_us_check }, 1244*ad879127SKrish Sadhukhan { "npt_rsvd", npt_supported, npt_rsvd_prepare, 1245*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1246*ad879127SKrish Sadhukhan default_finished, npt_rsvd_check }, 1247*ad879127SKrish Sadhukhan { "npt_rw", npt_supported, npt_rw_prepare, 1248*ad879127SKrish Sadhukhan default_prepare_gif_clear, npt_rw_test, 1249*ad879127SKrish Sadhukhan default_finished, npt_rw_check }, 1250*ad879127SKrish Sadhukhan { "npt_rsvd_pfwalk", npt_supported, npt_rsvd_pfwalk_prepare, 1251*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1252*ad879127SKrish Sadhukhan default_finished, npt_rsvd_pfwalk_check }, 1253*ad879127SKrish Sadhukhan { "npt_rw_pfwalk", npt_supported, npt_rw_pfwalk_prepare, 1254*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1255*ad879127SKrish Sadhukhan default_finished, npt_rw_pfwalk_check }, 1256*ad879127SKrish Sadhukhan { "npt_l1mmio", npt_supported, npt_l1mmio_prepare, 1257*ad879127SKrish Sadhukhan default_prepare_gif_clear, npt_l1mmio_test, 1258*ad879127SKrish Sadhukhan default_finished, npt_l1mmio_check }, 1259*ad879127SKrish Sadhukhan { "npt_rw_l1mmio", npt_supported, npt_rw_l1mmio_prepare, 1260*ad879127SKrish Sadhukhan default_prepare_gif_clear, npt_rw_l1mmio_test, 1261*ad879127SKrish Sadhukhan default_finished, npt_rw_l1mmio_check }, 1262*ad879127SKrish Sadhukhan { "tsc_adjust", default_supported, tsc_adjust_prepare, 1263*ad879127SKrish Sadhukhan default_prepare_gif_clear, tsc_adjust_test, 1264*ad879127SKrish Sadhukhan default_finished, tsc_adjust_check }, 1265*ad879127SKrish Sadhukhan { "latency_run_exit", default_supported, latency_prepare, 1266*ad879127SKrish Sadhukhan default_prepare_gif_clear, latency_test, 1267*ad879127SKrish Sadhukhan latency_finished, latency_check }, 1268*ad879127SKrish Sadhukhan { "latency_svm_insn", default_supported, lat_svm_insn_prepare, 1269*ad879127SKrish Sadhukhan default_prepare_gif_clear, null_test, 1270*ad879127SKrish Sadhukhan lat_svm_insn_finished, lat_svm_insn_check }, 1271*ad879127SKrish Sadhukhan { "pending_event", default_supported, pending_event_prepare, 1272*ad879127SKrish Sadhukhan default_prepare_gif_clear, 1273*ad879127SKrish Sadhukhan pending_event_test, pending_event_finished, pending_event_check }, 1274*ad879127SKrish Sadhukhan { "pending_event_vmask", default_supported, pending_event_prepare_vmask, 1275*ad879127SKrish Sadhukhan pending_event_prepare_gif_clear_vmask, 1276*ad879127SKrish Sadhukhan pending_event_test_vmask, pending_event_finished_vmask, 1277*ad879127SKrish Sadhukhan pending_event_check_vmask }, 1278*ad879127SKrish Sadhukhan { NULL, NULL, NULL, NULL, NULL, NULL, NULL } 1279*ad879127SKrish Sadhukhan }; 1280