Xen Test Framework
main.c
Go to the documentation of this file.
1
41#include <xtf.h>
42
43const char test_title[] = "PV IOPL emulation";
44
45static 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
57static 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
69static 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
81static 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
93static 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, },
101
102enum mode { KERN, USER };
103struct test {
104 void (*set_iopl)(unsigned int iopl);
105 bool (*should_fault)(enum mode, unsigned int iopl);
106};
107
108static 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
143static void hypercall_set_iopl(unsigned int iopl)
144{
146}
147
148static 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
173static const struct test hypercall = {
175 .should_fault = hypercall_should_fault,
176};
177
178static void __user_text nop(void) {}
179static 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
190static 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
204static const struct test vmassist = {
206 .should_fault = vmassist_should_fault,
207};
208
209void 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);
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 */
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
xen_pv_start_info_t * pv_start_info
Definition: traps.c:14
unsigned long exec_user_efl_or_mask
Definition: traps.c:16
#define __user_text
Definition: compiler.h:33
void printk(const char *fmt,...)
Definition: console.c:134
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:110
const char test_title[]
The title of the test.
Definition: main.c:24
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
static long hypercall_physdev_op(unsigned int cmd, void *arg)
Definition: hypercall.h:172
static long hypercall_vm_assist(unsigned int cmd, unsigned int type)
Definition: hypercall.h:137
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define ARRAY_SIZE(a)
Definition: lib.h:8
static unsigned long exec_user(unsigned long(*fn)(void))
Definition: lib.h:62
static void exec_user_void(void(*fn)(void))
Definition: lib.h:70
void panic(const char *fmt,...)
Definition: lib.c:15
#define strcmp(s1, s2)
Definition: libc.h:27
#define GP
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define MASK_INSR(v, m)
Definition: numbers.h:41
#define PHYSDEVOP_set_iopl
Definition: physdev.h:12
#define X86_EFLAGS_IOPL
Definition: processor.h:17
static unsigned long stub_outb(void)
Definition: main.c:69
mode
Definition: main.c:102
@ KERN
Definition: main.c:102
@ USER
Definition: main.c:102
static bool hypercall_should_fault(enum mode mode, unsigned int iopl)
Definition: main.c:148
static unsigned long stub_user_outb(void)
Definition: main.c:81
static bool vmassist_should_fault(enum mode mode, unsigned int iopl)
Definition: main.c:190
static const struct insn insns[]
static const struct test vmassist
Definition: main.c:204
static void nop(void)
Definition: main.c:178
static const struct test hypercall
Definition: main.c:173
static void run_test(const struct test *t)
Definition: main.c:108
static unsigned long stub_cli(void)
Definition: main.c:45
static void hypercall_set_iopl(unsigned int iopl)
Definition: main.c:143
static void vmassist_set_iopl(unsigned int iopl)
Definition: main.c:179
static unsigned long stub_user_cli(void)
Definition: main.c:57
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
_Bool bool
Definition: stdbool.h:9
#define NULL
Definition: stddef.h:12
Definition: main.c:93
unsigned long(* user_fn)(void)
Definition: main.c:96
unsigned long(* fn)(void)
Definition: main.c:95
const char * name
Definition: main.c:94
Definition: main.c:39
bool(* should_fault)(enum mode, unsigned int iopl)
Definition: main.c:105
void(* set_iopl)(unsigned int iopl)
Definition: main.c:104
int8_t cmd_line[MAX_GUEST_CMDLINE]
Definition: xen.h:231
#define VMASST_TYPE_architectural_iopl
Definition: xen.h:87
#define VMASST_CMD_enable
Definition: xen.h:78