1*7d36db35SAvi Kivity 2*7d36db35SAvi Kivity #include "libcflat.h" 3*7d36db35SAvi Kivity 4*7d36db35SAvi Kivity #define smp_id() 0 5*7d36db35SAvi Kivity 6*7d36db35SAvi Kivity #define true 1 7*7d36db35SAvi Kivity #define false 0 8*7d36db35SAvi Kivity 9*7d36db35SAvi Kivity static _Bool verbose = false; 10*7d36db35SAvi Kivity 11*7d36db35SAvi Kivity typedef unsigned long pt_element_t; 12*7d36db35SAvi Kivity 13*7d36db35SAvi Kivity #define PAGE_SIZE ((pt_element_t)4096) 14*7d36db35SAvi Kivity #define PAGE_MASK (~(PAGE_SIZE-1)) 15*7d36db35SAvi Kivity 16*7d36db35SAvi Kivity #define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 40) - 1) & PAGE_MASK)) 17*7d36db35SAvi Kivity #define PT_PSE_BASE_ADDR_MASK (PT_BASE_ADDR_MASK & ~(1ull << 21)) 18*7d36db35SAvi Kivity 19*7d36db35SAvi Kivity #define PT_PRESENT_MASK ((pt_element_t)1 << 0) 20*7d36db35SAvi Kivity #define PT_WRITABLE_MASK ((pt_element_t)1 << 1) 21*7d36db35SAvi Kivity #define PT_USER_MASK ((pt_element_t)1 << 2) 22*7d36db35SAvi Kivity #define PT_ACCESSED_MASK ((pt_element_t)1 << 5) 23*7d36db35SAvi Kivity #define PT_DIRTY_MASK ((pt_element_t)1 << 6) 24*7d36db35SAvi Kivity #define PT_PSE_MASK ((pt_element_t)1 << 7) 25*7d36db35SAvi Kivity #define PT_NX_MASK ((pt_element_t)1 << 63) 26*7d36db35SAvi Kivity 27*7d36db35SAvi Kivity #define CR0_WP_MASK (1UL << 16) 28*7d36db35SAvi Kivity 29*7d36db35SAvi Kivity #define PFERR_PRESENT_MASK (1U << 0) 30*7d36db35SAvi Kivity #define PFERR_WRITE_MASK (1U << 1) 31*7d36db35SAvi Kivity #define PFERR_USER_MASK (1U << 2) 32*7d36db35SAvi Kivity #define PFERR_RESERVED_MASK (1U << 3) 33*7d36db35SAvi Kivity #define PFERR_FETCH_MASK (1U << 4) 34*7d36db35SAvi Kivity 35*7d36db35SAvi Kivity #define MSR_EFER 0xc0000080 36*7d36db35SAvi Kivity #define EFER_NX_MASK (1ull << 11) 37*7d36db35SAvi Kivity 38*7d36db35SAvi Kivity /* 39*7d36db35SAvi Kivity * page table access check tests 40*7d36db35SAvi Kivity */ 41*7d36db35SAvi Kivity 42*7d36db35SAvi Kivity enum { 43*7d36db35SAvi Kivity AC_PTE_PRESENT, 44*7d36db35SAvi Kivity AC_PTE_WRITABLE, 45*7d36db35SAvi Kivity AC_PTE_USER, 46*7d36db35SAvi Kivity AC_PTE_ACCESSED, 47*7d36db35SAvi Kivity AC_PTE_DIRTY, 48*7d36db35SAvi Kivity AC_PTE_NX, 49*7d36db35SAvi Kivity AC_PTE_BIT51, 50*7d36db35SAvi Kivity 51*7d36db35SAvi Kivity AC_PDE_PRESENT, 52*7d36db35SAvi Kivity AC_PDE_WRITABLE, 53*7d36db35SAvi Kivity AC_PDE_USER, 54*7d36db35SAvi Kivity AC_PDE_ACCESSED, 55*7d36db35SAvi Kivity AC_PDE_DIRTY, 56*7d36db35SAvi Kivity AC_PDE_PSE, 57*7d36db35SAvi Kivity AC_PDE_NX, 58*7d36db35SAvi Kivity AC_PDE_BIT51, 59*7d36db35SAvi Kivity 60*7d36db35SAvi Kivity AC_ACCESS_USER, 61*7d36db35SAvi Kivity AC_ACCESS_WRITE, 62*7d36db35SAvi Kivity AC_ACCESS_FETCH, 63*7d36db35SAvi Kivity AC_ACCESS_TWICE, 64*7d36db35SAvi Kivity // AC_ACCESS_PTE, 65*7d36db35SAvi Kivity 66*7d36db35SAvi Kivity AC_CPU_EFER_NX, 67*7d36db35SAvi Kivity AC_CPU_CR0_WP, 68*7d36db35SAvi Kivity 69*7d36db35SAvi Kivity NR_AC_FLAGS 70*7d36db35SAvi Kivity }; 71*7d36db35SAvi Kivity 72*7d36db35SAvi Kivity const char *ac_names[] = { 73*7d36db35SAvi Kivity [AC_PTE_PRESENT] = "pte.p", 74*7d36db35SAvi Kivity [AC_PTE_ACCESSED] = "pte.a", 75*7d36db35SAvi Kivity [AC_PTE_WRITABLE] = "pte.rw", 76*7d36db35SAvi Kivity [AC_PTE_USER] = "pte.user", 77*7d36db35SAvi Kivity [AC_PTE_DIRTY] = "pte.d", 78*7d36db35SAvi Kivity [AC_PTE_NX] = "pte.nx", 79*7d36db35SAvi Kivity [AC_PTE_BIT51] = "pte.51", 80*7d36db35SAvi Kivity [AC_PDE_PRESENT] = "pde.p", 81*7d36db35SAvi Kivity [AC_PDE_ACCESSED] = "pde.a", 82*7d36db35SAvi Kivity [AC_PDE_WRITABLE] = "pde.rw", 83*7d36db35SAvi Kivity [AC_PDE_USER] = "pde.user", 84*7d36db35SAvi Kivity [AC_PDE_DIRTY] = "pde.d", 85*7d36db35SAvi Kivity [AC_PDE_PSE] = "pde.pse", 86*7d36db35SAvi Kivity [AC_PDE_NX] = "pde.nx", 87*7d36db35SAvi Kivity [AC_PDE_BIT51] = "pde.51", 88*7d36db35SAvi Kivity [AC_ACCESS_WRITE] = "write", 89*7d36db35SAvi Kivity [AC_ACCESS_USER] = "user", 90*7d36db35SAvi Kivity [AC_ACCESS_FETCH] = "fetch", 91*7d36db35SAvi Kivity [AC_ACCESS_TWICE] = "twice", 92*7d36db35SAvi Kivity [AC_CPU_EFER_NX] = "efer.nx", 93*7d36db35SAvi Kivity [AC_CPU_CR0_WP] = "cr0.wp", 94*7d36db35SAvi Kivity }; 95*7d36db35SAvi Kivity 96*7d36db35SAvi Kivity static inline void *va(pt_element_t phys) 97*7d36db35SAvi Kivity { 98*7d36db35SAvi Kivity return (void *)phys; 99*7d36db35SAvi Kivity } 100*7d36db35SAvi Kivity 101*7d36db35SAvi Kivity static unsigned long read_cr0() 102*7d36db35SAvi Kivity { 103*7d36db35SAvi Kivity unsigned long cr0; 104*7d36db35SAvi Kivity 105*7d36db35SAvi Kivity asm volatile ("mov %%cr0, %0" : "=r"(cr0)); 106*7d36db35SAvi Kivity 107*7d36db35SAvi Kivity return cr0; 108*7d36db35SAvi Kivity } 109*7d36db35SAvi Kivity 110*7d36db35SAvi Kivity static void write_cr0(unsigned long cr0) 111*7d36db35SAvi Kivity { 112*7d36db35SAvi Kivity asm volatile ("mov %0, %%cr0" : : "r"(cr0)); 113*7d36db35SAvi Kivity } 114*7d36db35SAvi Kivity 115*7d36db35SAvi Kivity typedef struct { 116*7d36db35SAvi Kivity unsigned short offset0; 117*7d36db35SAvi Kivity unsigned short selector; 118*7d36db35SAvi Kivity unsigned short ist : 3; 119*7d36db35SAvi Kivity unsigned short : 5; 120*7d36db35SAvi Kivity unsigned short type : 4; 121*7d36db35SAvi Kivity unsigned short : 1; 122*7d36db35SAvi Kivity unsigned short dpl : 2; 123*7d36db35SAvi Kivity unsigned short p : 1; 124*7d36db35SAvi Kivity unsigned short offset1; 125*7d36db35SAvi Kivity unsigned offset2; 126*7d36db35SAvi Kivity unsigned reserved; 127*7d36db35SAvi Kivity } idt_entry_t; 128*7d36db35SAvi Kivity 129*7d36db35SAvi Kivity typedef struct { 130*7d36db35SAvi Kivity pt_element_t pt_pool; 131*7d36db35SAvi Kivity unsigned pt_pool_size; 132*7d36db35SAvi Kivity unsigned pt_pool_current; 133*7d36db35SAvi Kivity } ac_pool_t; 134*7d36db35SAvi Kivity 135*7d36db35SAvi Kivity typedef struct { 136*7d36db35SAvi Kivity unsigned flags[NR_AC_FLAGS]; 137*7d36db35SAvi Kivity void *virt; 138*7d36db35SAvi Kivity pt_element_t phys; 139*7d36db35SAvi Kivity pt_element_t *ptep; 140*7d36db35SAvi Kivity pt_element_t expected_pte; 141*7d36db35SAvi Kivity pt_element_t *pdep; 142*7d36db35SAvi Kivity pt_element_t expected_pde; 143*7d36db35SAvi Kivity pt_element_t ignore_pde; 144*7d36db35SAvi Kivity int expected_fault; 145*7d36db35SAvi Kivity unsigned expected_error; 146*7d36db35SAvi Kivity idt_entry_t idt[256]; 147*7d36db35SAvi Kivity } ac_test_t; 148*7d36db35SAvi Kivity 149*7d36db35SAvi Kivity typedef struct { 150*7d36db35SAvi Kivity unsigned short limit; 151*7d36db35SAvi Kivity unsigned long linear_addr; 152*7d36db35SAvi Kivity } __attribute__((packed)) descriptor_table_t; 153*7d36db35SAvi Kivity 154*7d36db35SAvi Kivity 155*7d36db35SAvi Kivity static void ac_test_show(ac_test_t *at); 156*7d36db35SAvi Kivity 157*7d36db35SAvi Kivity void lidt(idt_entry_t *idt, int nentries) 158*7d36db35SAvi Kivity { 159*7d36db35SAvi Kivity descriptor_table_t dt; 160*7d36db35SAvi Kivity 161*7d36db35SAvi Kivity dt.limit = nentries * sizeof(*idt) - 1; 162*7d36db35SAvi Kivity dt.linear_addr = (unsigned long)idt; 163*7d36db35SAvi Kivity asm volatile ("lidt %0" : : "m"(dt)); 164*7d36db35SAvi Kivity } 165*7d36db35SAvi Kivity 166*7d36db35SAvi Kivity unsigned short read_cs() 167*7d36db35SAvi Kivity { 168*7d36db35SAvi Kivity unsigned short r; 169*7d36db35SAvi Kivity 170*7d36db35SAvi Kivity asm volatile ("mov %%cs, %0" : "=r"(r)); 171*7d36db35SAvi Kivity return r; 172*7d36db35SAvi Kivity } 173*7d36db35SAvi Kivity 174*7d36db35SAvi Kivity unsigned long long rdmsr(unsigned index) 175*7d36db35SAvi Kivity { 176*7d36db35SAvi Kivity unsigned a, d; 177*7d36db35SAvi Kivity 178*7d36db35SAvi Kivity asm volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(index)); 179*7d36db35SAvi Kivity return ((unsigned long long)d << 32) | a; 180*7d36db35SAvi Kivity } 181*7d36db35SAvi Kivity 182*7d36db35SAvi Kivity void wrmsr(unsigned index, unsigned long long val) 183*7d36db35SAvi Kivity { 184*7d36db35SAvi Kivity unsigned a = val, d = val >> 32; 185*7d36db35SAvi Kivity 186*7d36db35SAvi Kivity asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(index)); 187*7d36db35SAvi Kivity } 188*7d36db35SAvi Kivity 189*7d36db35SAvi Kivity void set_idt_entry(idt_entry_t *e, void *addr, int dpl) 190*7d36db35SAvi Kivity { 191*7d36db35SAvi Kivity memset(e, 0, sizeof *e); 192*7d36db35SAvi Kivity e->offset0 = (unsigned long)addr; 193*7d36db35SAvi Kivity e->selector = read_cs(); 194*7d36db35SAvi Kivity e->ist = 0; 195*7d36db35SAvi Kivity e->type = 14; 196*7d36db35SAvi Kivity e->dpl = dpl; 197*7d36db35SAvi Kivity e->p = 1; 198*7d36db35SAvi Kivity e->offset1 = (unsigned long)addr >> 16; 199*7d36db35SAvi Kivity e->offset2 = (unsigned long)addr >> 32; 200*7d36db35SAvi Kivity } 201*7d36db35SAvi Kivity 202*7d36db35SAvi Kivity void set_cr0_wp(int wp) 203*7d36db35SAvi Kivity { 204*7d36db35SAvi Kivity unsigned long cr0 = read_cr0(); 205*7d36db35SAvi Kivity 206*7d36db35SAvi Kivity cr0 &= ~CR0_WP_MASK; 207*7d36db35SAvi Kivity if (wp) 208*7d36db35SAvi Kivity cr0 |= CR0_WP_MASK; 209*7d36db35SAvi Kivity write_cr0(cr0); 210*7d36db35SAvi Kivity } 211*7d36db35SAvi Kivity 212*7d36db35SAvi Kivity void set_efer_nx(int nx) 213*7d36db35SAvi Kivity { 214*7d36db35SAvi Kivity unsigned long long efer; 215*7d36db35SAvi Kivity 216*7d36db35SAvi Kivity efer = rdmsr(MSR_EFER); 217*7d36db35SAvi Kivity efer &= ~EFER_NX_MASK; 218*7d36db35SAvi Kivity if (nx) 219*7d36db35SAvi Kivity efer |= EFER_NX_MASK; 220*7d36db35SAvi Kivity wrmsr(MSR_EFER, efer); 221*7d36db35SAvi Kivity } 222*7d36db35SAvi Kivity 223*7d36db35SAvi Kivity static void ac_env_int(ac_pool_t *pool) 224*7d36db35SAvi Kivity { 225*7d36db35SAvi Kivity static idt_entry_t idt[256]; 226*7d36db35SAvi Kivity 227*7d36db35SAvi Kivity memset(idt, 0, sizeof(idt)); 228*7d36db35SAvi Kivity lidt(idt, 256); 229*7d36db35SAvi Kivity extern char page_fault, kernel_entry; 230*7d36db35SAvi Kivity set_idt_entry(&idt[14], &page_fault, 0); 231*7d36db35SAvi Kivity set_idt_entry(&idt[0x20], &kernel_entry, 3); 232*7d36db35SAvi Kivity 233*7d36db35SAvi Kivity pool->pt_pool = 33 * 1024 * 1024; 234*7d36db35SAvi Kivity pool->pt_pool_size = 120 * 1024 * 1024 - pool->pt_pool; 235*7d36db35SAvi Kivity pool->pt_pool_current = 0; 236*7d36db35SAvi Kivity } 237*7d36db35SAvi Kivity 238*7d36db35SAvi Kivity void ac_test_init(ac_test_t *at, void *virt) 239*7d36db35SAvi Kivity { 240*7d36db35SAvi Kivity wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); 241*7d36db35SAvi Kivity set_cr0_wp(1); 242*7d36db35SAvi Kivity for (int i = 0; i < NR_AC_FLAGS; ++i) 243*7d36db35SAvi Kivity at->flags[i] = 0; 244*7d36db35SAvi Kivity at->virt = virt; 245*7d36db35SAvi Kivity at->phys = 32 * 1024 * 1024; 246*7d36db35SAvi Kivity } 247*7d36db35SAvi Kivity 248*7d36db35SAvi Kivity int ac_test_bump_one(ac_test_t *at) 249*7d36db35SAvi Kivity { 250*7d36db35SAvi Kivity for (int i = 0; i < NR_AC_FLAGS; ++i) 251*7d36db35SAvi Kivity if (!at->flags[i]) { 252*7d36db35SAvi Kivity at->flags[i] = 1; 253*7d36db35SAvi Kivity return 1; 254*7d36db35SAvi Kivity } else 255*7d36db35SAvi Kivity at->flags[i] = 0; 256*7d36db35SAvi Kivity return 0; 257*7d36db35SAvi Kivity } 258*7d36db35SAvi Kivity 259*7d36db35SAvi Kivity _Bool ac_test_legal(ac_test_t *at) 260*7d36db35SAvi Kivity { 261*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_ACCESS_WRITE]) 262*7d36db35SAvi Kivity return false; 263*7d36db35SAvi Kivity return true; 264*7d36db35SAvi Kivity } 265*7d36db35SAvi Kivity 266*7d36db35SAvi Kivity int ac_test_bump(ac_test_t *at) 267*7d36db35SAvi Kivity { 268*7d36db35SAvi Kivity int ret; 269*7d36db35SAvi Kivity 270*7d36db35SAvi Kivity ret = ac_test_bump_one(at); 271*7d36db35SAvi Kivity while (ret && !ac_test_legal(at)) 272*7d36db35SAvi Kivity ret = ac_test_bump_one(at); 273*7d36db35SAvi Kivity return ret; 274*7d36db35SAvi Kivity } 275*7d36db35SAvi Kivity 276*7d36db35SAvi Kivity unsigned long read_cr3() 277*7d36db35SAvi Kivity { 278*7d36db35SAvi Kivity unsigned long cr3; 279*7d36db35SAvi Kivity 280*7d36db35SAvi Kivity asm volatile ("mov %%cr3, %0" : "=r"(cr3)); 281*7d36db35SAvi Kivity return cr3; 282*7d36db35SAvi Kivity } 283*7d36db35SAvi Kivity 284*7d36db35SAvi Kivity void invlpg(void *addr) 285*7d36db35SAvi Kivity { 286*7d36db35SAvi Kivity asm volatile ("invlpg (%0)" : : "r"(addr)); 287*7d36db35SAvi Kivity } 288*7d36db35SAvi Kivity 289*7d36db35SAvi Kivity pt_element_t ac_test_alloc_pt(ac_pool_t *pool) 290*7d36db35SAvi Kivity { 291*7d36db35SAvi Kivity pt_element_t ret = pool->pt_pool + pool->pt_pool_current; 292*7d36db35SAvi Kivity pool->pt_pool_current += PAGE_SIZE; 293*7d36db35SAvi Kivity return ret; 294*7d36db35SAvi Kivity } 295*7d36db35SAvi Kivity 296*7d36db35SAvi Kivity _Bool ac_test_enough_room(ac_pool_t *pool) 297*7d36db35SAvi Kivity { 298*7d36db35SAvi Kivity return pool->pt_pool_current + 4 * PAGE_SIZE <= pool->pt_pool_size; 299*7d36db35SAvi Kivity } 300*7d36db35SAvi Kivity 301*7d36db35SAvi Kivity void ac_test_reset_pt_pool(ac_pool_t *pool) 302*7d36db35SAvi Kivity { 303*7d36db35SAvi Kivity pool->pt_pool_current = 0; 304*7d36db35SAvi Kivity } 305*7d36db35SAvi Kivity 306*7d36db35SAvi Kivity void ac_set_expected_status(ac_test_t *at) 307*7d36db35SAvi Kivity { 308*7d36db35SAvi Kivity int pde_valid, pte_valid; 309*7d36db35SAvi Kivity 310*7d36db35SAvi Kivity invlpg(at->virt); 311*7d36db35SAvi Kivity 312*7d36db35SAvi Kivity if (at->ptep) 313*7d36db35SAvi Kivity at->expected_pte = *at->ptep; 314*7d36db35SAvi Kivity at->expected_pde = *at->pdep; 315*7d36db35SAvi Kivity at->ignore_pde = 0; 316*7d36db35SAvi Kivity at->expected_fault = 0; 317*7d36db35SAvi Kivity at->expected_error = PFERR_PRESENT_MASK; 318*7d36db35SAvi Kivity 319*7d36db35SAvi Kivity pde_valid = at->flags[AC_PDE_PRESENT] 320*7d36db35SAvi Kivity && !at->flags[AC_PDE_BIT51] 321*7d36db35SAvi Kivity && !(at->flags[AC_PDE_NX] && !at->flags[AC_CPU_EFER_NX]); 322*7d36db35SAvi Kivity pte_valid = pde_valid 323*7d36db35SAvi Kivity && at->flags[AC_PTE_PRESENT] 324*7d36db35SAvi Kivity && !at->flags[AC_PTE_BIT51] 325*7d36db35SAvi Kivity && !(at->flags[AC_PTE_NX] && !at->flags[AC_CPU_EFER_NX]); 326*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_TWICE]) { 327*7d36db35SAvi Kivity if (pde_valid) { 328*7d36db35SAvi Kivity at->expected_pde |= PT_ACCESSED_MASK; 329*7d36db35SAvi Kivity if (pte_valid) 330*7d36db35SAvi Kivity at->expected_pte |= PT_ACCESSED_MASK; 331*7d36db35SAvi Kivity } 332*7d36db35SAvi Kivity } 333*7d36db35SAvi Kivity 334*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_USER]) 335*7d36db35SAvi Kivity at->expected_error |= PFERR_USER_MASK; 336*7d36db35SAvi Kivity 337*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_WRITE]) 338*7d36db35SAvi Kivity at->expected_error |= PFERR_WRITE_MASK; 339*7d36db35SAvi Kivity 340*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_FETCH]) 341*7d36db35SAvi Kivity at->expected_error |= PFERR_FETCH_MASK; 342*7d36db35SAvi Kivity 343*7d36db35SAvi Kivity if (!at->flags[AC_PDE_PRESENT]) { 344*7d36db35SAvi Kivity at->expected_fault = 1; 345*7d36db35SAvi Kivity at->expected_error &= ~PFERR_PRESENT_MASK; 346*7d36db35SAvi Kivity } else if (!pde_valid) { 347*7d36db35SAvi Kivity at->expected_fault = 1; 348*7d36db35SAvi Kivity at->expected_error |= PFERR_RESERVED_MASK; 349*7d36db35SAvi Kivity } 350*7d36db35SAvi Kivity 351*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_USER] && !at->flags[AC_PDE_USER]) 352*7d36db35SAvi Kivity at->expected_fault = 1; 353*7d36db35SAvi Kivity 354*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_WRITE] 355*7d36db35SAvi Kivity && !at->flags[AC_PDE_WRITABLE] 356*7d36db35SAvi Kivity && (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER])) 357*7d36db35SAvi Kivity at->expected_fault = 1; 358*7d36db35SAvi Kivity 359*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_PDE_NX]) 360*7d36db35SAvi Kivity at->expected_fault = 1; 361*7d36db35SAvi Kivity 362*7d36db35SAvi Kivity if (!at->flags[AC_PDE_ACCESSED]) 363*7d36db35SAvi Kivity at->ignore_pde = PT_ACCESSED_MASK; 364*7d36db35SAvi Kivity 365*7d36db35SAvi Kivity if (!pde_valid) 366*7d36db35SAvi Kivity goto fault; 367*7d36db35SAvi Kivity 368*7d36db35SAvi Kivity if (!at->expected_fault) 369*7d36db35SAvi Kivity at->expected_pde |= PT_ACCESSED_MASK; 370*7d36db35SAvi Kivity 371*7d36db35SAvi Kivity if (at->flags[AC_PDE_PSE]) { 372*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_WRITE] && !at->expected_fault) 373*7d36db35SAvi Kivity at->expected_pde |= PT_DIRTY_MASK; 374*7d36db35SAvi Kivity goto no_pte; 375*7d36db35SAvi Kivity } 376*7d36db35SAvi Kivity 377*7d36db35SAvi Kivity if (!at->flags[AC_PTE_PRESENT]) { 378*7d36db35SAvi Kivity at->expected_fault = 1; 379*7d36db35SAvi Kivity at->expected_error &= ~PFERR_PRESENT_MASK; 380*7d36db35SAvi Kivity } else if (!pte_valid) { 381*7d36db35SAvi Kivity at->expected_fault = 1; 382*7d36db35SAvi Kivity at->expected_error |= PFERR_RESERVED_MASK; 383*7d36db35SAvi Kivity } 384*7d36db35SAvi Kivity 385*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_USER] && !at->flags[AC_PTE_USER]) 386*7d36db35SAvi Kivity at->expected_fault = 1; 387*7d36db35SAvi Kivity 388*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_WRITE] 389*7d36db35SAvi Kivity && !at->flags[AC_PTE_WRITABLE] 390*7d36db35SAvi Kivity && (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER])) 391*7d36db35SAvi Kivity at->expected_fault = 1; 392*7d36db35SAvi Kivity 393*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_PTE_NX]) 394*7d36db35SAvi Kivity at->expected_fault = 1; 395*7d36db35SAvi Kivity 396*7d36db35SAvi Kivity if (at->expected_fault) 397*7d36db35SAvi Kivity goto fault; 398*7d36db35SAvi Kivity 399*7d36db35SAvi Kivity at->expected_pte |= PT_ACCESSED_MASK; 400*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_WRITE]) 401*7d36db35SAvi Kivity at->expected_pte |= PT_DIRTY_MASK; 402*7d36db35SAvi Kivity 403*7d36db35SAvi Kivity no_pte: 404*7d36db35SAvi Kivity fault: 405*7d36db35SAvi Kivity if (!at->expected_fault) 406*7d36db35SAvi Kivity at->ignore_pde = 0; 407*7d36db35SAvi Kivity if (!at->flags[AC_CPU_EFER_NX]) 408*7d36db35SAvi Kivity at->expected_error &= ~PFERR_FETCH_MASK; 409*7d36db35SAvi Kivity } 410*7d36db35SAvi Kivity 411*7d36db35SAvi Kivity void ac_test_setup_pte(ac_test_t *at, ac_pool_t *pool) 412*7d36db35SAvi Kivity { 413*7d36db35SAvi Kivity unsigned long root = read_cr3(); 414*7d36db35SAvi Kivity 415*7d36db35SAvi Kivity if (!ac_test_enough_room(pool)) 416*7d36db35SAvi Kivity ac_test_reset_pt_pool(pool); 417*7d36db35SAvi Kivity 418*7d36db35SAvi Kivity at->ptep = 0; 419*7d36db35SAvi Kivity for (int i = 4; i >= 1 && (i >= 2 || !at->flags[AC_PDE_PSE]); --i) { 420*7d36db35SAvi Kivity pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK); 421*7d36db35SAvi Kivity unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511; 422*7d36db35SAvi Kivity pt_element_t pte = 0; 423*7d36db35SAvi Kivity switch (i) { 424*7d36db35SAvi Kivity case 4: 425*7d36db35SAvi Kivity case 3: 426*7d36db35SAvi Kivity pte = vroot[index]; 427*7d36db35SAvi Kivity pte = ac_test_alloc_pt(pool) | PT_PRESENT_MASK; 428*7d36db35SAvi Kivity pte |= PT_WRITABLE_MASK | PT_USER_MASK; 429*7d36db35SAvi Kivity break; 430*7d36db35SAvi Kivity case 2: 431*7d36db35SAvi Kivity if (!at->flags[AC_PDE_PSE]) 432*7d36db35SAvi Kivity pte = ac_test_alloc_pt(pool); 433*7d36db35SAvi Kivity else { 434*7d36db35SAvi Kivity pte = at->phys & PT_PSE_BASE_ADDR_MASK; 435*7d36db35SAvi Kivity pte |= PT_PSE_MASK; 436*7d36db35SAvi Kivity } 437*7d36db35SAvi Kivity if (at->flags[AC_PDE_PRESENT]) 438*7d36db35SAvi Kivity pte |= PT_PRESENT_MASK; 439*7d36db35SAvi Kivity if (at->flags[AC_PDE_WRITABLE]) 440*7d36db35SAvi Kivity pte |= PT_WRITABLE_MASK; 441*7d36db35SAvi Kivity if (at->flags[AC_PDE_USER]) 442*7d36db35SAvi Kivity pte |= PT_USER_MASK; 443*7d36db35SAvi Kivity if (at->flags[AC_PDE_ACCESSED]) 444*7d36db35SAvi Kivity pte |= PT_ACCESSED_MASK; 445*7d36db35SAvi Kivity if (at->flags[AC_PDE_DIRTY]) 446*7d36db35SAvi Kivity pte |= PT_DIRTY_MASK; 447*7d36db35SAvi Kivity if (at->flags[AC_PDE_NX]) 448*7d36db35SAvi Kivity pte |= PT_NX_MASK; 449*7d36db35SAvi Kivity if (at->flags[AC_PDE_BIT51]) 450*7d36db35SAvi Kivity pte |= 1ull << 51; 451*7d36db35SAvi Kivity at->pdep = &vroot[index]; 452*7d36db35SAvi Kivity break; 453*7d36db35SAvi Kivity case 1: 454*7d36db35SAvi Kivity pte = at->phys & PT_BASE_ADDR_MASK; 455*7d36db35SAvi Kivity if (at->flags[AC_PTE_PRESENT]) 456*7d36db35SAvi Kivity pte |= PT_PRESENT_MASK; 457*7d36db35SAvi Kivity if (at->flags[AC_PTE_WRITABLE]) 458*7d36db35SAvi Kivity pte |= PT_WRITABLE_MASK; 459*7d36db35SAvi Kivity if (at->flags[AC_PTE_USER]) 460*7d36db35SAvi Kivity pte |= PT_USER_MASK; 461*7d36db35SAvi Kivity if (at->flags[AC_PTE_ACCESSED]) 462*7d36db35SAvi Kivity pte |= PT_ACCESSED_MASK; 463*7d36db35SAvi Kivity if (at->flags[AC_PTE_DIRTY]) 464*7d36db35SAvi Kivity pte |= PT_DIRTY_MASK; 465*7d36db35SAvi Kivity if (at->flags[AC_PTE_NX]) 466*7d36db35SAvi Kivity pte |= PT_NX_MASK; 467*7d36db35SAvi Kivity if (at->flags[AC_PTE_BIT51]) 468*7d36db35SAvi Kivity pte |= 1ull << 51; 469*7d36db35SAvi Kivity at->ptep = &vroot[index]; 470*7d36db35SAvi Kivity break; 471*7d36db35SAvi Kivity } 472*7d36db35SAvi Kivity vroot[index] = pte; 473*7d36db35SAvi Kivity root = vroot[index]; 474*7d36db35SAvi Kivity } 475*7d36db35SAvi Kivity ac_set_expected_status(at); 476*7d36db35SAvi Kivity } 477*7d36db35SAvi Kivity 478*7d36db35SAvi Kivity static void ac_test_check(ac_test_t *at, _Bool *success_ret, _Bool cond, 479*7d36db35SAvi Kivity const char *fmt, ...) 480*7d36db35SAvi Kivity { 481*7d36db35SAvi Kivity va_list ap; 482*7d36db35SAvi Kivity char buf[500]; 483*7d36db35SAvi Kivity 484*7d36db35SAvi Kivity if (!*success_ret) { 485*7d36db35SAvi Kivity return; 486*7d36db35SAvi Kivity } 487*7d36db35SAvi Kivity 488*7d36db35SAvi Kivity if (!cond) { 489*7d36db35SAvi Kivity return; 490*7d36db35SAvi Kivity } 491*7d36db35SAvi Kivity 492*7d36db35SAvi Kivity *success_ret = false; 493*7d36db35SAvi Kivity 494*7d36db35SAvi Kivity if (!verbose) { 495*7d36db35SAvi Kivity ac_test_show(at); 496*7d36db35SAvi Kivity } 497*7d36db35SAvi Kivity 498*7d36db35SAvi Kivity va_start(ap, fmt); 499*7d36db35SAvi Kivity vsnprintf(buf, sizeof(buf), fmt, ap); 500*7d36db35SAvi Kivity va_end(ap); 501*7d36db35SAvi Kivity printf("FAIL: %s\n", buf); 502*7d36db35SAvi Kivity } 503*7d36db35SAvi Kivity 504*7d36db35SAvi Kivity static int pt_match(pt_element_t pte1, pt_element_t pte2, pt_element_t ignore) 505*7d36db35SAvi Kivity { 506*7d36db35SAvi Kivity pte1 &= ~ignore; 507*7d36db35SAvi Kivity pte2 &= ~ignore; 508*7d36db35SAvi Kivity return pte1 == pte2; 509*7d36db35SAvi Kivity } 510*7d36db35SAvi Kivity 511*7d36db35SAvi Kivity int ac_test_do_access(ac_test_t *at) 512*7d36db35SAvi Kivity { 513*7d36db35SAvi Kivity static unsigned unique = 42; 514*7d36db35SAvi Kivity int fault = 0; 515*7d36db35SAvi Kivity unsigned e; 516*7d36db35SAvi Kivity static unsigned char user_stack[4096]; 517*7d36db35SAvi Kivity unsigned long rsp; 518*7d36db35SAvi Kivity _Bool success = true; 519*7d36db35SAvi Kivity 520*7d36db35SAvi Kivity ++unique; 521*7d36db35SAvi Kivity 522*7d36db35SAvi Kivity *((unsigned char *)at->phys) = 0xc3; /* ret */ 523*7d36db35SAvi Kivity 524*7d36db35SAvi Kivity unsigned r = unique; 525*7d36db35SAvi Kivity set_cr0_wp(at->flags[AC_CPU_CR0_WP]); 526*7d36db35SAvi Kivity set_efer_nx(at->flags[AC_CPU_EFER_NX]); 527*7d36db35SAvi Kivity 528*7d36db35SAvi Kivity if (at->flags[AC_ACCESS_TWICE]) { 529*7d36db35SAvi Kivity asm volatile ( 530*7d36db35SAvi Kivity "mov $fixed2, %%rsi \n\t" 531*7d36db35SAvi Kivity "mov (%[addr]), %[reg] \n\t" 532*7d36db35SAvi Kivity "fixed2:" 533*7d36db35SAvi Kivity : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e) 534*7d36db35SAvi Kivity : [addr]"r"(at->virt) 535*7d36db35SAvi Kivity : "rsi" 536*7d36db35SAvi Kivity ); 537*7d36db35SAvi Kivity fault = 0; 538*7d36db35SAvi Kivity } 539*7d36db35SAvi Kivity 540*7d36db35SAvi Kivity asm volatile ("mov $fixed1, %%rsi \n\t" 541*7d36db35SAvi Kivity "mov %%rsp, %%rdx \n\t" 542*7d36db35SAvi Kivity "cmp $0, %[user] \n\t" 543*7d36db35SAvi Kivity "jz do_access \n\t" 544*7d36db35SAvi Kivity "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax \n\t" 545*7d36db35SAvi Kivity "pushq %[user_ds] \n\t" 546*7d36db35SAvi Kivity "pushq %[user_stack_top] \n\t" 547*7d36db35SAvi Kivity "pushfq \n\t" 548*7d36db35SAvi Kivity "pushq %[user_cs] \n\t" 549*7d36db35SAvi Kivity "pushq $do_access \n\t" 550*7d36db35SAvi Kivity "iretq \n" 551*7d36db35SAvi Kivity "do_access: \n\t" 552*7d36db35SAvi Kivity "cmp $0, %[fetch] \n\t" 553*7d36db35SAvi Kivity "jnz 2f \n\t" 554*7d36db35SAvi Kivity "cmp $0, %[write] \n\t" 555*7d36db35SAvi Kivity "jnz 1f \n\t" 556*7d36db35SAvi Kivity "mov (%[addr]), %[reg] \n\t" 557*7d36db35SAvi Kivity "jmp done \n\t" 558*7d36db35SAvi Kivity "1: mov %[reg], (%[addr]) \n\t" 559*7d36db35SAvi Kivity "jmp done \n\t" 560*7d36db35SAvi Kivity "2: call *%[addr] \n\t" 561*7d36db35SAvi Kivity "done: \n" 562*7d36db35SAvi Kivity "fixed1: \n" 563*7d36db35SAvi Kivity "int %[kernel_entry_vector] \n\t" 564*7d36db35SAvi Kivity "back_to_kernel:" 565*7d36db35SAvi Kivity : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp) 566*7d36db35SAvi Kivity : [addr]"r"(at->virt), 567*7d36db35SAvi Kivity [write]"r"(at->flags[AC_ACCESS_WRITE]), 568*7d36db35SAvi Kivity [user]"r"(at->flags[AC_ACCESS_USER]), 569*7d36db35SAvi Kivity [fetch]"r"(at->flags[AC_ACCESS_FETCH]), 570*7d36db35SAvi Kivity [user_ds]"i"(32+3), 571*7d36db35SAvi Kivity [user_cs]"i"(24+3), 572*7d36db35SAvi Kivity [user_stack_top]"r"(user_stack + sizeof user_stack), 573*7d36db35SAvi Kivity [kernel_entry_vector]"i"(0x20) 574*7d36db35SAvi Kivity : "rsi"); 575*7d36db35SAvi Kivity 576*7d36db35SAvi Kivity asm volatile (".section .text.pf \n\t" 577*7d36db35SAvi Kivity "page_fault: \n\t" 578*7d36db35SAvi Kivity "pop %rbx \n\t" 579*7d36db35SAvi Kivity "mov %rsi, (%rsp) \n\t" 580*7d36db35SAvi Kivity "movl $1, %eax \n\t" 581*7d36db35SAvi Kivity "iretq \n\t" 582*7d36db35SAvi Kivity ".section .text"); 583*7d36db35SAvi Kivity 584*7d36db35SAvi Kivity asm volatile (".section .text.entry \n\t" 585*7d36db35SAvi Kivity "kernel_entry: \n\t" 586*7d36db35SAvi Kivity "mov %rdx, %rsp \n\t" 587*7d36db35SAvi Kivity "jmp back_to_kernel \n\t" 588*7d36db35SAvi Kivity ".section .text"); 589*7d36db35SAvi Kivity 590*7d36db35SAvi Kivity ac_test_check(at, &success, fault && !at->expected_fault, 591*7d36db35SAvi Kivity "unexpected fault"); 592*7d36db35SAvi Kivity ac_test_check(at, &success, !fault && at->expected_fault, 593*7d36db35SAvi Kivity "unexpected access"); 594*7d36db35SAvi Kivity ac_test_check(at, &success, fault && e != at->expected_error, 595*7d36db35SAvi Kivity "error code %x expected %x", e, at->expected_error); 596*7d36db35SAvi Kivity ac_test_check(at, &success, at->ptep && *at->ptep != at->expected_pte, 597*7d36db35SAvi Kivity "pte %x expected %x", *at->ptep, at->expected_pte); 598*7d36db35SAvi Kivity ac_test_check(at, &success, 599*7d36db35SAvi Kivity !pt_match(*at->pdep, at->expected_pde, at->ignore_pde), 600*7d36db35SAvi Kivity "pde %x expected %x", *at->pdep, at->expected_pde); 601*7d36db35SAvi Kivity 602*7d36db35SAvi Kivity if (success && verbose) { 603*7d36db35SAvi Kivity printf("PASS\n"); 604*7d36db35SAvi Kivity } 605*7d36db35SAvi Kivity return success; 606*7d36db35SAvi Kivity } 607*7d36db35SAvi Kivity 608*7d36db35SAvi Kivity static void ac_test_show(ac_test_t *at) 609*7d36db35SAvi Kivity { 610*7d36db35SAvi Kivity char line[5000]; 611*7d36db35SAvi Kivity 612*7d36db35SAvi Kivity *line = 0; 613*7d36db35SAvi Kivity strcat(line, "test"); 614*7d36db35SAvi Kivity for (int i = 0; i < NR_AC_FLAGS; ++i) 615*7d36db35SAvi Kivity if (at->flags[i]) { 616*7d36db35SAvi Kivity strcat(line, " "); 617*7d36db35SAvi Kivity strcat(line, ac_names[i]); 618*7d36db35SAvi Kivity } 619*7d36db35SAvi Kivity strcat(line, ": "); 620*7d36db35SAvi Kivity printf("%s", line); 621*7d36db35SAvi Kivity } 622*7d36db35SAvi Kivity 623*7d36db35SAvi Kivity /* 624*7d36db35SAvi Kivity * This test case is used to triger the bug which is fixed by 625*7d36db35SAvi Kivity * commit e09e90a5 in the kvm tree 626*7d36db35SAvi Kivity */ 627*7d36db35SAvi Kivity static int corrupt_hugepage_triger(ac_pool_t *pool) 628*7d36db35SAvi Kivity { 629*7d36db35SAvi Kivity ac_test_t at1, at2; 630*7d36db35SAvi Kivity 631*7d36db35SAvi Kivity ac_test_init(&at1, (void *)(0x123400000000)); 632*7d36db35SAvi Kivity ac_test_init(&at2, (void *)(0x666600000000)); 633*7d36db35SAvi Kivity 634*7d36db35SAvi Kivity at2.flags[AC_CPU_CR0_WP] = 1; 635*7d36db35SAvi Kivity at2.flags[AC_PDE_PSE] = 1; 636*7d36db35SAvi Kivity at2.flags[AC_PDE_PRESENT] = 1; 637*7d36db35SAvi Kivity ac_test_setup_pte(&at2, pool); 638*7d36db35SAvi Kivity if (!ac_test_do_access(&at2)) 639*7d36db35SAvi Kivity goto err; 640*7d36db35SAvi Kivity 641*7d36db35SAvi Kivity at1.flags[AC_CPU_CR0_WP] = 1; 642*7d36db35SAvi Kivity at1.flags[AC_PDE_PSE] = 1; 643*7d36db35SAvi Kivity at1.flags[AC_PDE_WRITABLE] = 1; 644*7d36db35SAvi Kivity at1.flags[AC_PDE_PRESENT] = 1; 645*7d36db35SAvi Kivity ac_test_setup_pte(&at1, pool); 646*7d36db35SAvi Kivity if (!ac_test_do_access(&at1)) 647*7d36db35SAvi Kivity goto err; 648*7d36db35SAvi Kivity 649*7d36db35SAvi Kivity at1.flags[AC_ACCESS_WRITE] = 1; 650*7d36db35SAvi Kivity ac_set_expected_status(&at1); 651*7d36db35SAvi Kivity if (!ac_test_do_access(&at1)) 652*7d36db35SAvi Kivity goto err; 653*7d36db35SAvi Kivity 654*7d36db35SAvi Kivity at2.flags[AC_ACCESS_WRITE] = 1; 655*7d36db35SAvi Kivity ac_set_expected_status(&at2); 656*7d36db35SAvi Kivity if (!ac_test_do_access(&at2)) 657*7d36db35SAvi Kivity goto err; 658*7d36db35SAvi Kivity 659*7d36db35SAvi Kivity return 1; 660*7d36db35SAvi Kivity 661*7d36db35SAvi Kivity err: 662*7d36db35SAvi Kivity printf("corrupt_hugepage_triger test fail\n"); 663*7d36db35SAvi Kivity return 0; 664*7d36db35SAvi Kivity } 665*7d36db35SAvi Kivity 666*7d36db35SAvi Kivity int ac_test_exec(ac_test_t *at, ac_pool_t *pool) 667*7d36db35SAvi Kivity { 668*7d36db35SAvi Kivity int r; 669*7d36db35SAvi Kivity 670*7d36db35SAvi Kivity if (verbose) { 671*7d36db35SAvi Kivity ac_test_show(at); 672*7d36db35SAvi Kivity } 673*7d36db35SAvi Kivity ac_test_setup_pte(at, pool); 674*7d36db35SAvi Kivity r = ac_test_do_access(at); 675*7d36db35SAvi Kivity return r; 676*7d36db35SAvi Kivity } 677*7d36db35SAvi Kivity 678*7d36db35SAvi Kivity int ac_test_run(void) 679*7d36db35SAvi Kivity { 680*7d36db35SAvi Kivity ac_test_t at; 681*7d36db35SAvi Kivity ac_pool_t pool; 682*7d36db35SAvi Kivity int tests, successes; 683*7d36db35SAvi Kivity 684*7d36db35SAvi Kivity printf("run\n"); 685*7d36db35SAvi Kivity tests = successes = 0; 686*7d36db35SAvi Kivity ac_env_int(&pool); 687*7d36db35SAvi Kivity ac_test_init(&at, (void *)(0x123400000000 + 16 * smp_id())); 688*7d36db35SAvi Kivity do { 689*7d36db35SAvi Kivity ++tests; 690*7d36db35SAvi Kivity successes += ac_test_exec(&at, &pool); 691*7d36db35SAvi Kivity } while (ac_test_bump(&at)); 692*7d36db35SAvi Kivity 693*7d36db35SAvi Kivity ++tests; 694*7d36db35SAvi Kivity successes += corrupt_hugepage_triger(&pool); 695*7d36db35SAvi Kivity 696*7d36db35SAvi Kivity printf("\n%d tests, %d failures\n", tests, tests - successes); 697*7d36db35SAvi Kivity 698*7d36db35SAvi Kivity return successes == tests; 699*7d36db35SAvi Kivity } 700*7d36db35SAvi Kivity 701*7d36db35SAvi Kivity int main() 702*7d36db35SAvi Kivity { 703*7d36db35SAvi Kivity int r; 704*7d36db35SAvi Kivity 705*7d36db35SAvi Kivity printf("starting test\n\n"); 706*7d36db35SAvi Kivity r = ac_test_run(); 707*7d36db35SAvi Kivity return r ? 0 : 1; 708*7d36db35SAvi Kivity } 709