xref: /kvm-unit-tests/x86/access.c (revision fd5d3dc60d413d77a93da79e65cc945aeb87cf4d)
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