Xen Test Framework
main.c
Go to the documentation of this file.
1 
33 #include <xtf.h>
34 
35 const char test_title[] = "XSA-186 PoC";
36 
37 bool test_needs_fep = true;
38 
39 /* Test-local `int` handler. */
40 void test_int_handler(void);
41 asm(".align 16;"
42  "test_int_handler:"
43  "movl $0xc0de, %eax;"
44  __ASM_SEL(iretl, iretq)
45  );
46 
47 static const struct xtf_idte idte = {
49  .cs = __KERN_CS,
50 };
51 
52 /* Stub instruction buffer. */
53 asm(".align 16;"
54  "insn_stub_start:;"
56  ".Lstub_fault:;"
57  ".byte 0x67; int $" STR(X86_VEC_AVAIL) ";"
58  ".Lstub_fixup: ret;"
59  "insn_stub_end:;"
60  );
61 
62 static bool ex_fault(struct cpu_regs *regs, const struct extable_entry *ex)
63 {
64  if ( regs->entry_vector == X86_EXC_GP && regs->error_code == 0 )
65  {
66  extern char _fault[] asm(".Lstub_fault");
67  extern char _fixup[] asm(".Lstub_fixup");
68  const size_t delta = _fixup - _fault;
69 
70  regs->ax = 0xc0de;
71  regs->ip += delta;
72  return true;
73  }
74 
75  return false;
76 }
77 
78 void test_main(void)
79 {
80  /* Hook test_int_handler() into the real IDT. */
82 
83  /* Reinstate the mapping at 0 virtual. It will be needed. */
84  if ( CONFIG_PAGING_LEVELS > 0 )
85  {
86  l1_identmap[0] = pte_from_gfn(0, PF_SYM(AD, RW, P));
87  barrier();
88  }
89 
90  if ( IS_DEFINED(CONFIG_64BIT) )
91  {
94 
95  /*
96  * The manuals say we can't `iretq` to a compat mode code segment with
97  * a NULL %ss. Indeed, this causes a #GP(0). Despite the fact we can
98  * `lcall/lret` ourselves there, and everything works fine.
99  *
100  * /sigh x86...
101  *
102  * Load a flat non-NULL %ss so test_int_handler() can sensibly return.
103  */
104  write_ss(GDTE_DS32_DPL0 << 3);
105 
106  /* Map gfn 0 at the very top of virtual address space. */
107  nl1t[511] = pte_from_gfn(0, PF_SYM(AD, RW, P));
108  nl2t[511] = pte_from_virt(nl1t, PF_SYM(AD, U, RW, P));
109  pae_l3_identmap[511] = pte_from_virt(nl2t, PF_SYM(AD, U, RW, P));
110  pae_l4_identmap[511] = pte_from_virt(pae_l3_identmap, PF_SYM(AD, U, RW, P));
111  barrier();
112  }
113  else
114  {
115  unsigned long extent = (GB(4) - 1) >> PAGE_SHIFT;
116  struct xen_memory_reservation mr =
117  {
118  .extent_start = &extent,
119  .nr_extents = 1,
120  .domid = DOMID_SELF,
121  };
122 
123  /* Populate gfn 0xfffff (the 4GB boundary) with real RAM. */
125  panic("Failed to populate_physmap() at %#lx\n", extent);
126  }
127 
128  /*
129  * Copy the instruction stub over the virtual address space wrap.
130  */
131  uint8_t *stub = _p(~0ULL - 5);
132  unsigned int res;
133 
134  extern char insn_buf_start[] asm("insn_stub_start");
135  extern char insn_buf_end[] asm("insn_stub_end");
136  memcpy(stub, insn_buf_start, insn_buf_end - insn_buf_start);
137 
138  /*
139  * Work around suspected Broadwell TLB Erratum
140  *
141  * Occasionally, this test failes with:
142  *
143  * --- Xen Test Framework ---
144  * Environment: HVM 64bit (Long mode 4 levels)
145  * XSA-186 PoC
146  * ******************************
147  * PANIC: Unhandled exception at 0008:fffffffffffffffa
148  * Vec 14 #PF[-I-sr-] %cr2 fffffffffffffffa
149  * ******************************
150  *
151  * on Broadwell hardware. The mapping is definitely present as the
152  * memcpy() has already succeeded. Inserting an invlpg resolves the
153  * issue, sugguesting that there is a race conditon between dTLB/iTLB
154  * handling.
155  *
156  * Work around the issue for now, to avoid intermittent OSSTest failures
157  * from blocking pushes of unrelated changes.
158  */
159  invlpg(stub);
160 
161  /*
162  * Execute the stub.
163  *
164  * Intel CPUs are happy doing this for 32 and 64bit. AMD CPUs are happy
165  * for 64bit, but hit a segment limit violation for 32bit. The Xen
166  * emulator follows AMD behaviour for 32bit guests.
167  *
168  * Cover the segment limit violation with an extable handler, which
169  * matches the `int $N` behaviour. All that matters is that the
170  * instructions don't get lost.
171  */
172  asm volatile ("call *%[ptr];"
173  _ASM_EXTABLE_HANDLER(-1, 0, %P[hnd])
174  : "=a" (res)
175  : "0" (0),
176  [ptr] "r" (stub),
177  [hnd] "p" (ex_fault)
178  : "memory");
179 
180  if ( res != 0xc0de )
181  xtf_failure("Fail: Instruction stub wasn't executed correctly\n");
182 
183  /*
184  * Execute a 16bit stub.
185  *
186  * Construct a 16bit unreal mode code segment with a 32bit segment limit,
187  * to execute the code with. The stub still runs with 32bit data
188  * segments, which is perfectly valid.
189  */
191  GDTE_SYM(0, 0xfffff, COMMON, CODE, DPL0, R));
192 
193  asm volatile ("push $%c[cs16];"
194  "push $1f;"
195  __ASM_SEL(lretl, lretq) ";"
196 
197  "1: .code16;"
198  "start_16bit:;"
200  "int $" STR(X86_VEC_AVAIL) ";"
201  "ljmpl $%c[cs], $.Ldone;"
202  "end_16bit:;"
203 
204  __ASM_SEL(.code32, .code64) ";"
205  ".Ldone:"
206  : "=a" (res)
207  : "0" (0),
208  [cs] "i" (__KERN_CS),
209  [cs16] "i" (GDTE_AVAIL0 << 3)
210  : "memory");
211 
212  if ( res != 0xc0de )
213  xtf_failure("Fail: 16bit code wasn't executed correctly\n");
214 
215  xtf_success(NULL);
216 }
217 
218 /*
219  * Local variables:
220  * mode: C
221  * c-file-style: "BSD"
222  * c-basic-offset: 4
223  * tab-width: 4
224  * indent-tabs-mode: nil
225  * End:
226  */
#define _ASM_XEN_FEP
Xen Forced Emulation Prefix.
Definition: xen.h:150
Definition: main.c:189
static bool ex_fault(struct cpu_regs *regs, const struct extable_entry *ex)
Definition: main.c:62
#define L1_PT_ENTRIES
Definition: page.h:69
#define IS_DEFINED(x)
Evalute whether the CONFIG_ token x is defined.
Definition: macro_magic.h:67
static intpte_t nl2t[L2_PT_ENTRIES]
Definition: main.c:30
#define XENMEM_populate_physmap
Definition: memory.h:10
unsigned long addr
Definition: idt.h:28
#define __page_aligned_bss
Definition: compiler.h:37
unsigned long * extent_start
Definition: memory.h:13
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 const struct xtf_idte idte
Definition: main.c:47
intpte_t pte_from_virt(const void *va, uint64_t flags)
#define X86_EXC_GP
Definition: processor.h:115
#define barrier()
Definition: compiler.h:30
void panic(const char *fmt,...)
Definition: lib.c:15
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define GDTE_DS32_DPL0
Definition: segment.h:29
#define STR(x)
Stringise an expression, expanding preprocessor tokens.
Definition: macro_magic.h:17
intpte_t pte_from_gfn(unsigned long gfn, uint64_t flags)
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
#define NULL
Definition: stddef.h:12
static intpte_t nl1t[L1_PT_ENTRIES]
Definition: main.c:31
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define memcpy(d, s, n)
Definition: libc.h:36
user_desc gdt[NR_GDT_ENTRIES]
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
static void invlpg(const void *va)
Definition: lib.h:322
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
unsigned long intpte_t
Definition: page.h:152
void test_int_handler(void)
bool test_needs_fep
Boolean indicating whether the test is entirely predicated on the available of the Force Emulation Pr...
Definition: main.c:34
const char test_title[]
The title of the test.
Definition: main.c:14
#define PAGE_SHIFT
Definition: page.h:10
#define L2_PT_ENTRIES
Definition: page.h:70
#define GDTE_AVAIL0
Definition: segment.h:37
#define X86_VEC_AVAIL
Available for test use.
Definition: idt.h:20
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
A guest agnostic represention of IDT information.
Definition: idt.h:26
#define GB(num)
Express num in Gigabytes.
Definition: numbers.h:29
static void write_ss(unsigned int ss)
Definition: lib.h:206
#define __ASM_SEL(c, l)
Definition: asm_macros.h:25
#define DOMID_SELF
Definition: xen.h:70
static long hypercall_memory_op(unsigned int cmd, void *arg)
Definition: hypercall.h:100
#define GDTE_SYM(base, limit,...)
As INIT_GDTE_SYM(), but creates a user_desc object.
__UINT8_TYPE__ uint8_t
Definition: stdint.h:14
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38