Xen Test Framework
main.c
Go to the documentation of this file.
1
83#include <xtf.h>
84
85const char test_title[] = "Invlpg tests";
86
87/* Swizzle to easily change all invlpg instructions to being emulated. */
88#if 0
89#define _ASM_MAYBE_XEN_FEP _ASM_XEN_FEP
90#else
91#define _ASM_MAYBE_XEN_FEP
92#endif
93
98static bool ex_fail(struct cpu_regs *regs, const struct extable_entry *ex)
99{
100 exinfo_t info = EXINFO(regs->entry_vector, regs->error_code);
101
102 xtf_failure(" Fail: Unexpected fault %#x, %pe\n", info, _p(info));
103
104 regs->ip = ex->fixup;
105 return true;
106}
107
109static bool test_ad(uint64_t pte)
110{
111 return (pte & _PAGE_AD) == _PAGE_AD;
112}
113
114static unsigned int invlpg_refill(void)
115{
116 asm volatile ("mov %[zero], 0x1000;\n\t" /* Force TLB fill. */
117 "mov %[zero], 0x2000;\n\t"
118 "andb $~%c[ad], %[pte1];\n\t" /* Clear A/D bits. */
119 "andb $~%c[ad], %[pte2];\n\t"
121 "1: invlpg 0x1000; 2:\n\t" /* Invalidate one page only. */
122 _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
123 "mov %[zero], 0x1000;\n\t" /* Expect refill. */
124 "mov %[zero], 0x2000;\n\t" /* Expect no refill. */
125 :
126 : [zero] "r" (0),
127 [ad] "i" (_PAGE_AD),
128 [pte1] "m" (pae_l1_identmap[1]),
129 [pte2] "m" (pae_l1_identmap[2]),
130 [hnd] "p" (ex_fail)
131 : "memory");
132
133 return ((test_ad(pae_l1_identmap[1]) << 0) |
134 (test_ad(pae_l1_identmap[2]) << 1));
135}
136
137static unsigned int invlpg_fs_refill(void)
138{
139 asm volatile ("mov %[zero], 0x1000;\n\t" /* Force TLB fill. */
140 "mov %[zero], 0x2000;\n\t"
141 "andb $~%c[ad], %[pte1];\n\t" /* Clear A/D bits. */
142 "andb $~%c[ad], %[pte2];\n\t"
144 "1: invlpg %%fs:0x1000; 2:\n\t" /* Invalidate one page only. */
145 _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
146 "mov %[zero], 0x1000;\n\t" /* Expect one TLB entry to refil, */
147 "mov %[zero], 0x2000;\n\t" /* depending on %fs base.*/
148 :
149 : [zero] "r" (0),
150 [ad] "i" (_PAGE_AD),
151 [pte1] "m" (pae_l1_identmap[1]),
152 [pte2] "m" (pae_l1_identmap[2]),
153 [hnd] "p" (ex_fail)
154 : "memory");
155
156 return ((test_ad(pae_l1_identmap[1]) << 0) |
157 (test_ad(pae_l1_identmap[2]) << 1));
158}
159
160static void run_tlb_refill_test(unsigned int (*fn)(void), unsigned int expect)
161{
162 unsigned int ret, tries = 20;
163
164 do
165 {
166 ret = fn();
167 /*
168 * Tests are racy if a vcpu reschedule happens in the asm blocks, as
169 * the TLB on the new vcpu will be empty and extra refills will occur.
170 * If a refil of both entries occurs, repeat the test quickly several
171 * times in the hope that one doesn't hit a reschedule point.
172 */
173 } while ( ret == 3 && --tries );
174
175 switch ( ret )
176 {
177 case 0:
178 return xtf_failure(" Fail: No TLB refill at all\n");
179 break;
180
181 case 1: case 2:
182 printk(" TLB refill of %#x\n", ret * 0x1000);
183
184 if ( ret != expect )
185 xtf_failure(" Fail: Expected mapping %#x to have been refilled\n",
186 expect * 0x1000);
187 break;
188
189 case 3:
190 printk(" TLB refill of both 0x1000 and 0x2000\n");
191 break;
192
193 default:
194 return xtf_failure(" Fail: Unexpected return value %u\n", ret);
195 }
196}
197
198static const struct tlb_refill_fs_test
199{
200 const char *desc;
201 unsigned int mapping;
202 user_desc seg;
203
205{
206 { "(base 0x0)", 1,
207 INIT_GDTE_SYM(0, 0xfffff, P, S, G, A, DATA, DPL0, B, W),
208 },
209
210 { "(base 0x0, limit 0x1)", 1,
211 INIT_GDTE_SYM(0, 1, P, S, A, DATA, DPL0, B, W),
212 },
213
214 { "(base 0x1000)", 2,
215 INIT_GDTE_SYM(0x1000, 0xfffff, P, S, G, A, DATA, DPL0, B, W),
216 },
217
218 { "(base 0x1000, limit 0x1001)", 2,
219 INIT_GDTE_SYM(0x1000, 0x1001, P, S, A, DATA, DPL0, B, W),
220 },
222
223static void test_tlb_refill(void)
224{
225 unsigned int i;
226
227 printk("Testing 'invlpg 0x1000' with segment bases\n");
228
229 printk(" Test: No segment\n");
231
232 for ( i = 0; i < ARRAY_SIZE(tlb_refill_fs_tests); ++i )
233 {
234 const struct tlb_refill_fs_test *t = &tlb_refill_fs_tests[i];
235
236 printk(" Test: %%fs %s\n", t->desc);
238 write_fs(GDTE_AVAIL0 << 3);
240 }
241}
242
243static void invlpg_checked(unsigned long linear)
244{
245 asm volatile (_ASM_MAYBE_XEN_FEP
246 "1: invlpg (%0); 2:"
247 _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
248 :: "r" (linear), [hnd] "p" (ex_fail));
249}
250
251static void invlpg_fs_checked(unsigned long linear)
252{
253 asm volatile (_ASM_MAYBE_XEN_FEP
254 "1: invlpg %%fs:(%0); 2:"
255 _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
256 :: "r" (linear), [hnd] "p" (ex_fail));
257}
258
259static void test_no_fault(void)
260{
261 printk("Testing 'invlpg' in normally-faulting conditions\n");
262
263 printk(" Test: Mapped address\n");
265
266 printk(" Test: Unmapped address\n");
268
269 printk(" Test: NULL segment override\n");
270 write_fs(0);
272
273 printk(" Test: Past segment limit\n");
274 update_desc(&gdt[GDTE_AVAIL0], GDTE_SYM(0, 1, COMMON, DATA, DPL0, B, W));
275 write_fs(GDTE_AVAIL0 << 3);
276 invlpg_fs_checked(0x2000);
277
278 printk(" Test: Before expand-down segment limit\n");
279 update_desc(&gdt[GDTE_AVAIL0], GDTE_SYM(0, 1, COMMON, DATA, DPL0, B, W, E));
280 write_fs(GDTE_AVAIL0 << 3);
282
283#if CONFIG_PAGING_LEVELS >= 4
284 printk(" Test: Noncanonical address\n");
285 invlpg_checked(0x800000000000ULL);
286
287 printk(" Test: Noncanonical including segment base\n");
288 write_fs(0);
289 wrmsr(MSR_FS_BASE, (1UL << 47) - 1);
290 invlpg_fs_checked((1UL << 47) - 1);
291#endif
292}
293
294void test_main(void)
295{
296 if ( CONFIG_PAGING_LEVELS > 0 )
299
301}
302
303/*
304 * Local variables:
305 * mode: C
306 * c-file-style: "BSD"
307 * c-basic-offset: 4
308 * tab-width: 4
309 * indent-tabs-mode: nil
310 * End:
311 */
static void write_fs(unsigned int fs)
Definition: lib.h:196
static void update_desc(user_desc *ptr, const user_desc new)
Helper to update a live LDT/GDT entry.
Definition: xtf.h:26
void printk(const char *fmt,...)
Definition: console.c:134
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:110
const char test_title[]
The title of the test.
Definition: main.c:24
user_desc gdt[NR_GDT_ENTRIES]
#define EXINFO(vec, ec)
Definition: exinfo.h:26
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define ARRAY_SIZE(a)
Definition: lib.h:8
static void run_tlb_refill_test(unsigned int(*fn)(void), unsigned int expect)
Definition: main.c:160
static bool ex_fail(struct cpu_regs *regs, const struct extable_entry *ex)
Custom extable handler, linked to all invlpg instruction which are expected not to fault.
Definition: main.c:98
static bool test_ad(uint64_t pte)
Are both the Accessed and Dirty bits are set in a pagetable entry?
Definition: main.c:109
#define _ASM_MAYBE_XEN_FEP
Definition: main.c:91
static unsigned int invlpg_refill(void)
Definition: main.c:114
static void test_no_fault(void)
Definition: main.c:259
static const struct tlb_refill_fs_test tlb_refill_fs_tests[]
static void invlpg_checked(unsigned long linear)
Definition: main.c:243
static void test_tlb_refill(void)
Definition: main.c:223
static unsigned int invlpg_fs_refill(void)
Definition: main.c:137
static void invlpg_fs_checked(unsigned long linear)
Definition: main.c:251
#define MSR_FS_BASE
Definition: msr-index.h:64
static void wrmsr(uint32_t idx, uint64_t val)
Thin wrapper around an wrmsr instruction.
Definition: msr.h:55
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define _PAGE_AD
Definition: page.h:32
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define GDTE_AVAIL0
Definition: segment.h:37
#define NULL
Definition: stddef.h:12
__UINT64_TYPE__ uint64_t
Definition: stdint.h:17
Exception table entry.
Definition: extable.h:65
unsigned long fixup
Fixup address.
Definition: extable.h:67
user_desc seg
Definition: main.c:202
const char * desc
Definition: main.c:200
unsigned int mapping
Definition: main.c:201
#define GDTE_SYM(base, limit,...)
As INIT_GDTE_SYM(), but creates a user_desc object.
#define INIT_GDTE_SYM(base, limit,...)
Initialiser for an LDT/GDT entry using SEG_ATTR_ mnemonics.