Xen Test Framework
main.c
Go to the documentation of this file.
1 
83 #include <xtf.h>
84 
85 const 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 
98 static 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 
109 static bool test_ad(uint64_t pte)
110 {
111  return (pte & _PAGE_AD) == _PAGE_AD;
112 }
113 
114 static 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 
137 static 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 
160 static 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 
198 static 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  },
221 };
222 
223 static 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 
243 static 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 
251 static 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 
259 static 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");
267  invlpg_checked(0);
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 
294 void test_main(void)
295 {
296  if ( CONFIG_PAGING_LEVELS > 0 )
297  test_tlb_refill();
298  test_no_fault();
299 
300  xtf_success(NULL);
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  */
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
static void wrmsr(uint32_t idx, uint64_t val)
Thin wrapper around an wrmsr instruction.
Definition: msr.h:55
unsigned long fixup
Fixup address.
Definition: extable.h:67
static void run_tlb_refill_test(unsigned int(*fn)(void), unsigned int expect)
Definition: main.c:160
static unsigned int invlpg_fs_refill(void)
Definition: main.c:137
unsigned int mapping
Definition: main.c:201
static void invlpg_checked(unsigned long linear)
Definition: main.c:243
#define EXINFO(vec, ec)
Definition: exinfo.h:26
#define ARRAY_SIZE(a)
Definition: lib.h:8
user_desc seg
Definition: main.c:202
static const struct tlb_refill_fs_test tlb_refill_fs_tests[]
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define INIT_GDTE_SYM(base, limit,...)
Initialiser for an LDT/GDT entry using SEG_ATTR_ mnemonics.
void printk(const char *fmt,...)
Definition: console.c:134
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 _PAGE_AD
Definition: page.h:32
#define MSR_FS_BASE
Definition: msr-index.h:64
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static void invlpg_fs_checked(unsigned long linear)
Definition: main.c:251
user_desc gdt[NR_GDT_ENTRIES]
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
__UINT64_TYPE__ uint64_t
Definition: stdint.h:17
Exception table entry.
Definition: extable.h:64
static void update_desc(user_desc *ptr, const user_desc new)
Helper to update a live LDT/GDT entry.
Definition: xtf.h:26
const char test_title[]
The title of the test.
Definition: main.c:14
#define GDTE_AVAIL0
Definition: segment.h:37
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
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 void test_no_fault(void)
Definition: main.c:259
const char * desc
Definition: main.c:200
static unsigned int invlpg_refill(void)
Definition: main.c:114
#define GDTE_SYM(base, limit,...)
As INIT_GDTE_SYM(), but creates a user_desc object.
static void write_fs(unsigned int fs)
Definition: lib.h:196
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define _ASM_MAYBE_XEN_FEP
Definition: main.c:91
static void test_tlb_refill(void)
Definition: main.c:223