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