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