const char test_title[] = "Guest CPUID Faulting support";
-bool test_wants_user_mappings = true;
-
unsigned long stub_cpuid(void)
{
unsigned int fault = 0, tmp;
return fault;
}
+unsigned long __user_text stub_user_cpuid(void)
+{
+ unsigned int fault = 0, tmp;
+
+ asm volatile("1: cpuid; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi)
+ : "=a" (tmp), "+D" (fault)
+ : "a" (0)
+ : "ebx", "ecx", "edx");
+
+ return fault;
+}
+
unsigned long stub_fep_cpuid(void)
{
unsigned int fault = 0, tmp;
return fault;
}
+unsigned long __user_text stub_user_fep_cpuid(void)
+{
+ unsigned int fault = 0, tmp;
+
+ asm volatile(_ASM_XEN_FEP
+ "1: cpuid; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi)
+ : "=a" (tmp), "+D" (fault)
+ : "a" (0)
+ : "ebx", "ecx", "edx");
+
+ return fault;
+}
+
static void test_cpuid(bool exp_faulting)
{
/*
unsigned long exp = exp_faulting ? EXINFO_SYM(GP, 0) : 0;
const char *exp_fail_str = exp_faulting ? "didn't fault" : "faulted";
- if ( exec_user(stub_cpuid) != exp )
+ if ( exec_user(stub_user_cpuid) != exp )
xtf_failure("Fail: user cpuid %s\n", exp_fail_str);
- if ( IS_DEFINED(CONFIG_PV) && exec_user(stub_fep_cpuid) != exp )
+ if ( IS_DEFINED(CONFIG_PV) && exec_user(stub_user_fep_cpuid) != exp )
xtf_failure("Fail: user pv cpuid %s\n", exp_fail_str);
- if ( xtf_has_fep && exec_user(stub_fep_cpuid) != exp )
+ if ( xtf_has_fep && exec_user(stub_user_fep_cpuid) != exp )
xtf_failure("Fail: user emulated cpuid %s\n", exp_fail_str);
}
const char test_title[] = "PV IOPL emulation";
-bool test_wants_user_mappings = true;
-
/**
* Execute @p fn at user privilege, folding @p iopl into the iret frame.
*/
_ASM_EXTABLE(1b, 2b));
}
+/** Stub CLI instruction with @#GP fixup. */
+static void __user_text stub_user_cli(void)
+{
+ asm volatile ("1: cli; 2:"
+ _ASM_EXTABLE(1b, 2b));
+}
+
/** Stub OUTB instruction with @#GP fixup. */
static void stub_outb(void)
{
:: "a" (0));
}
+/** Stub OUTB instruction with @#GP fixup. */
+static void __user_text stub_user_outb(void)
+{
+ asm volatile ("1: outb %b0, $0x80; 2:"
+ _ASM_EXTABLE(1b, 2b)
+ :: "a" (0));
+}
+
static const struct insn
{
const char *name;
void (*fn)(void);
+ void (*user_fn)(void);
} /** Sequence of instructions to run. */
insn_sequence[] =
{
- { "cli", stub_cli, },
- { "outb", stub_outb, },
+ { "cli", stub_cli, stub_user_cli, },
+ { "outb", stub_outb, stub_user_outb, },
};
static struct expectation
/* Run insn in userspace. */
expect(seq->name, 1, t->should_fault(1, iopl));
- exec_user_with_iopl(seq->fn, iopl);
+ exec_user_with_iopl(seq->user_fn, iopl);
check();
}
}
.should_fault = hypercall_should_fault,
};
-static void nop(void){}
+static void __user_text nop(void){}
static void vmassist_set_iopl(unsigned int iopl)
{
/*
/* Macro to generate a single test function. */
/* See lowlevel.h for a description of nomenclature. */
-.macro GEN_SINGLE insn, type
+.macro GEN_SINGLE name, insn, type
/* Function label. e.g. stub_int3_red(). */
-ENTRY(stub_\insn\()_\type)
+ENTRY(stub_\name\()_\type)
.ifc \insn, into
/* Ensure the overflow flag is set, to trigger 'into'. */
.endif
/* Label where a fault should occur. e.g. label_int3_red_fault. */
-GLOBAL(label_\insn\()_\type\()_fault)
+GLOBAL(label_\name\()_\type\()_fault)
/*
* Possibly insert a redundant prefix.
.endif
/* Label where a trap should occur. e.g. label_int3_red_trap. */
-GLOBAL(label_\insn\()_\type\()_trap)
+GLOBAL(label_\name\()_\type\()_trap)
/* Function return. */
ret
/* Fixup from fault label to trap label. */
- _ASM_EXTABLE(label_\insn\()_\type\()_fault,
- label_\insn\()_\type\()_trap)
+ _ASM_EXTABLE(label_\name\()_\type\()_fault,
+ label_\name\()_\type\()_trap)
-ENDFUNC(stub_\insn\()_\type)
+ENDFUNC(stub_\name\()_\type)
.endm
/* For a single instruction, generate each test variant. */
.macro GEN_SEQUENCE insn
- GEN_SINGLE \insn reg
- GEN_SINGLE \insn red
- GEN_SINGLE \insn force
- GEN_SINGLE \insn forcered
+ GEN_SINGLE \insn \insn reg
+ GEN_SINGLE \insn \insn red
+ GEN_SINGLE \insn \insn force
+ GEN_SINGLE \insn \insn forcered
.endm
/* Generate test sequences for each instruction. */
GEN_SEQUENCE int_0x1
GEN_SEQUENCE into
+.pushsection .text.user, "ax", @progbits
+
+ /* For a single instruction, generate each user test variant. */
+.macro GEN_SEQUENCE_USER insn
+ GEN_SINGLE user_\insn \insn reg
+ GEN_SINGLE user_\insn \insn red
+ GEN_SINGLE user_\insn \insn force
+ GEN_SINGLE user_\insn \insn forcered
+.endm
+
+ /* Generate user test sequences for each instruction. */
+GEN_SEQUENCE_USER int3
+GEN_SEQUENCE_USER int_0x3
+GEN_SEQUENCE_USER icebp
+GEN_SEQUENCE_USER int_0x1
+GEN_SEQUENCE_USER into
+
+.popsection
+
/*
* Local variables:
* tab-width: 8
* - Stub function executing instruction `$X` with prefix `$Y`.
* - `label_$X_$Y_{trap, fault}:`
* - Labels for where `$X` is expected to trap or fault.
+ * - `{stub,label}_user_*`
+ * - Stubs/labels in user mappings.
*
* Instructions `$X`:
* - int3
extern unsigned long label_into_force_trap[], label_into_force_fault[];
extern unsigned long label_into_forcered_trap[], label_into_forcered_fault[];
+void stub_user_int3_reg(void);
+void stub_user_int3_red(void);
+void stub_user_int3_force(void);
+void stub_user_int3_forcered(void);
+extern unsigned long label_user_int3_reg_trap[], label_user_int3_reg_fault[];
+extern unsigned long label_user_int3_red_trap[], label_user_int3_red_fault[];
+extern unsigned long label_user_int3_force_trap[], label_user_int3_force_fault[];
+extern unsigned long label_user_int3_forcered_trap[], label_user_int3_forcered_fault[];
+
+void stub_user_int_0x3_reg(void);
+void stub_user_int_0x3_red(void);
+void stub_user_int_0x3_force(void);
+void stub_user_int_0x3_forcered(void);
+extern unsigned long label_user_int_0x3_reg_trap[], label_user_int_0x3_reg_fault[];
+extern unsigned long label_user_int_0x3_red_trap[], label_user_int_0x3_red_fault[];
+extern unsigned long label_user_int_0x3_force_trap[], label_user_int_0x3_force_fault[];
+extern unsigned long label_user_int_0x3_forcered_trap[], label_user_int_0x3_forcered_fault[];
+
+void stub_user_icebp_reg(void);
+void stub_user_icebp_red(void);
+void stub_user_icebp_force(void);
+void stub_user_icebp_forcered(void);
+extern unsigned long label_user_icebp_reg_trap[], label_user_icebp_reg_fault[];
+extern unsigned long label_user_icebp_red_trap[], label_user_icebp_red_fault[];
+extern unsigned long label_user_icebp_force_trap[], label_user_icebp_force_fault[];
+extern unsigned long label_user_icebp_forcered_trap[], label_user_icebp_forcered_fault[];
+
+void stub_user_int_0x1_reg(void);
+void stub_user_int_0x1_red(void);
+void stub_user_int_0x1_force(void);
+void stub_user_int_0x1_forcered(void);
+extern unsigned long label_user_int_0x1_reg_trap[], label_user_int_0x1_reg_fault[];
+extern unsigned long label_user_int_0x1_red_trap[], label_user_int_0x1_red_fault[];
+extern unsigned long label_user_int_0x1_force_trap[], label_user_int_0x1_force_fault[];
+extern unsigned long label_user_int_0x1_forcered_trap[], label_user_int_0x1_forcered_fault[];
+
+void stub_user_into_reg(void);
+void stub_user_into_red(void);
+void stub_user_into_force(void);
+void stub_user_into_forcered(void);
+extern unsigned long label_user_into_reg_trap[], label_user_into_reg_fault[];
+extern unsigned long label_user_into_red_trap[], label_user_into_red_fault[];
+extern unsigned long label_user_into_force_trap[], label_user_into_force_fault[];
+extern unsigned long label_user_into_forcered_trap[], label_user_into_forcered_fault[];
+
#endif /* __LOWLEVEL_H__ */
/*
const char test_title[] = "Software interrupt emulation";
-bool test_wants_user_mappings = true;
-
/** Single stub's worth of information. */
struct single
{
const char *type;
void (*fn)(void);
void *trap, *fault;
+
+ void (*user_fn)(void);
+ void *user_trap, *user_fault;
};
/** A collection of subs for an instruction. */
{ "int3",
{
{"regular", stub_int3_reg,
- label_int3_reg_trap, label_int3_reg_fault},
+ label_int3_reg_trap, label_int3_reg_fault,
+
+ stub_user_int3_reg,
+ label_user_int3_reg_trap, label_user_int3_reg_fault,
+ },
{"redundant", stub_int3_red,
- label_int3_red_trap, label_int3_red_fault},
+ label_int3_red_trap, label_int3_red_fault,
+
+ stub_user_int3_red,
+ label_user_int3_red_trap, label_user_int3_red_fault,
+ },
{"forced", stub_int3_force,
- label_int3_force_trap, label_int3_force_fault},
+ label_int3_force_trap, label_int3_force_fault,
+
+ stub_user_int3_force,
+ label_user_int3_force_trap, label_user_int3_force_fault,
+ },
{"forced redundant", stub_int3_forcered,
- label_int3_forcered_trap, label_int3_forcered_fault},
+ label_int3_forcered_trap, label_int3_forcered_fault,
+
+ stub_user_int3_forcered,
+ label_user_int3_forcered_trap, label_user_int3_forcered_fault,
+ },
},
};
{ "int $3",
{
{"regular", stub_int_0x3_reg,
- label_int_0x3_reg_trap, label_int_0x3_reg_fault},
+ label_int_0x3_reg_trap, label_int_0x3_reg_fault,
+
+ stub_user_int_0x3_reg,
+ label_user_int_0x3_reg_trap, label_user_int_0x3_reg_fault,
+ },
{"redundant", stub_int_0x3_red,
- label_int_0x3_red_trap, label_int_0x3_red_fault},
+ label_int_0x3_red_trap, label_int_0x3_red_fault,
+
+ stub_user_int_0x3_red,
+ label_user_int_0x3_red_trap, label_user_int_0x3_red_fault,
+ },
{"forced", stub_int_0x3_force,
- label_int_0x3_force_trap, label_int_0x3_force_fault},
+ label_int_0x3_force_trap, label_int_0x3_force_fault,
+
+ stub_user_int_0x3_force,
+ label_user_int_0x3_force_trap, label_user_int_0x3_force_fault,
+ },
{"forced redundant", stub_int_0x3_forcered,
- label_int_0x3_forcered_trap, label_int_0x3_forcered_fault},
+ label_int_0x3_forcered_trap, label_int_0x3_forcered_fault,
+
+ stub_user_int_0x3_forcered,
+ label_user_int_0x3_forcered_trap, label_user_int_0x3_forcered_fault,
+ },
},
};
{ "icebp",
{
{"regular", stub_icebp_reg,
- label_icebp_reg_trap, label_icebp_reg_fault},
+ label_icebp_reg_trap, label_icebp_reg_fault,
+
+ stub_user_icebp_reg,
+ label_user_icebp_reg_trap, label_user_icebp_reg_fault,
+ },
{"redundant", stub_icebp_red,
- label_icebp_red_trap, label_icebp_red_fault},
+ label_icebp_red_trap, label_icebp_red_fault,
+
+ stub_user_icebp_red,
+ label_user_icebp_red_trap, label_user_icebp_red_fault,
+ },
{"forced", stub_icebp_force,
- label_icebp_force_trap, label_icebp_force_fault},
+ label_icebp_force_trap, label_icebp_force_fault,
+
+ stub_user_icebp_force,
+ label_user_icebp_force_trap, label_user_icebp_force_fault,
+ },
{"forced redundant", stub_icebp_forcered,
- label_icebp_forcered_trap, label_icebp_forcered_fault},
+ label_icebp_forcered_trap, label_icebp_forcered_fault,
+
+ stub_user_icebp_forcered,
+ label_user_icebp_forcered_trap, label_user_icebp_forcered_fault,
+ },
},
};
{ "int $1",
{
{"regular", stub_int_0x1_reg,
- label_int_0x1_reg_trap, label_int_0x1_reg_fault},
+ label_int_0x1_reg_trap, label_int_0x1_reg_fault,
+
+ stub_user_int_0x1_reg,
+ label_user_int_0x1_reg_trap, label_user_int_0x1_reg_fault
+ },
{"redundant", stub_int_0x1_red,
- label_int_0x1_red_trap, label_int_0x1_red_fault},
+ label_int_0x1_red_trap, label_int_0x1_red_fault,
+
+ stub_user_int_0x1_red,
+ label_user_int_0x1_red_trap, label_user_int_0x1_red_fault,
+ },
{"forced", stub_int_0x1_force,
- label_int_0x1_force_trap, label_int_0x1_force_fault},
+ label_int_0x1_force_trap, label_int_0x1_force_fault,
+
+ stub_user_int_0x1_force,
+ label_user_int_0x1_force_trap, label_user_int_0x1_force_fault,
+ },
{"forced redundant", stub_int_0x1_forcered,
- label_int_0x1_forcered_trap, label_int_0x1_forcered_fault},
+ label_int_0x1_forcered_trap, label_int_0x1_forcered_fault,
+
+ stub_user_int_0x1_forcered,
+ label_user_int_0x1_forcered_trap, label_user_int_0x1_forcered_fault,
+ },
},
};
{ "into",
{
{"regular", stub_into_reg,
- label_into_reg_trap, label_into_reg_fault},
+ label_into_reg_trap, label_into_reg_fault,
+
+ stub_user_into_reg,
+ label_user_into_reg_trap, label_user_into_reg_fault,
+ },
{"redundant", stub_into_red,
- label_into_red_trap, label_into_red_fault},
+ label_into_red_trap, label_into_red_fault,
+
+ stub_user_into_red,
+ label_user_into_red_trap, label_user_into_red_fault,
+ },
{"forced", stub_into_force,
- label_into_force_trap, label_into_force_fault},
+ label_into_force_trap, label_into_force_fault,
+
+ stub_user_into_force,
+ label_user_into_force_trap, label_user_into_force_fault,
+ },
{"forced redundant", stub_into_forcered,
- label_into_forcered_trap, label_into_forcered_fault},
+ label_into_forcered_trap, label_into_forcered_fault,
+
+ stub_user_into_forcered,
+ label_user_into_forcered_trap, label_user_into_forcered_fault,
+ },
},
};
for ( i = 0; i < ARRAY_SIZE(seq->tests); ++i )
{
struct single *s = &seq->tests[i];
+ void *addr;
+
+ if ( user )
+ addr = fault ? s->user_fault : s->user_trap;
+ else
+ addr = fault ? s->fault : s->trap;
- expect(s->type,
- fault ? s->fault : s->trap,
- vector, error);
+ expect(s->type, addr, vector, error);
- user ? exec_user_void(s->fn) : s->fn();
+ user ? exec_user_void(s->user_fn) : s->fn();
check();
const char test_title[] = "XSA-170 PoC";
-bool test_wants_user_mappings = true;
bool test_needs_fep = true;
-void wild_jump(void)
+void __user_text wild_jump(void)
{
/*
* After XSA-170, Xen's instruction emulator was improved to perform a
:: "qI" (0x8000000000000000ULL));
}
-void nop_slide(void)
+void __user_text nop_slide(void)
{
/*
* AMD hardware can correctly re-enter the guest with a non-canonical
const char test_title[] = "XSA-196 PoC";
-bool test_wants_user_mappings = true;
bool test_needs_fep = true;
void custom_doublefault_handler(void);
"iretq;"
);
-unsigned long compat_userspace(void)
+static unsigned long __user_text compat_userspace(void)
{
exinfo_t fault = 0;