Xen Test Framework
main.c
Go to the documentation of this file.
1 
41 #include <xtf.h>
42 
43 const char test_title[] = "PV IOPL emulation";
44 
46 
48 static void stub_cli(void)
49 {
50  asm volatile ("1: cli; 2:"
51  _ASM_EXTABLE(1b, 2b));
52 }
53 
55 static void stub_outb(void)
56 {
57  asm volatile ("1: outb %b0, $0x80; 2:"
58  _ASM_EXTABLE(1b, 2b)
59  :: "a" (0));
60 }
61 
62 static const struct insn
63 {
64  const char *name;
65  void (*fn)(void);
66 }
67  insn_sequence[] =
68 {
69  { "cli", stub_cli, },
70  { "outb", stub_outb, },
71 };
72 
73 static struct expectation
74 {
75  const char *insn;
76  bool user;
77  bool fault;
78 }
80 
82 static void expect(const char *insn, bool user, bool fault)
83 {
84  expectation = (struct expectation){insn, user, fault, };
86 }
87 
89 static void check(void)
90 {
91  unsigned int entries = xtf_exlog_entries();
92  const char *mode = expectation.user ? "user" : "kernel";
93 
94  if ( expectation.fault )
95  {
96  if ( entries != 1 )
97  {
98  xtf_failure("Fail (%s %s): Expected 1 exception, got %u\n",
99  mode, expectation.insn, entries);
101  return;
102  }
103 
104  exlog_entry_t *entry = xtf_exlog_entry(0);
105  if ( !entry )
106  {
107  xtf_failure("Fail (%s %s): Unable to retrieve exception log\n",
108  mode, expectation.insn);
109  return;
110  }
111 
112  if ( (entry->ev != X86_EXC_GP) || (entry->ec != 0) )
113  {
114  xtf_failure("Fail (%s %s): Expected #GP[0], got %2u[%04x]\n",
115  mode, expectation.insn, entry->ev, entry->ec);
116  return;
117  }
118  }
119  else
120  {
121  if ( entries != 0 )
122  {
123  xtf_failure("Fail (%s %s): Expected no exceptions, got %u\n",
124  mode, expectation.insn, entries);
126  return;
127  }
128  }
129 }
130 
131 struct test
132 {
133  void (*set_iopl)(unsigned int iopl);
134  bool (*should_fault)(bool user, unsigned int iopl);
135 };
136 
138 static void run_test(const struct test *t)
139 {
140  unsigned int i, iopl;
141 
142  xtf_exlog_start();
143 
144  for ( iopl = 0; iopl <= 3; ++iopl )
145  {
146  /* vIOPL 2 is not interesting to test. */
147  if ( iopl == 2 )
148  continue;
149 
150  printk(" vIOPL %u\n", iopl);
151  t->set_iopl(iopl);
152 
153  for ( i = 0; i < ARRAY_SIZE(insn_sequence); ++i )
154  {
155  const struct insn *seq = &insn_sequence[i];
156 
157  /* Run insn in kernel. */
158  expect(seq->name, 0, t->should_fault(0, iopl));
159  seq->fn();
160  check();
161 
162  /* Run insn in userspace. */
163  expect(seq->name, 1, t->should_fault(1, iopl));
164  exec_user_void(seq->fn);
165 
166  check();
167  }
168  }
169 
170  xtf_exlog_stop();
171 }
172 
173 static void hypercall_set_iopl(unsigned int iopl)
174 {
176 }
177 
178 static bool hypercall_should_fault(bool user, unsigned int iopl)
179 {
180  /*
181  * Kernel has vCPL 1, userspace has vCPL 3
182  */
183  switch ( iopl )
184  {
185  case 0:
186  /* Both kernel and userspace should fault. */
187  return true;
188 
189  case 1:
190  case 2:
191  /* Kernel should succeed, user should fault. */
192  return user;
193 
194  case 3:
195  /* Both kernel and userspace should succeed. */
196  return false;
197 
198  default:
199  panic("Bad vIOPL %u\n", iopl);
200  }
201 }
202 
204 static const struct test hypercall =
205 {
207  .should_fault = hypercall_should_fault,
208 };
209 
210 static void nop(void){}
211 static void vmassist_set_iopl(unsigned int iopl)
212 {
213  /*
214  * All that needs to happen to set iopl is to execute an iret hypercall
215  * with the appropriate iopl set. Reuse the exec_user infrastructure to
216  * issue the iret, and execute nothing interesting in user context.
217  */
218  exec_user_efl_or_mask = iopl << 12;
220 }
221 
222 static bool vmassist_should_fault(bool user, unsigned int iopl)
223 {
224  /*
225  * Kernel has vCPL 0, userspace has vCPL 3.
226  *
227  * Kenrel should never fault, while userspace should only not fault at
228  * iopl 3.
229  */
230  if ( !user )
231  return false;
232 
233  return iopl != 3;
234 }
235 
237 static const struct test vmassist =
238 {
240  .should_fault = vmassist_should_fault,
241 };
242 
243 void test_main(void)
244 {
245  const struct test *test;
246 
251  if ( !strcmp((char *)pv_start_info->cmd_line, "hypercall") )
252  {
253  printk("Test: PHYSDEVOP_set_iopl\n");
254  test = &hypercall;
255  }
256  else if ( !strcmp((char *)pv_start_info->cmd_line, "vmassist") )
257  {
260  return xtf_skip("VMASST_TYPE_architectural_iopl not detected\n");
261 
262  printk("Test: VMASST_TYPE_architectural_iopl\n");
263  test = &vmassist;
264  }
265  else
266  return xtf_error("Unknown test to run\n");
267 
268  /* Run the chosen test. */
269  run_test(test);
270  xtf_success(NULL);
271 }
272 
273 /*
274  * Local variables:
275  * mode: C
276  * c-file-style: "BSD"
277  * c-basic-offset: 4
278  * tab-width: 4
279  * indent-tabs-mode: nil
280  * End:
281  */
Definition: main.c:62
#define VMASST_CMD_enable
Definition: xen.h:78
exlog_entry_t * xtf_exlog_entry(unsigned int idx)
Definition: exlog.c:32
static void stub_cli(void)
Stub CLI instruction with #GP fixup.
Definition: main.c:48
static const struct insn insn_sequence[]
Sequence of instructions to run.
static const struct test vmassist
VMASSIT based IOPL interface.
Definition: main.c:237
void xtf_exlog_dump_log(void)
Definition: exlog.c:63
static void nop(void)
Definition: main.c:210
static void run_test(const struct test *t)
Test the instruction sequence using a specific iopl interface.
Definition: main.c:138
static bool vmassist_should_fault(bool user, unsigned int iopl)
Definition: main.c:222
#define ARRAY_SIZE(a)
Definition: lib.h:8
static void vmassist_set_iopl(unsigned int iopl)
Definition: main.c:211
static struct expectation expectation
Details about the stub under test.
#define X86_EXC_GP
Definition: processor.h:104
void panic(const char *fmt,...)
Definition: lib.c:15
void printk(const char *fmt,...)
Definition: console.c:134
#define PHYSDEVOP_set_iopl
Definition: physdev.h:12
const char * name
Definition: main.c:64
unsigned int xtf_exlog_entries(void)
Definition: exlog.c:27
static void check(void)
Check the exception long against the expected details.
Definition: main.c:89
static void hypercall_set_iopl(unsigned int iopl)
Definition: main.c:173
void xtf_exlog_reset(void)
Definition: exlog.c:16
Definition: exlog.h:11
const char * insn
Definition: main.c:75
static long hypercall_physdev_op(unsigned int cmd, void *arg)
Definition: hypercall.h:162
bool user
Definition: main.c:76
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static bool hypercall_should_fault(bool user, unsigned int iopl)
Definition: main.c:178
unsigned long exec_user_efl_or_mask
Definition: traps.c:17
static long hypercall_vm_assist(unsigned int cmd, unsigned int type)
Definition: hypercall.h:127
_Bool bool
Definition: stdbool.h:9
static void exec_user_void(void(*fn)(void))
Definition: lib.h:70
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
bool test_wants_user_mappings
Boolean indicating whether the test wants user mappings or not.
Definition: main.c:26
static void expect(const char *insn, bool user, bool fault)
Latch details of the stub under test.
Definition: main.c:82
void(* set_iopl)(unsigned int iopl)
Definition: main.c:133
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
void(* fn)(void)
Definition: main.c:65
static void stub_outb(void)
Stub OUTB instruction with #GP fixup.
Definition: main.c:55
static const struct test hypercall
Hypercall based IOPL interface.
Definition: main.c:204
static bool user
Whether to run the stub in user or supervisor mode.
Definition: main.c:161
const char test_title[]
The title of the test.
Definition: main.c:14
#define VMASST_TYPE_architectural_iopl
Definition: xen.h:87
uint16_t ev
Definition: exlog.h:14
void xtf_exlog_stop(void)
Definition: exlog.c:21
#define strcmp(s1, s2)
Definition: libc.h:27
Definition: main.c:38
void xtf_exlog_start(void)
Definition: exlog.c:10
bool(* should_fault)(bool user, unsigned int iopl)
Definition: main.c:134
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
int8_t cmd_line[MAX_GUEST_CMDLINE]
Definition: xen.h:231
uint16_t ec
Definition: exlog.h:14
xen_pv_start_info_t * pv_start_info
Definition: traps.c:14
bool fault
Definition: main.c:77
#define _ASM_EXTABLE(fault, fixup)
Create an exception table entry.
Definition: extable.h:50