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