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 
45 static unsigned long stub_cli(void)
46 {
47  unsigned long fault = 0;
48 
49  asm ("1: cli; 2:"
50  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
51  : "+a" (fault)
52  : [rec] "p" (ex_record_fault_eax));
53 
54  return fault;
55 }
56 
57 static unsigned long __user_text stub_user_cli(void)
58 {
59  unsigned long fault = 0;
60 
61  asm ("1: cli; 2:"
62  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
63  : "+a" (fault)
64  : [rec] "p" (ex_record_fault_eax));
65 
66  return fault;
67 }
68 
69 static unsigned long stub_outb(void)
70 {
71  unsigned long fault = 0;
72 
73  asm ("1: outb %b0, $0x80; 2:"
74  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
75  : "+a" (fault) /* Overloaded as the input to OUTB */
76  : [rec] "p" (ex_record_fault_eax));
77 
78  return fault;
79 }
80 
81 static unsigned long __user_text stub_user_outb(void)
82 {
83  unsigned long fault = 0;
84 
85  asm ("1: outb %b0, $0x80; 2:"
86  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
87  : "+a" (fault) /* Overloaded as the input to OUTB */
88  : [rec] "p" (ex_record_fault_eax));
89 
90  return fault;
91 }
92 
93 static const struct insn {
94  const char *name;
95  unsigned long (*fn)(void);
96  unsigned long (*user_fn)(void);
97 } insns[] = {
98  { "cli", stub_cli, stub_user_cli, },
99  { "outb", stub_outb, stub_user_outb, },
100 };
101 
102 enum mode { KERN, USER };
103 struct test {
104  void (*set_iopl)(unsigned int iopl);
105  bool (*should_fault)(enum mode, unsigned int iopl);
106 };
107 
108 static void run_test(const struct test *t)
109 {
110  for ( unsigned int iopl = 0; iopl <= 3; ++iopl )
111  {
112  /* vIOPL 2 is not interesting to test. */
113  if ( iopl == 2 )
114  continue;
115 
116  printk(" vIOPL %u\n", iopl);
117  t->set_iopl(iopl);
118 
119  for ( unsigned int i = 0; i < ARRAY_SIZE(insns); ++i )
120  {
121  const struct insn *insn = &insns[i];
122  exinfo_t exp, got;
123 
124  /* Run insn in kernel. */
125  exp = t->should_fault(KERN, iopl) ? EXINFO_SYM(GP, 0) : 0;
126  got = insn->fn();
127 
128  if ( exp != got )
129  xtf_failure("Fail: kern %s, expected %pe, got %pe\n",
130  insn->name, _p(exp), _p(got));
131 
132  /* Run insn in userspace. */
133  exp = t->should_fault(USER, iopl) ? EXINFO_SYM(GP, 0) : 0;
134  got = exec_user(insn->user_fn);
135 
136  if ( exp != got )
137  xtf_failure("Fail: user %s, expected %pe, got %pe\n",
138  insn->name, _p(exp), _p(got));
139  }
140  }
141 }
142 
143 static void hypercall_set_iopl(unsigned int iopl)
144 {
146 }
147 
148 static bool hypercall_should_fault(enum mode mode, unsigned int iopl)
149 {
150  /*
151  * Kernel has vCPL 1, userspace has vCPL 3
152  */
153  switch ( iopl )
154  {
155  case 0:
156  /* Both kernel and userspace should fault. */
157  return true;
158 
159  case 1:
160  case 2:
161  /* Kernel should succeed, user should fault. */
162  return mode == USER;
163 
164  case 3:
165  /* Both kernel and userspace should succeed. */
166  return false;
167 
168  default:
169  panic("Bad vIOPL %u\n", iopl);
170  }
171 }
172 
173 static const struct test hypercall = {
175  .should_fault = hypercall_should_fault,
176 };
177 
178 static void __user_text nop(void) {}
179 static void vmassist_set_iopl(unsigned int iopl)
180 {
181  /*
182  * All that needs to happen to set iopl is to execute an iret hypercall
183  * with the appropriate iopl set. Reuse the exec_user infrastructure to
184  * issue the iret, and execute nothing interesting in user context.
185  */
188 }
189 
190 static bool vmassist_should_fault(enum mode mode, unsigned int iopl)
191 {
192  /*
193  * Kernel has vCPL 0, userspace has vCPL 3.
194  *
195  * Kenrel should never fault, while userspace should only not fault at
196  * iopl 3.
197  */
198  if ( mode == KERN )
199  return false;
200 
201  return iopl != 3;
202 }
203 
204 static const struct test vmassist = {
206  .should_fault = vmassist_should_fault,
207 };
208 
209 void test_main(void)
210 {
211  const char *cmdline = (const char *)pv_start_info->cmd_line;
212  const struct test *test;
213 
218  if ( !strcmp(cmdline, "hypercall") )
219  {
220  printk("Test: PHYSDEVOP_set_iopl\n");
221  test = &hypercall;
222  }
223  else if ( !strcmp(cmdline, "vmassist") )
224  {
227  return xtf_skip("VMASST_TYPE_architectural_iopl not detected\n");
228 
229  printk("Test: VMASST_TYPE_architectural_iopl\n");
230  test = &vmassist;
231  }
232  else
233  return xtf_error("Unknown test to run\n");
234 
235  /* Run the chosen test. */
236  run_test(test);
237  xtf_success(NULL);
238 }
239 
240 /*
241  * Local variables:
242  * mode: C
243  * c-file-style: "BSD"
244  * c-basic-offset: 4
245  * tab-width: 4
246  * indent-tabs-mode: nil
247  * End:
248  */
unsigned long(* user_fn)(void)
Definition: main.c:96
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
Definition: main.c:93
#define VMASST_CMD_enable
Definition: xen.h:78
static const struct test vmassist
Definition: main.c:204
static void nop(void)
Definition: main.c:178
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
static void run_test(const struct test *t)
Definition: main.c:108
static unsigned long stub_user_cli(void)
Definition: main.c:57
static unsigned long stub_user_outb(void)
Definition: main.c:81
#define ARRAY_SIZE(a)
Definition: lib.h:8
static void vmassist_set_iopl(unsigned int iopl)
Definition: main.c:179
bool(* should_fault)(enum mode, unsigned int iopl)
Definition: main.c:105
Definition: main.c:102
void panic(const char *fmt,...)
Definition: lib.c:15
mode
Definition: main.c:102
void printk(const char *fmt,...)
Definition: console.c:134
#define PHYSDEVOP_set_iopl
Definition: physdev.h:12
static void hypercall_set_iopl(unsigned int iopl)
Definition: main.c:143
#define __user_text
Definition: compiler.h:33
static long hypercall_physdev_op(unsigned int cmd, void *arg)
Definition: hypercall.h:172
Definition: main.c:102
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
unsigned long exec_user_efl_or_mask
Definition: traps.c:16
static long hypercall_vm_assist(unsigned int cmd, unsigned int type)
Definition: hypercall.h:137
_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
static const struct insn insns[]
#define GP
void(* set_iopl)(unsigned int iopl)
Definition: main.c:104
static unsigned long stub_outb(void)
Definition: main.c:69
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
static const struct test hypercall
Definition: main.c:173
const char test_title[]
The title of the test.
Definition: main.c:14
static bool vmassist_should_fault(enum mode mode, unsigned int iopl)
Definition: main.c:190
static bool hypercall_should_fault(enum mode mode, unsigned int iopl)
Definition: main.c:148
#define VMASST_TYPE_architectural_iopl
Definition: xen.h:87
static unsigned long exec_user(unsigned long(*fn)(void))
Definition: lib.h:62
#define strcmp(s1, s2)
Definition: libc.h:27
Definition: main.c:38
const char * name
Definition: main.c:94
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
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
xen_pv_start_info_t * pv_start_info
Definition: traps.c:14
unsigned long(* fn)(void)
Definition: main.c:95
#define X86_EFLAGS_IOPL
Definition: processor.h:17
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define MASK_INSR(v, m)
Definition: numbers.h:41
static unsigned long stub_cli(void)
Definition: main.c:45