Commit 7457c0da authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

x86/alternatives: Add int3_emulate_call() selftest

Given that the entry_*.S changes for this functionality are somewhat
tricky, make sure the paths are tested every boot, instead of on the
rare occasion when we trip an INT3 while rewriting text.

Requested-by: default avatarAndy Lutomirski <>
Signed-off-by: default avatarPeter Zijlstra (Intel) <>
Reviewed-by: default avatarJosh Poimboeuf <>
Acked-by: default avatarAndy Lutomirski <>
Cc: Linus Torvalds <>
Cc: Peter Zijlstra <>
Cc: Thomas Gleixner <>
Signed-off-by: default avatarIngo Molnar <>
parent faeedb06
......@@ -615,11 +615,83 @@ extern struct paravirt_patch_site __start_parainstructions[],
#endif /* CONFIG_PARAVIRT */
* Self-test for the INT3 based CALL emulation code.
* This exercises int3_emulate_call() to make sure INT3 pt_regs are set up
* properly and that there is a stack gap between the INT3 frame and the
* previous context. Without this gap doing a virtual PUSH on the interrupted
* stack would corrupt the INT3 IRET frame.
* See entry_{32,64}.S for more details.
static void __init int3_magic(unsigned int *ptr)
*ptr = 1;
extern __initdata unsigned long int3_selftest_ip; /* defined in asm below */
static int __init
int3_exception_notify(struct notifier_block *self, unsigned long val, void *data)
struct die_args *args = data;
struct pt_regs *regs = args->regs;
if (!regs || user_mode(regs))
if (val != DIE_INT3)
if (regs->ip - INT3_INSN_SIZE != int3_selftest_ip)
int3_emulate_call(regs, (unsigned long)&int3_magic);
static void __init int3_selftest(void)
static __initdata struct notifier_block int3_exception_nb = {
.notifier_call = int3_exception_notify,
.priority = INT_MAX-1, /* last */
unsigned int val = 0;
* Basically: int3_magic(&val); but really complicated :-)
* Stick the address of the INT3 instruction into int3_selftest_ip,
* then trigger the INT3, padded with NOPs to match a CALL instruction
* length.
asm volatile ("1: int3; nop; nop; nop; nop\n\t"
".align " __ASM_SEL(4, 8) "\n\t"
".type int3_selftest_ip, @object\n\t"
".size int3_selftest_ip, " __ASM_SEL(4, 8) "\n\t"
__ASM_SEL(.long, .quad) " 1b\n\t"
: : __ASM_SEL_RAW(a, D) (&val) : "memory");
BUG_ON(val != 1);
void __init alternative_instructions(void)
/* The patching is not fully atomic, so try to avoid local interruptions
that might execute the to be patched code.
Other CPUs are not running. */
* The patching is not fully atomic, so try to avoid local
* interruptions that might execute the to be patched code.
* Other CPUs are not running.
......@@ -644,10 +716,11 @@ void __init alternative_instructions(void)
_text, _etext);
if (!uniproc_patched || num_possible_cpus() == 1)
if (!uniproc_patched || num_possible_cpus() == 1) {
free_init_pages("SMP alternatives",
(unsigned long)__smp_locks,
(unsigned long)__smp_locks_end);
apply_paravirt(__parainstructions, __parainstructions_end);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment