Xen Test Framework
main.c
Go to the documentation of this file.
1 
12 #include <xtf.h>
13 
14 const char test_title[] = "XTF Selftests";
15 bool has_xenstore = true;
16 
17 static void test_xenstore(void)
18 {
19  printk("Test: Xenstore read\n");
20 
21  const char *domid_str = xenstore_read("domid");
22 
23  if ( !domid_str )
24  return xtf_failure("Fail: No domid value returned\n");
25 
26  if ( domid_str[0] == '\0' )
27  return xtf_failure("Fail: domid value empty\n");
28 
29  unsigned int i;
30  for ( i = 0; domid_str[i]; ++i )
31  {
32  if ( domid_str[i] < '0' || domid_str[i] > '9' )
33  return xtf_failure("Fail: unexpected domid value '%s'\n",
34  domid_str);
35  }
36 
37  printk(" Found domid %s\n", domid_str);
38 }
39 
40 static void test_extable(void)
41 {
42  printk("Test: Exception Table\n");
43 
44  /*
45  * Check that control flow is successfully redirected with a ud2a
46  * instruction and appropriate extable entry.
47  */
48  asm volatile ("1: ud2a; 2:"
49  _ASM_EXTABLE(1b, 2b));
50 }
51 
52 static bool check_nr_entries(unsigned int nr)
53 {
54  unsigned int entries = xtf_exlog_entries();
55 
56  if ( entries != nr )
57  {
58  xtf_failure("Fail: expected %u entries, got %u\n",
59  nr, entries);
60  return false;
61  }
62 
63  return true;
64 }
65 
66 static bool check_exlog_entry(unsigned int entry, unsigned int cs,
67  unsigned long ip, unsigned int ev,
68  unsigned int ec)
69 {
70  exlog_entry_t *e = xtf_exlog_entry(entry);
71 
72  /* Check whether the log entry is available. */
73  if ( !e )
74  {
75  xtf_failure("Fail: unable to retrieve log entry %u\n", entry);
76  return false;
77  }
78 
79  /* Check whether the log entry is correct. */
80  if ( (e->ip != ip) || (e->cs != cs) || (e->ec != ec) || (e->ev != ev) )
81  {
82  xtf_failure("Fail: exlog entry:\n"
83  " Expected: %04x:%p, ec %04x, vec %u\n"
84  " Got: %04x:%p, ec %04x, vec %u\n",
85  cs, _p(ip), ec, ev, e->cs, _p(e->ip), e->ec, e->ev);
86  return false;
87  }
88 
89  return true;
90 }
91 
92 static void test_exlog(void)
93 {
94  extern unsigned long exlog_int3[] asm(".Lexlog_int3");
95  extern unsigned long exlog_ud2a[] asm(".Lexlog_ud2a");
96 
97  printk("Test: Exception Logging\n");
98 
100 
101  /* Check that no entries have been logged thus far. */
102  if ( !check_nr_entries(0) )
103  goto out;
104 
105  asm volatile ("int3; .Lexlog_int3:"
106  _ASM_TRAP_OK(.Lexlog_int3));
107 
108  /* Check that one entry has now been logged. */
109  if ( !check_nr_entries(1) ||
110  !check_exlog_entry(0, __KERN_CS, _u(exlog_int3), X86_EXC_BP, 0) )
111  goto out;
112 
113  asm volatile (".Lexlog_ud2a: ud2a; 1:"
114  _ASM_EXTABLE(.Lexlog_ud2a, 1b));
115 
116  /* Check that two entries have now been logged. */
117  if ( !check_nr_entries(2) ||
118  !check_exlog_entry(1, __KERN_CS, _u(exlog_ud2a), X86_EXC_UD, 0) )
119  goto out;
120 
121  xtf_exlog_reset();
122 
123  /* Check that no entries now exist. */
124  if ( !check_nr_entries(0) )
125  goto out;
126 
127  asm volatile ("int3; 1:"
128  _ASM_TRAP_OK(1b));
129 
130  /* Check that one entry now exists. */
131  if ( !check_nr_entries(1) )
132  goto out;
133 
134  xtf_exlog_stop();
135 
136  /* Check that one entry still exists. */
137  if ( !check_nr_entries(1) )
138  goto out;
139 
140  asm volatile ("int3; 1:"
141  _ASM_TRAP_OK(1b));
142 
143  /* Check that the previous breakpoint wasn't logged. */
144  if ( !check_nr_entries(1) )
145  goto out;
146 
147  out:
148  xtf_exlog_reset();
149  xtf_exlog_stop();
150 }
151 
152 enum {
156 };
157 
158 static unsigned long __user_text test_exec_user_cpl3(void)
159 {
160  return ((read_cs() & 3) == 3) ? USER_seen : USER_bad_cs;
161 }
162 
163 static void test_exec_user(void)
164 {
165  unsigned int res;
166 
167  printk("Test: Userspace execution\n");
168 
170 
171  switch ( res )
172  {
173  case USER_seen:
174  /* Success */
175  break;
176 
177  case USER_bad_cs:
178  xtf_failure("Fail: Not at cpl3\n");
179  break;
180 
181  default:
182  xtf_failure("Fail: Did not execute function\n");
183  break;
184  }
185 }
186 
187 static void test_NULL_unmapped(void)
188 {
189  extern unsigned long label_test_NULL_unmapped[];
190  unsigned long tmp;
191 
192  printk("Test: NULL unmapped\n");
193 
194  xtf_exlog_start();
195 
196  asm volatile ("label_test_NULL_unmapped: mov 0, %0; 2:"
197  _ASM_EXTABLE(label_test_NULL_unmapped, 2b)
198  : "=q" (tmp) :: "memory");
199 
200  if ( check_nr_entries(1) )
201  check_exlog_entry(0, __KERN_CS, _u(label_test_NULL_unmapped), X86_EXC_PF, 0);
202 
203  xtf_exlog_stop();
204 }
205 
206 bool do_unhandled_exception(struct cpu_regs *regs)
207 {
208  extern unsigned long hook_fault[], hook_fixup[];
209 
210  if ( _p(regs->ip) != hook_fault )
211  {
212  xtf_failure("Fail: Expected fault at %p, got %p\n",
213  hook_fault, _p(regs->ip));
214  return false;
215  }
216 
217  regs->ip = _u(hook_fixup);
218  return true;
219 }
220 
222 {
223  printk("Test: Unhandled Exception Hook\n");
224 
225  /* Check that the hook catches the exception, and fix it up. */
226  asm volatile ("hook_fault: ud2a; hook_fixup:");
227 }
228 
230 static bool test_extable_handler_handler(struct cpu_regs *regs,
231  const struct extable_entry *ex)
232 {
234  regs->ip = ex->fixup;
235  return true;
236 }
237 
238 static void test_extable_handler(void)
239 {
240  printk("Test: Exception Table Handler\n");
241 
242  asm volatile ("1: ud2a; 2:"
243  _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
244  :: [hnd] "p" (test_extable_handler_handler));
245 
247  xtf_failure("Fail: Custom handler didn't run\n");
248 }
249 
250 void test_idte_handler(void);
251 asm ("test_idte_handler:;"
252 #if defined (CONFIG_PV) && defined (CONFIG_64BIT)
253  "pop %rcx; pop %r11;"
254 #endif
255  "mov $0x1e51c0de, %eax;"
256 #if defined (CONFIG_HVM)
257  __ASM_SEL(iretl, iretq) ";"
258 #else /* CONFIG_HVM */
259 #ifdef __x86_64__
260  "push $0;"
261 #endif
262  "jmp HYPERCALL_iret;"
263 #endif
264  );
265 
266 static const struct xtf_idte idte = {
268  /* PV guests need DPL1, HVM need DPL0. */
269  .dpl = IS_DEFINED(CONFIG_PV) ? 1 : 0,
270  .cs = __KERN_CS,
271 };
272 
273 static void test_custom_idte(void)
274 {
275  printk("Test: Custom IDT entry\n");
276 
277  int rc = xtf_set_idte(X86_VEC_AVAIL, &idte);
278 
279  if ( rc )
280  return xtf_failure("Fail: xtf_set_idte() returned %d\n", rc);
281 
282  unsigned int res;
283  asm volatile ("int $%c[vec]"
284  : "=a" (res)
285  : "0" (0),
286  [vec] "i" (X86_VEC_AVAIL));
287 
288  if ( res != 0x1e51c0de )
289  xtf_failure("Fail: Unexpected result %#x\n", res);
290 };
291 
292 static void test_driver_init(void)
293 {
294  int rc;
295 
296  printk("Test: Driver basic initialisation\n");
297 
298  if ( IS_DEFINED(CONFIG_HVM) )
299  {
301 
302  /* Cope with guests which have LAPIC emulation disabled. */
303  if ( rc != -ENODEV )
304  {
305  if ( rc )
306  xtf_failure("Fail: apic_init(XAPIC) returned %d\n", rc);
307 
308  if ( cpu_has_x2apic )
309  {
311 
312  if ( rc )
313  xtf_failure("Fail: apic_init(X2APIC) returned %d\n", rc);
314  }
315  }
316 
317  rc = hpet_init();
318  if ( rc && rc != -ENODEV )
319  xtf_failure("Fail: hpet_init() returned %d\n", rc);
320 
321  rc = ioapic_init();
322  if ( rc && rc != -ENODEV )
323  xtf_failure("Fail: ioapic_init() returned %d\n", rc);
324  }
325 
326  rc = xenstore_init();
327  has_xenstore = !rc;
328  if ( rc && rc != -ENODEV )
329  xtf_failure("Fail: xenstore_init() returned %d\n", rc);
330 
331  rc = xtf_init_grant_table(1);
332  if ( rc )
333  xtf_failure("Fail: xtf_init_grant_table(1) returned %d\n", rc);
334 
335  rc = xtf_init_grant_table(2);
336  if ( rc && rc != -ENODEV )
337  xtf_failure("Fail: xtf_init_grant_table(2) returned %d\n", rc);
338 }
339 
340 static void test_vsnprintf_crlf_one(const char *fmt, ...)
341 {
342  va_list args;
343 
344  char buf[4];
345  int rc;
346 
347  va_start(args, fmt);
348  rc = vsnprintf(buf, sizeof(buf), fmt, args);
349  va_end(args);
350 
351  if ( rc != 1 )
352  return xtf_failure("Fail: '%s', expected length 1, got %d\n", fmt, rc);
353  if ( strcmp(buf, "\n") )
354  return xtf_failure("Fail: '%s', expected \"\\n\", got %*ph\n",
355  fmt, (int)sizeof(buf), buf);
356 
357  va_start(args, fmt);
358  rc = vsnprintf_internal(buf, sizeof(buf), fmt, args, LF_TO_CRLF);
359  va_end(args);
360 
361  if ( rc != 2 )
362  return xtf_failure("Fail: '%s', expected length 2, got %d\n", fmt, rc);
363  if ( strcmp(buf, "\r\n") )
364  return xtf_failure("Fail: '%s', expected \"\\r\\n\", got %*ph\n",
365  fmt, (int)sizeof(buf), buf);
366 }
367 
368 static void test_vsnprintf_crlf(void)
369 {
370  printk("Test: vsnprintf() with CRLF expansion\n");
371 
373  test_vsnprintf_crlf_one("%c", '\n');
374  test_vsnprintf_crlf_one("%s", "\n");
375 }
376 
377 void test_main(void)
378 {
379  /*
380  * Wherever possible, enable SMEP and SMAP to test the safety of the
381  * exec_user infrastructure.
382  */
383  if ( IS_DEFINED(CONFIG_HVM) )
384  {
385  unsigned long cr4 = read_cr4(), ocr4 = cr4;
386 
387  if ( cpu_has_smep )
388  cr4 |= X86_CR4_SMEP;
389  if ( cpu_has_smap )
390  cr4 |= X86_CR4_SMAP;
391 
392  if ( cr4 != ocr4 )
393  write_cr4(cr4);
394  }
395 
396  test_extable();
397  test_exlog();
398  test_exec_user();
399  if ( CONFIG_PAGING_LEVELS > 0 )
406 
407  if ( has_xenstore )
408  test_xenstore();
409 
410  xtf_success(NULL);
411 }
412 
413 /*
414  * Inline assembly checks.
415  *
416  * Needs to be written out into an object file to cause build failures.
417  * Nothing executes the resulting code.
418  *
419  * - push/pop %reg need to use unsigned long types to avoid trying to allocate
420  * 32bit registers, which aren't encodable in 64bit.
421  * - push $imm can't encode 64bit integers (only 32bit sign extended)
422  */
423 static void __used asm_checks(void)
424 {
425  read_flags();
426 
427 #ifdef __x86_64__
428  unsigned long tmp = 0xdead0000c0deULL;
429 
430  write_flags(tmp);
431  write_cs(tmp);
432 #endif
433 }
434 
435 /*
436  * Local variables:
437  * mode: C
438  * c-file-style: "BSD"
439  * c-basic-offset: 4
440  * tab-width: 4
441  * indent-tabs-mode: nil
442  * End:
443  */
static void test_extable(void)
Definition: main.c:40
int hpet_init(void)
Discover and initialise the HPET.
Definition: hpet.c:29
unsigned long ip
Definition: exlog.h:13
static bool check_nr_entries(unsigned int nr)
Definition: main.c:52
unsigned long fixup
Fixup address.
Definition: extable.h:67
exlog_entry_t * xtf_exlog_entry(unsigned int idx)
Definition: exlog.c:32
static unsigned int read_cs(void)
Definition: lib.h:124
out
Definition: mkcfg.py:12
#define cpu_has_smep
Definition: cpuid.h:93
static bool check_exlog_entry(unsigned int entry, unsigned int cs, unsigned long ip, unsigned int ev, unsigned int ec)
Definition: main.c:66
static void test_vsnprintf_crlf_one(const char *fmt,...)
Definition: main.c:340
#define X86_CR4_SMEP
Definition: processor.h:61
#define IS_DEFINED(x)
Evalute whether the CONFIG_ token x is defined.
Definition: macro_magic.h:67
static bool test_extable_handler_handler(struct cpu_regs *regs, const struct extable_entry *ex)
Definition: main.c:230
bool has_xenstore
Definition: main.c:15
static void test_driver_init(void)
Definition: main.c:292
unsigned long addr
Definition: idt.h:28
int vsnprintf_internal(char *buf, size_t size, const char *fmt, va_list args, unsigned int caller_flags)
Definition: vsnprintf.c:276
static void test_unhandled_exception_hook(void)
Definition: main.c:221
#define cpu_has_x2apic
Definition: cpuid.h:80
int xtf_set_idte(unsigned int vector, const struct xtf_idte *idte)
Set up an IDT Entry, in a guest agnostic way.
Definition: traps.c:73
static int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
Definition: libc.h:54
#define LF_TO_CRLF
Definition: libc.h:48
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
int apic_init(enum apic_mode mode)
Discover and initialise the local APIC to the requested mode.
Definition: apic.c:33
static void asm_checks(void)
Definition: main.c:423
#define __used
Definition: compiler.h:14
void printk(const char *fmt,...)
Definition: console.c:134
static unsigned long test_exec_user_cpl3(void)
Definition: main.c:158
void test_idte_handler(void)
#define va_end(v)
Definition: stdarg.h:11
unsigned int xtf_exlog_entries(void)
Definition: exlog.c:27
void xtf_exlog_reset(void)
Definition: exlog.c:16
#define X86_EXC_BP
Definition: processor.h:94
#define __user_text
Definition: compiler.h:33
Definition: exlog.h:11
static bool test_extable_handler_handler_run
Definition: main.c:229
#define va_start(v, l)
Definition: stdarg.h:10
static void test_exec_user(void)
Definition: main.c:163
int xenstore_init(void)
Initialise XTF ready for xenstore communication.
Definition: xenbus.c:109
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
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
#define _ASM_TRAP_OK(loc)
Create an exception table entry, whitelisting a trap as being ok at loc.
Definition: extable.h:57
#define cpu_has_smap
Definition: cpuid.h:95
Exception table entry.
Definition: extable.h:64
static void test_xenstore(void)
Definition: main.c:17
#define X86_CR4_SMAP
Definition: processor.h:62
static unsigned long read_cr4(void)
Definition: lib.h:252
static const struct xtf_idte idte
Definition: main.c:266
const char * xenstore_read(const char *path)
Issue a XS_READ operation for key, waiting synchronously for the reply.
Definition: xenbus.c:115
int xtf_init_grant_table(unsigned int version)
Initialise XTF&#39;s grant infrastructure.
Definition: grant_table.c:21
static void write_flags(unsigned long flags)
Definition: lib.h:220
uint16_t cs
Definition: exlog.h:14
const char test_title[]
The title of the test.
Definition: main.c:14
static unsigned long read_flags(void)
Definition: lib.h:211
static void test_NULL_unmapped(void)
Definition: main.c:187
uint16_t ev
Definition: exlog.h:14
#define X86_EXC_UD
Definition: processor.h:97
#define ENODEV
Definition: errno.h:32
void xtf_exlog_stop(void)
Definition: exlog.c:21
static void write_cr4(unsigned long cr4)
Definition: lib.h:285
static unsigned long exec_user(unsigned long(*fn)(void))
Definition: lib.h:62
#define strcmp(s1, s2)
Definition: libc.h:27
__builtin_va_list va_list
Definition: stdarg.h:9
#define X86_VEC_AVAIL
Available for test use.
Definition: idt.h:20
static void test_exlog(void)
Definition: main.c:92
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
void xtf_exlog_start(void)
Definition: exlog.c:10
static void test_vsnprintf_crlf(void)
Definition: main.c:368
A guest agnostic represention of IDT information.
Definition: idt.h:26
uint16_t ec
Definition: exlog.h:14
#define _ASM_EXTABLE(fault, fixup)
Create an exception table entry.
Definition: extable.h:50
#define __ASM_SEL(c, l)
Definition: asm_macros.h:25
static void test_custom_idte(void)
Definition: main.c:273
#define X86_EXC_PF
Definition: processor.h:105
bool do_unhandled_exception(struct cpu_regs *regs)
May be implemented by a guest to provide custom exception handling.
Definition: main.c:96
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
static void write_cs(unsigned long cs)
Definition: lib.h:178
int ioapic_init(void)
Discover and initialise the IO-APIC.
Definition: io-apic.c:15
static void test_extable_handler(void)
Definition: main.c:238