Xen Test Framework
main.c
Go to the documentation of this file.
1
12#include <xtf.h>
13
14const char test_title[] = "XTF Selftests";
15bool has_xenstore = true;
16
17static 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
40static 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
52enum {
56};
57
58static unsigned long __user_text test_exec_user_cpl3(void)
59{
60 return ((read_cs() & 3) == 3) ? USER_seen : USER_bad_cs;
61}
62
63static void test_exec_user(void)
64{
65 unsigned int res;
66
67 printk("Test: Userspace execution\n");
68
70
71 switch ( res )
72 {
73 case USER_seen:
74 /* Success */
75 break;
76
77 case USER_bad_cs:
78 xtf_failure("Fail: Not at cpl3\n");
79 break;
80
81 default:
82 xtf_failure("Fail: Did not execute function\n");
83 break;
84 }
85}
86
87static void test_NULL_unmapped(void)
88{
89 unsigned int tmp;
90 exinfo_t got = 0;
91
92 printk("Test: NULL unmapped\n");
93
94 asm volatile ("1: mov 0, %[tmp]; 2:"
95 _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
96 : "+a" (got),
97 [tmp] "=r" (tmp)
98 : [rec] "p" (ex_record_fault_eax));
99
100 if ( got != EXINFO_SYM(PF, 0) )
101 xtf_failure("Fail: Expected #PF, got %pe\n", _p(got));
102}
103
104static volatile bool test_hook_active;
105bool do_unhandled_exception(struct cpu_regs *regs)
106{
107 extern unsigned long hook_fault[], hook_fixup[];
108
109 if ( !test_hook_active )
110 return false;
111
112 if ( _p(regs->ip) != hook_fault )
113 {
114 xtf_failure("Fail: Expected fault at %p, got %p\n",
115 hook_fault, _p(regs->ip));
116 return false;
117 }
118
119 regs->ip = _u(hook_fixup);
120 return true;
121}
122
124{
125 printk("Test: Unhandled Exception Hook\n");
126
127 /* Check that the hook catches the exception, and fix it up. */
128 test_hook_active = true;
129 asm volatile ("hook_fault: ud2a; hook_fixup:");
130 test_hook_active = false;
131}
132
134static bool test_extable_handler_handler(struct cpu_regs *regs,
135 const struct extable_entry *ex)
136{
138 regs->ip = ex->fixup;
139 return true;
140}
141
142static void test_extable_handler(void)
143{
144 printk("Test: Exception Table Handler\n");
145
146 asm volatile ("1: ud2a; 2:"
147 _ASM_EXTABLE_HANDLER(1b, 2b, %P[hnd])
148 :: [hnd] "p" (test_extable_handler_handler));
149
151 xtf_failure("Fail: Custom handler didn't run\n");
152}
153
155asm ("test_idte_handler:;"
156#if defined (CONFIG_PV) && defined (CONFIG_64BIT)
157 "pop %rcx; pop %r11;"
158#endif
159 "mov $0x1e51c0de, %eax;"
160#if defined (CONFIG_HVM)
161 __ASM_SEL(iretl, iretq) ";"
162#else /* CONFIG_HVM */
163#ifdef __x86_64__
164 "push $0;"
165#endif
166 "jmp HYPERCALL_iret;"
167#endif
168 );
169
170static const struct xtf_idte idte = {
172 /* PV guests need DPL1, HVM need DPL0. */
173 .dpl = IS_DEFINED(CONFIG_PV) ? 1 : 0,
174 .cs = __KERN_CS,
175};
176
177static void test_custom_idte(void)
178{
179 printk("Test: Custom IDT entry\n");
180
181 int rc = xtf_set_idte(X86_VEC_AVAIL, &idte);
182
183 if ( rc )
184 return xtf_failure("Fail: xtf_set_idte() returned %d\n", rc);
185
186 unsigned int res;
187 asm volatile ("int $%c[vec]"
188 : "=a" (res)
189 : "0" (0),
190 [vec] "i" (X86_VEC_AVAIL));
191
192 if ( res != 0x1e51c0de )
193 xtf_failure("Fail: Unexpected result %#x\n", res);
194};
195
196static void test_driver_init(void)
197{
198 int rc;
199
200 printk("Test: Driver basic initialisation\n");
201
202 if ( IS_DEFINED(CONFIG_HVM) )
203 {
205
206 /* Cope with guests which have LAPIC emulation disabled. */
207 if ( rc != -ENODEV )
208 {
209 if ( rc )
210 xtf_failure("Fail: apic_init(XAPIC) returned %d\n", rc);
211
212 if ( cpu_has_x2apic )
213 {
215
216 if ( rc )
217 xtf_failure("Fail: apic_init(X2APIC) returned %d\n", rc);
218 }
219 }
220
221 rc = hpet_init();
222 if ( rc && rc != -ENODEV )
223 xtf_failure("Fail: hpet_init() returned %d\n", rc);
224
225 rc = ioapic_init();
226 if ( rc && rc != -ENODEV )
227 xtf_failure("Fail: ioapic_init() returned %d\n", rc);
228 }
229
230 rc = xenstore_init();
231 has_xenstore = !rc;
232 if ( rc && rc != -ENODEV )
233 xtf_failure("Fail: xenstore_init() returned %d\n", rc);
234
235 rc = xtf_init_grant_table(1);
236 if ( rc )
237 xtf_failure("Fail: xtf_init_grant_table(1) returned %d\n", rc);
238
239 rc = xtf_init_grant_table(2);
240 if ( rc && rc != -ENODEV )
241 xtf_failure("Fail: xtf_init_grant_table(2) returned %d\n", rc);
242}
243
244static void test_vsnprintf_crlf_one(const char *fmt, ...)
245{
246 va_list args;
247
248 char buf[4];
249 int rc;
250
251 va_start(args, fmt);
252 rc = vsnprintf(buf, sizeof(buf), fmt, args);
253 va_end(args);
254
255 if ( rc != 1 )
256 return xtf_failure("Fail: '%s', expected length 1, got %d\n", fmt, rc);
257 if ( strcmp(buf, "\n") )
258 return xtf_failure("Fail: '%s', expected \"\\n\", got %*ph\n",
259 fmt, (int)sizeof(buf), buf);
260
261 va_start(args, fmt);
262 rc = vsnprintf_internal(buf, sizeof(buf), fmt, args, LF_TO_CRLF);
263 va_end(args);
264
265 if ( rc != 2 )
266 return xtf_failure("Fail: '%s', expected length 2, got %d\n", fmt, rc);
267 if ( strcmp(buf, "\r\n") )
268 return xtf_failure("Fail: '%s', expected \"\\r\\n\", got %*ph\n",
269 fmt, (int)sizeof(buf), buf);
270}
271
272static void test_vsnprintf_crlf(void)
273{
274 printk("Test: vsnprintf() with CRLF expansion\n");
275
277 test_vsnprintf_crlf_one("%c", '\n');
278 test_vsnprintf_crlf_one("%s", "\n");
279}
280
281void test_main(void)
282{
283 /*
284 * Wherever possible, enable SMEP and SMAP to test the safety of the
285 * exec_user infrastructure.
286 */
287 if ( IS_DEFINED(CONFIG_HVM) )
288 {
289 unsigned long cr4 = read_cr4(), ocr4 = cr4;
290
291 if ( cpu_has_smep )
292 cr4 |= X86_CR4_SMEP;
293 if ( cpu_has_smap )
294 cr4 |= X86_CR4_SMAP;
295
296 if ( cr4 != ocr4 )
297 write_cr4(cr4);
298 }
299
300 test_extable();
302 if ( CONFIG_PAGING_LEVELS > 0 )
309
310 if ( has_xenstore )
312
314}
315
316/*
317 * Inline assembly checks.
318 *
319 * Needs to be written out into an object file to cause build failures.
320 * Nothing executes the resulting code.
321 *
322 * - push/pop %reg need to use unsigned long types to avoid trying to allocate
323 * 32bit registers, which aren't encodable in 64bit.
324 * - push $imm can't encode 64bit integers (only 32bit sign extended)
325 */
326static void __used asm_checks(void)
327{
328 read_flags();
329
330#ifdef __x86_64__
331 unsigned long tmp = 0xdead0000c0deULL;
332
333 write_flags(tmp);
334 write_cs(tmp);
335#endif
336}
337
338/*
339 * Local variables:
340 * mode: C
341 * c-file-style: "BSD"
342 * c-basic-offset: 4
343 * tab-width: 4
344 * indent-tabs-mode: nil
345 * End:
346 */
int apic_init(enum apic_mode mode)
Discover and initialise the local APIC to the requested mode.
Definition: apic.c:33
@ APIC_MODE_XAPIC
Definition: apic.h:39
@ APIC_MODE_X2APIC
Definition: apic.h:40
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
#define __ASM_SEL(c, l)
Definition: asm_macros.h:25
#define cpu_has_smep
Definition: cpuid.h:95
#define cpu_has_smap
Definition: cpuid.h:97
#define cpu_has_x2apic
Definition: cpuid.h:81
static void write_cs(unsigned long cs)
Definition: lib.h:178
static unsigned int read_cs(void)
Definition: lib.h:124
static unsigned long read_cr4(void)
Definition: lib.h:252
static unsigned long read_flags(void)
Definition: lib.h:211
static void write_cr4(unsigned long cr4)
Definition: lib.h:285
static void write_flags(unsigned long flags)
Definition: lib.h:220
int xtf_init_grant_table(unsigned int version)
Initialise XTF's grant infrastructure.
Definition: grant_table.c:21
#define __user_text
Definition: compiler.h:33
#define __used
Definition: compiler.h:14
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
#define ENODEV
Definition: errno.h:32
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
int hpet_init(void)
Discover and initialise the HPET.
Definition: hpet.c:29
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
#define X86_VEC_AVAIL
Available for test use.
Definition: idt.h:20
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define _ASM_EXTABLE(fault, fixup)
Create an exception table entry.
Definition: extable.h:50
static unsigned long exec_user(unsigned long(*fn)(void))
Definition: lib.h:62
int ioapic_init(void)
Discover and initialise the IO-APIC.
Definition: io-apic.c:15
#define LF_TO_CRLF
Definition: libc.h:48
#define strcmp(s1, s2)
Definition: libc.h:27
static int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
Definition: libc.h:54
#define IS_DEFINED(x)
Evalute whether the CONFIG_ token x is defined.
Definition: macro_magic.h:67
bool do_unhandled_exception(struct cpu_regs *regs)
May be implemented by a guest to provide custom exception handling.
Definition: main.c:93
#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 X86_CR4_SMEP
Definition: processor.h:61
#define X86_CR4_SMAP
Definition: processor.h:62
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
@ USER_not_seen
Definition: main.c:53
@ USER_bad_cs
Definition: main.c:55
@ USER_seen
Definition: main.c:54
static void test_driver_init(void)
Definition: main.c:196
static void test_vsnprintf_crlf(void)
Definition: main.c:272
static void test_unhandled_exception_hook(void)
Definition: main.c:123
void test_idte_handler(void)
static void test_vsnprintf_crlf_one(const char *fmt,...)
Definition: main.c:244
static void test_custom_idte(void)
Definition: main.c:177
static bool test_extable_handler_handler_run
Definition: main.c:133
static volatile bool test_hook_active
Definition: main.c:104
static void test_exec_user(void)
Definition: main.c:63
static bool test_extable_handler_handler(struct cpu_regs *regs, const struct extable_entry *ex)
Definition: main.c:134
static void test_extable(void)
Definition: main.c:40
static void test_extable_handler(void)
Definition: main.c:142
static void test_NULL_unmapped(void)
Definition: main.c:87
static void test_xenstore(void)
Definition: main.c:17
static const struct xtf_idte idte
Definition: main.c:170
bool has_xenstore
Definition: main.c:15
static unsigned long test_exec_user_cpl3(void)
Definition: main.c:58
static void asm_checks(void)
Definition: main.c:326
#define va_end(v)
Definition: stdarg.h:11
#define va_start(v, l)
Definition: stdarg.h:10
__builtin_va_list va_list
Definition: stdarg.h:9
#define NULL
Definition: stddef.h:12
Exception table entry.
Definition: extable.h:65
unsigned long fixup
Fixup address.
Definition: extable.h:67
A guest agnostic represention of IDT information.
Definition: idt.h:27
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
const char * xenstore_read(const char *path)
Issue a XS_READ operation for key, waiting synchronously for the reply.
Definition: xenbus.c:115
int xenstore_init(void)
Initialise XTF ready for xenstore communication.
Definition: xenbus.c:109