Xen Test Framework
traps.c
Go to the documentation of this file.
1 #include <xtf/traps.h>
2 #include <xtf/lib.h>
3 #include <xtf/hypercall.h>
4 #include <xtf/test.h>
5 
6 #include <arch/idt.h>
7 #include <arch/lib.h>
8 #include <arch/processor.h>
9 #include <arch/segment.h>
10 #include <arch/pagetable.h>
11 #include <arch/symbolic-const.h>
12 
13 /* Filled in by pv/head.S */
15 
16 /* Real entry points */
17 void entry_DE(void);
18 void entry_DB(void);
19 void entry_NMI(void);
20 void entry_BP(void);
21 void entry_OF(void);
22 void entry_BR(void);
23 void entry_UD(void);
24 void entry_NM(void);
25 void entry_DF(void);
26 void entry_TS(void);
27 void entry_NP(void);
28 void entry_SS(void);
29 void entry_GP(void);
30 void entry_PF(void);
31 void entry_MF(void);
32 void entry_AC(void);
33 void entry_MC(void);
34 void entry_XM(void);
35 void entry_VE(void);
36 void entry_ret_to_kernel(void);
37 
38 void entry_SYSCALL(void);
39 void entry_SYSENTER(void);
40 void entry_EVTCHN(void);
41 
43 {
44  { X86_EXC_DE, 0|4, __KERN_CS, _u(entry_DE) },
45  { X86_EXC_DB, 0|4, __KERN_CS, _u(entry_DB) },
46  { X86_EXC_NMI, 0|4, __KERN_CS, _u(entry_NMI) },
47  { X86_EXC_BP, 3|4, __KERN_CS, _u(entry_BP) },
48  { X86_EXC_OF, 3|4, __KERN_CS, _u(entry_OF) },
49  { X86_EXC_BR, 0|4, __KERN_CS, _u(entry_BR) },
50  { X86_EXC_UD, 0|4, __KERN_CS, _u(entry_UD) },
51  { X86_EXC_NM, 0|4, __KERN_CS, _u(entry_NM) },
52  { X86_EXC_DF, 0|4, __KERN_CS, _u(entry_DF) },
53  { X86_EXC_TS, 0|4, __KERN_CS, _u(entry_TS) },
54  { X86_EXC_NP, 0|4, __KERN_CS, _u(entry_NP) },
55  { X86_EXC_SS, 0|4, __KERN_CS, _u(entry_SS) },
56  { X86_EXC_GP, 0|4, __KERN_CS, _u(entry_GP) },
57  { X86_EXC_PF, 0|4, __KERN_CS, _u(entry_PF) },
58  { X86_EXC_MF, 0|4, __KERN_CS, _u(entry_MF) },
59  { X86_EXC_AC, 0|4, __KERN_CS, _u(entry_AC) },
60  { X86_EXC_MC, 0|4, __KERN_CS, _u(entry_MC) },
61  { X86_EXC_XM, 0|4, __KERN_CS, _u(entry_XM) },
62  { X86_EXC_VE, 0|4, __KERN_CS, _u(entry_VE) },
63 
64  { X86_VEC_RET2KERN, 3|4, __KERN_CS, _u(entry_ret_to_kernel) },
65 
66  { 0, 0, 0, 0 }, /* Sentinel. */
67 };
68 
69 int xtf_set_idte(unsigned int vector, const struct xtf_idte *idte)
70 {
71  struct xen_trap_info ti[2] =
72  {
73  { vector, idte->dpl | 4, idte->cs, idte->addr },
74  { 0, 0, 0, 0 }, /* Sentinel. */
75  };
76 
77  return hypercall_set_trap_table(ti);
78 }
79 
80 static bool __maybe_unused ex_pf_user(struct cpu_regs *regs,
81  const struct extable_entry *ex)
82 {
83  if ( regs->entry_vector == X86_EXC_PF && read_cr2() == 0xfff )
84  {
85  regs->ax = true;
86  regs->ip = ex->fixup;
87 
88  return true;
89  }
90 
91  return false;
92 }
93 
94 static int remap_linear(const void *linear, uint64_t flags)
95 {
96  intpte_t nl1e = pte_from_virt(linear, flags);
97 
98  return hypercall_update_va_mapping(_u(linear), nl1e, UVMF_INVLPG);
99 }
100 
101 static int __maybe_unused remap_linear_range(const void *start, const void *end,
102  uint64_t flags)
103 {
104  int ret = 0;
105 
106  while ( !ret && start < end )
107  {
108  ret = remap_linear(start, flags);
109  start += PAGE_SIZE;
110  }
111 
112  return ret;
113 }
114 
115 static void init_callbacks(void)
116 {
117  /* PV equivalent of `lidt`. */
118  int rc = hypercall_set_trap_table(pv_default_trap_info);
119 
120  if ( rc )
121  panic("Failed to set trap table: %d\n", rc);
122 
123  xen_callback_register_t cb[] = {
124  {
126  .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_EVTCHN)),
127  },
128 #ifdef __x86_64__
129  {
130  .type = CALLBACKTYPE_syscall,
131  .flags = CALLBACKF_mask_events,
132  .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_SYSCALL)),
133  },
134 #endif
135  {
136  .type = CALLBACKTYPE_syscall32,
137  .flags = CALLBACKF_mask_events,
138  .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_SYSCALL)),
139  },
140  {
141  .type = CALLBACKTYPE_sysenter,
142  .flags = CALLBACKF_mask_events,
143  .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_SYSENTER)),
144  },
145  };
146 
147  for ( unsigned int i = 0; i < ARRAY_SIZE(cb); ++i )
148  {
149  rc = hypercall_register_callback(&cb[i]);
150  if ( rc )
151  panic("Failed to register callback[%u]: %d\n", i, rc);
152  }
153 }
154 
155 void arch_init_traps(void)
156 {
157  int rc;
158 
159  init_callbacks();
160 
161  /* Register gdt[] with Xen. Need to map it read-only first. */
162  if ( remap_linear(gdt, PF_SYM(AD, P)) )
163  panic("Unable to remap gdt[] as read-only\n");
164 
165  unsigned long gdt_frames[] = {
166  virt_to_mfn(gdt),
167  };
168  BUILD_BUG_ON(NR_GDT_ENTRIES > (PAGE_SIZE / sizeof(user_desc)));
169 
170  rc = hypercall_set_gdt(gdt_frames, NR_GDT_ENTRIES);
171  if ( rc )
172  panic("Failed to set gdt: %d\n", rc);
173 
174  /* PV equivalent of setting tss.{esp0,ss0}. */
175  rc = hypercall_stack_switch(__KERN_DS, &boot_stack[2 * PAGE_SIZE]);
176  if ( rc )
177  panic("Failed to set kernel stack: %d\n", rc);
178 
179  write_ds(__USER_DS);
180  write_es(__USER_DS);
181  write_fs(__USER_DS);
182  write_gs(__USER_DS);
183 
184 #ifdef __x86_64__
185  /*
186  * Set the user pagetables (only applicable to 64bit PV).
187  *
188  * XTF uses a shared user/kernel address space, so register the kernel
189  * %cr3 as the user %cr3.
190  */
191  mmuext_op_t ext =
192  {
194  .arg1.mfn = read_cr3() >> PAGE_SHIFT,
195  };
196 
197  rc = hypercall_mmuext_op(&ext, 1, NULL, DOMID_SELF);
198  if ( rc )
199  panic("Failed to set user %%cr3: %d\n", rc);
200 
201 #elif defined(__i386__)
203  {
204  /*
205  * XTF uses a shared user/kernel address space, and _PAGE_USER must be
206  * set to permit cpl3 access to the virtual addresses without taking a
207  * pagefault.
208  *
209  * PV guests and Xen share a virtual address space, and before Xen
210  * 4.7, Xen's setting of CR4.{SMEP,SMAP} leaked with 32bit PV guests.
211  * On hardware which supports SMEP/SMAP, older versions of Xen must be
212  * booted with 'smep=0 smap=0' for pv32pae tests to run.
213  */
214 
215  /*
216  * First, probe whether Xen is leaking its SMEP/SMAP settings.
217  */
218  intpte_t nl1e = pte_from_gfn(pfn_to_mfn(0), PF_SYM(AD, U, RW, P));
219  bool leaked = false;
220 
221  /* Remap the page at 0 with _PAGE_USER. */
223  if ( rc )
224  panic("Failed to remap page at NULL with _PAGE_USER: %d\n", rc);
225 
226  /*
227  * Write a `ret` instruction into the page at 0 (will be caught by
228  * leaked SMAP), then attempt to call at the `ret` instruction (will
229  * be caught by leaked SMEP).
230  */
231  asm volatile ("1: movb $0xc3, (%[ptr]);"
232  "call *%[ptr];"
233  "jmp 3f;"
234  "2: ret;"
235  "3:"
236  _ASM_EXTABLE_HANDLER(1b, 3b, %P[rec])
237  _ASM_EXTABLE_HANDLER(0xfff, 2b, %P[rec])
238  : "+a" (leaked)
239  : [ptr] "r" (0xfff),
240  [rec] "p" (ex_pf_user));
241 
242  if ( leaked )
243  panic("Xen's SMEP/SMAP settings leaked into guest context.\n"
244  "Must boot this Xen with 'smep=0 smap=0' to run this test.\n");
245 
246  /*
247  * If we have got this far, SMEP/SMAP are not leaking into guest
248  * context. Proceed with remapping all mappings as _PAGE_USER.
249  */
250  uint64_t *l3 = _p(pv_start_info->pt_base);
251  unsigned long linear = 0;
252 
253  while ( linear < __HYPERVISOR_VIRT_START_PAE )
254  {
255  unsigned int i3 = l3_table_offset(linear);
256 
257  if ( !(l3[i3] & _PAGE_PRESENT) )
258  {
259  linear += 1UL << L3_PT_SHIFT;
260  continue;
261  }
262 
263  uint64_t *l2 = maddr_to_virt(pte_to_paddr(l3[i3]));
264  unsigned int i2 = l2_table_offset(linear);
265 
266  if ( !(l2[i2] & _PAGE_PRESENT) )
267  {
268  linear += 1UL << L2_PT_SHIFT;
269  continue;
270  }
271 
272  uint64_t *l1 = maddr_to_virt(pte_to_paddr(l2[i2]));
273  unsigned int i1 = l1_table_offset(linear);
274 
275  if ( !(l1[i1] & _PAGE_PRESENT) )
276  {
277  linear += 1UL << L1_PT_SHIFT;
278  continue;
279  }
280 
281  if ( !(l1[i1] & _PAGE_USER) )
282  {
284  linear, l1[i1] | _PAGE_USER, UVMF_INVLPG);
285  if ( rc )
286  panic("update_va_mapping(%p, 0x%016"PRIx64") failed: %d\n",
287  _p(linear), l1[i1] | _PAGE_USER, rc);
288  }
289 
290  linear += 1UL << L1_PT_SHIFT;
291  }
292  }
293  else
294  {
295  /*
296  * If we haven't applied blanket PAGE_USER mappings, remap the
297  * structures which specifically want to be user.
298  */
299  extern const char __start_user_text[], __end_user_text[];
300  extern const char __start_user_data[], __end_user_data[];
301  extern const char __start_user_bss[], __end_user_bss[];
302 
303  remap_linear_range(__start_user_text, __end_user_text,
304  PF_SYM(AD, U, RW, P));
305 
306  remap_linear_range(__start_user_data, __end_user_data,
307  PF_SYM(AD, U, RW, P));
308 
309  remap_linear_range(__start_user_bss, __end_user_bss,
310  PF_SYM(AD, U, RW, P));
311  }
312 #endif
313 
314  /* Unmap page at 0 to catch errors with NULL pointers. */
316  if ( rc )
317  panic("Failed to unmap page at NULL: %d\n", rc);
318 }
319 
321 {
322  /*
323  * For both architectures, put the stack pointer into an invalid place and
324  * attempt to use it. Xen should fail to create a bounce frame and crash
325  * the domain.
326  */
327  asm volatile(
328  "mov %0, %%" _ASM_SP ";"
329  "pushf"
330  ::
331 #ifdef __i386__
332  "i" (0xfbadc0deUL) /* 32bit: In the read-only M2P mapping. */
333 #else
334  "i" (0x800000000badc0deUL) /* 64bit: Non-canonical region. */
335 #endif
336  : "memory" );
337 
338  /*
339  * Attempt to crash failed. Give up and sit in a loop.
340  */
341  asm volatile("1: hlt;"
342  "pause;"
343  "jmp 1b"
344  ::: "memory");
345  unreachable();
346 }
347 
348 /*
349  * Local variables:
350  * mode: C
351  * c-file-style: "BSD"
352  * c-basic-offset: 4
353  * tab-width: 4
354  * indent-tabs-mode: nil
355  * End:
356  */
void entry_NP(void)
static void init_callbacks(void)
Definition: traps.c:115
static long hypercall_set_trap_table(const struct xen_trap_info *ti)
Definition: hypercall.h:55
void entry_OF(void)
API for tests.
#define L2_PT_SHIFT
Definition: page.h:67
uint8_t flags
Definition: xen.h:34
unsigned long fixup
Fixup address.
Definition: extable.h:67
void entry_BR(void)
#define __HYPERVISOR_VIRT_START_PAE
Definition: xen-x86_32.h:18
#define MMUEXT_NEW_USER_BASEPTR
Definition: xen.h:347
Macros for creating constants using mnemonics.
void arch_crash_hard(void)
Definition: traps.c:147
#define __noreturn
Definition: compiler.h:10
static long hypercall_update_va_mapping(unsigned long linear, uint64_t npte, enum XEN_UVMF flags)
Definition: hypercall.h:105
void entry_AC(void)
static int remap_linear(const void *linear, uint64_t flags)
Definition: traps.c:94
unsigned long addr
Definition: idt.h:28
void entry_PF(void)
#define ARRAY_SIZE(a)
Definition: lib.h:8
#define X86_EXC_DF
Definition: processor.h:99
#define X86_EXC_MF
Definition: processor.h:107
void entry_ret_to_kernel(void)
#define X86_EXC_OF
Definition: processor.h:95
paddr_t pte_to_paddr(intpte_t pte)
static int hypercall_register_callback(const xen_callback_register_t *arg)
Definition: hypercall.h:208
unsigned long pfn_to_mfn(unsigned long pfn)
#define CALLBACKTYPE_event
Definition: callback.h:18
void entry_GP(void)
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
x86 IDT vector infrastructure.
#define X86_EXC_MC
Definition: processor.h:109
intpte_t pte_from_virt(const void *va, uint64_t flags)
#define X86_EXC_GP
Definition: processor.h:104
void panic(const char *fmt,...)
Definition: lib.c:15
#define X86_EXC_NM
Definition: processor.h:98
void entry_UD(void)
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
static long hypercall_stack_switch(const unsigned int ss, const void *sp)
Definition: hypercall.h:75
unsigned int l3_table_offset(unsigned long linear)
void entry_SYSCALL(void)
void entry_DB(void)
#define _PAGE_PRESENT
Definition: page.h:25
static void write_gs(unsigned int gs)
Definition: lib.h:201
intpte_t pte_from_gfn(unsigned long gfn, uint64_t flags)
static bool ex_pf_user(struct cpu_regs *regs, const struct extable_entry *ex)
Definition: traps.c:80
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
#define X86_EXC_BP
Definition: processor.h:94
#define X86_EXC_DE
Definition: processor.h:91
#define PRIx64
Definition: inttypes.h:18
static unsigned long read_cr2(void)
Definition: lib.h:234
void entry_MF(void)
uint8_t vector
Definition: xen.h:33
unsigned int cs
Definition: idt.h:29
#define X86_EXC_XM
Definition: processor.h:110
unsigned long virt_to_mfn(const void *va)
void entry_TS(void)
#define NULL
Definition: stddef.h:12
void entry_MC(void)
void entry_NMI(void)
#define CALLBACKTYPE_syscall32
Definition: callback.h:49
void entry_DE(void)
void arch_init_traps(void)
Definition: traps.c:86
void entry_VE(void)
static int remap_linear_range(const void *start, const void *end, uint64_t flags)
Definition: traps.c:101
static unsigned long read_cr3(void)
Definition: lib.h:243
unsigned long pt_base
Definition: xen.h:223
user_desc gdt[NR_GDT_ENTRIES]
__UINT64_TYPE__ uint64_t
Definition: stdint.h:17
#define CALLBACKF_mask_events
Definition: callback.h:56
Definition: xen.h:355
void * maddr_to_virt(uint64_t maddr)
unsigned int l1_table_offset(unsigned long linear)
Exception table entry.
Definition: extable.h:64
#define CALLBACKTYPE_syscall
Definition: callback.h:24
static void write_ds(unsigned int ds)
Definition: lib.h:186
void entry_BP(void)
#define X86_EXC_NP
Definition: processor.h:102
static void write_es(unsigned int es)
Definition: lib.h:191
unsigned long intpte_t
Definition: page.h:152
static const struct xtf_idte idte
Definition: main.c:266
#define CALLBACKTYPE_sysenter
Definition: callback.h:43
static long hypercall_set_gdt(const unsigned long *mfns, unsigned int entries)
Definition: hypercall.h:69
unsigned int dpl
Definition: idt.h:29
#define PAGE_SHIFT
Definition: page.h:10
#define X86_EXC_UD
Definition: processor.h:97
#define X86_EXC_VE
Definition: processor.h:111
void entry_XM(void)
#define X86_EXC_AC
Definition: processor.h:108
#define INIT_XEN_CALLBACK(_cs, _ip)
Definition: xen-x86_32.h:88
#define unreachable()
Definition: compiler.h:29
uint8_t boot_stack[3 *PAGE_SIZE]
Definition: setup.c:21
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define X86_EXC_DB
Definition: processor.h:92
#define L1_PT_SHIFT
Definition: page.h:66
#define X86_EXC_BR
Definition: processor.h:96
#define PAGE_SIZE
Definition: page.h:11
#define _PAGE_USER
Definition: page.h:27
bool test_wants_user_mappings
Boolean indicating whether the test wants user mappings or not.
Definition: setup.c:287
#define X86_VEC_RET2KERN
Return to kernel mode.
Definition: idt.h:15
A guest agnostic represention of IDT information.
Definition: idt.h:26
#define _ASM_SP
Definition: asm_macros.h:37
static long hypercall_mmuext_op(const mmuext_op_t ops[], unsigned int count, unsigned int *done, unsigned int foreigndom)
Definition: hypercall.h:138
#define X86_EXC_NMI
Definition: processor.h:93
#define X86_EXC_SS
Definition: processor.h:103
void entry_NM(void)
struct xen_trap_info pv_default_trap_info[]
Definition: traps.c:42
#define X86_EXC_TS
Definition: processor.h:101
#define BUILD_BUG_ON(cond)
Definition: lib.h:24
unsigned int cmd
Definition: xen.h:356
xen_pv_start_info_t * pv_start_info
Definition: traps.c:14
#define DOMID_SELF
Definition: xen.h:70
#define X86_EXC_PF
Definition: processor.h:105
unsigned int l2_table_offset(unsigned long linear)
#define __maybe_unused
Definition: compiler.h:13
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 NR_GDT_ENTRIES
Definition: segment.h:44
void entry_SYSENTER(void)
void entry_DF(void)
void entry_SS(void)
void entry_EVTCHN(void)