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