Xen Test Framework
main.c
Go to the documentation of this file.
1 
36 #include <xtf.h>
37 
38 const char test_title[] = "FPU Exception Emulation";
39 
40 #define CR0_SYM(...) TOK_OR(X86_CR0_, ##__VA_ARGS__)
41 #define CR0_MASK CR0_SYM(EM, MP, TS)
42 
43 struct test_cfg
44 {
45  unsigned long cr0;
47 };
48 
49 static unsigned long default_cr0;
50 
55 static const struct test_cfg x87[] =
56 {
57  { CR0_SYM( ), 0 },
58  { CR0_SYM( TS), EXINFO_SYM(NM, 0) },
59  { CR0_SYM( MP ), 0 },
60  { CR0_SYM( MP, TS), EXINFO_SYM(NM, 0) },
61  { CR0_SYM(EM ), EXINFO_SYM(NM, 0) },
62  { CR0_SYM(EM, TS), EXINFO_SYM(NM, 0) },
63  { CR0_SYM(EM, MP ), EXINFO_SYM(NM, 0) },
64  { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
65 };
66 
67 exinfo_t probe_x87(bool force)
68 {
69  exinfo_t fault = 0;
70 
71  asm volatile ("test %[fep], %[fep];"
72  "jz 1f;"
74  "1: fnop; 2:"
75  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
76  : "+a" (fault)
77  : [fep] "q" (force),
78  [rec] "p" (ex_record_fault_eax));
79 
80  return fault;
81 }
82 
88 static const struct test_cfg x87_wait[] =
89 {
90  { CR0_SYM( ), 0 },
91  { CR0_SYM( TS), 0 },
92  { CR0_SYM( MP ), 0 },
93  { CR0_SYM( MP, TS), EXINFO_SYM(NM, 0) },
94  { CR0_SYM(EM ), 0 },
95  { CR0_SYM(EM, TS), 0 },
96  { CR0_SYM(EM, MP ), 0 },
97  { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
98 };
99 
101 {
102  exinfo_t fault = 0;
103 
104  asm volatile ("test %[fep], %[fep];"
105  "jz 1f;"
107  "1: wait; 2:"
108  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
109  : "+a" (fault)
110  : [fep] "q" (force),
111  [rec] "p" (ex_record_fault_eax));
112 
113  return fault;
114 }
115 
120 static const struct test_cfg mmx_sse[] =
121 {
122  { CR0_SYM( ), 0 },
123  { CR0_SYM( TS), EXINFO_SYM(NM, 0) },
124  { CR0_SYM( MP ), 0 },
125  { CR0_SYM( MP, TS), EXINFO_SYM(NM, 0) },
126  { CR0_SYM(EM ), EXINFO_SYM(UD, 0) },
127  { CR0_SYM(EM, TS), EXINFO_SYM(UD, 0) },
128  { CR0_SYM(EM, MP ), EXINFO_SYM(UD, 0) },
129  { CR0_SYM(EM, MP, TS), EXINFO_SYM(UD, 0) },
130 };
131 
132 exinfo_t probe_mmx(bool force)
133 {
134  exinfo_t fault = 0;
135 
136  asm volatile ("test %[fep], %[fep];"
137  "jz 1f;"
139  "1: movq %%mm0, %%mm0; 2:"
140  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
141  : "+a" (fault)
142  : [fep] "q" (force),
143  [rec] "p" (ex_record_fault_eax));
144 
145  return fault;
146 }
147 
148 exinfo_t probe_sse(bool force)
149 {
150  exinfo_t fault = 0;
151 
152  asm volatile ("test %[fep], %[fep];"
153  "jz 1f;"
155  "1: movups %%xmm0, %%xmm0; 2:"
156  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
157  : "+a" (fault)
158  : [fep] "q" (force),
159  [rec] "p" (ex_record_fault_eax));
160 
161  return fault;
162 }
163 
168 static const struct test_cfg avx[] =
169 {
170  { CR0_SYM( ), 0 },
171  { CR0_SYM( TS), EXINFO_SYM(NM, 0) },
172  { CR0_SYM( MP ), 0 },
173  { CR0_SYM( MP, TS), EXINFO_SYM(NM, 0) },
174  { CR0_SYM(EM ), 0 },
175  { CR0_SYM(EM, TS), EXINFO_SYM(NM, 0) },
176  { CR0_SYM(EM, MP ), 0 },
177  { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
178 };
179 
180 static exinfo_t probe_avx(bool force)
181 {
182  exinfo_t fault = 0;
183 
184  asm volatile ("test %[fep], %[fep];"
185  "jz 1f;"
187  "1: vmovups %%xmm0, %%xmm0; 2:"
188  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
189  : "+a" (fault)
190  : [fep] "q" (force),
191  [rec] "p" (ex_record_fault_eax));
192 
193  return fault;
194 }
195 
196 void run_sequence(const struct test_cfg *seq, unsigned int nr,
197  unsigned int (*fn)(bool), bool force, exinfo_t override)
198 {
199  unsigned int i;
200 
201  for ( i = 0; i < nr; ++i )
202  {
203  const struct test_cfg *t = &seq[i];
204  exinfo_t res, exp = override ?: t->fault;
205 
206  write_cr0((default_cr0 & ~CR0_MASK) | t->cr0);
207  res = fn(force);
208 
209  if ( res != exp )
210  {
211  char cr0str[12];
212 
213  snprintf(cr0str, sizeof(cr0str), "%s%s%s",
214  t->cr0 & X86_CR0_EM ? " EM" : "",
215  t->cr0 & X86_CR0_MP ? " MP" : "",
216  t->cr0 & X86_CR0_TS ? " TS" : "");
217 
218  xtf_failure(" Expected %pe, got %pe (cr0:%s)\n",
219  _p(exp), _p(res), cr0str[0] ? cr0str : " - ");
220  }
221  }
222 }
223 
224 void run_tests(bool force)
225 {
226  if ( cpu_has_fpu )
227  {
228  printk("Testing%s x87\n", force ? " emulated" : "");
229  run_sequence(x87, ARRAY_SIZE(x87), probe_x87, force, 0);
230 
231  printk("Testing%s x87 wait\n", force ? " emulated" : "");
232  run_sequence(x87_wait, ARRAY_SIZE(x87_wait), probe_x87_wait, force, 0);
233  }
234 
235  if ( cpu_has_mmx )
236  {
237  printk("Testing%s MMX\n", force ? " emulated" : "");
238  run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_mmx, force, 0);
239  }
240 
241  if ( cpu_has_sse )
242  {
243  unsigned long cr4 = read_cr4();
244 
245  printk("Testing%s SSE\n", force ? " emulated" : "");
246  write_cr4(cr4 & ~X86_CR4_OSFXSR);
247  run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_sse, force,
248  EXINFO_SYM(UD, 0));
249 
250  printk("Testing%s SSE (CR4.OSFXSR)\n", force ? " emulated" : "");
251  write_cr4(cr4 | X86_CR4_OSFXSR);
252  run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_sse, force, 0);
253 
254  write_cr4(cr4);
255  }
256 
257  if ( cpu_has_avx )
258  {
259  unsigned long cr4 = read_cr4();
260  unsigned long xcr0;
261 
262  printk("Testing%s AVX\n", force ? " emulated" : "");
263  write_cr4(cr4 & ~X86_CR4_OSXSAVE);
264  run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force,
265  EXINFO_SYM(UD, 0));
266 
267  printk("Testing%s AVX (CR4.OSXSAVE)\n", force ? " emulated" : "");
268  write_cr4(cr4 | X86_CR4_OSXSAVE);
269  xcr0 = read_xcr0();
270  write_xcr0(xcr0 & ~XSTATE_YMM);
271  run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force,
272  EXINFO_SYM(UD, 0));
273 
274  printk("Testing%s AVX (CR4.OSXSAVE+XCR0.YMM)\n", force ? " emulated" : "");
275  write_xcr0(xcr0 | XSTATE_SSE | XSTATE_YMM);
276  run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force, 0);
277 
278  write_xcr0(xcr0);
279  write_cr4(cr4);
280  }
281 }
282 
283 void test_main(void)
284 {
285  default_cr0 = read_cr0();
286 
287  run_tests(false);
288 
289  if ( !xtf_has_fep )
290  xtf_skip("FEP support not detected - some tests will be skipped\n");
291  else
292  run_tests(true);
293 
294  xtf_success(NULL);
295 }
296 
297 /*
298  * Local variables:
299  * mode: C
300  * c-file-style: "BSD"
301  * c-basic-offset: 4
302  * tab-width: 4
303  * indent-tabs-mode: nil
304  * End:
305  */
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
#define _ASM_XEN_FEP
Xen Forced Emulation Prefix.
Definition: xen.h:150
#define XSTATE_YMM
Definition: processor.h:72
exinfo_t probe_sse(bool force)
Definition: main.c:148
#define X86_CR0_TS
Definition: processor.h:32
#define cpu_has_fpu
Definition: cpuid.h:60
static exinfo_t probe_avx(bool force)
Definition: main.c:180
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: stdio.c:3
#define ARRAY_SIZE(a)
Definition: lib.h:8
#define X86_CR4_OSFXSR
Definition: processor.h:53
exinfo_t fault
Definition: main.c:46
void run_tests(bool force)
Definition: main.c:224
void printk(const char *fmt,...)
Definition: console.c:134
static uint64_t read_xcr0(void)
Definition: lib.h:392
static void write_xcr0(uint64_t xcr0)
Definition: lib.h:397
bool xtf_has_fep
Boolean indicating whether generic Force Emulation Prefix support is available for the test to use...
Definition: setup.c:276
#define CR0_MASK
Definition: main.c:41
exinfo_t probe_x87_wait(bool force)
Definition: main.c:100
void run_sequence(const struct test_cfg *seq, unsigned int nr, unsigned int(*fn)(bool), bool force, exinfo_t override)
Definition: main.c:196
static const struct test_cfg x87_wait[]
The x87 wait instruction.
Definition: main.c:88
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static unsigned long default_cr0
Definition: main.c:49
#define X86_CR4_OSXSAVE
Definition: processor.h:60
exinfo_t probe_mmx(bool force)
Definition: main.c:132
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
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
static unsigned long read_cr4(void)
Definition: lib.h:252
const char test_title[]
The title of the test.
Definition: main.c:14
static void write_cr0(unsigned long cr0)
Definition: lib.h:270
#define X86_CR0_EM
Definition: processor.h:31
#define XSTATE_SSE
Definition: processor.h:70
static void write_cr4(unsigned long cr4)
Definition: lib.h:285
#define cpu_has_mmx
Definition: cpuid.h:72
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
static const struct test_cfg avx[]
AVX instructions.
Definition: main.c:168
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
static unsigned long read_cr0(void)
Definition: lib.h:225
#define cpu_has_sse
Definition: cpuid.h:75
#define cpu_has_avx
Definition: cpuid.h:82
unsigned long cr0
Definition: main.c:45
static const struct test_cfg x87[]
x87 coprocessor.
Definition: main.c:55
static const struct test_cfg mmx_sse[]
MMX and SSE instructions.
Definition: main.c:120
#define CR0_SYM(...)
Definition: main.c:40
exinfo_t probe_x87(bool force)
Definition: main.c:67
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
Definition: main.c:43
#define X86_CR0_MP
Definition: processor.h:30