Commit adb45839 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky

[S390] kprobes: disable interrupts throughout

Execute the kprobe exception and fault handler with interrupts disabled.
To disable the interrupts only while a single step is in progress is not
good enough, a kprobe from interrupt context while another kprobe is
handled can confuse the internal house keeping.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent becf91f1
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hardirq.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
...@@ -212,7 +213,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) ...@@ -212,7 +213,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
/* Set the PER control regs, turns on single step for this address */ /* Set the PER control regs, turns on single step for this address */
__ctl_load(kprobe_per_regs, 9, 11); __ctl_load(kprobe_per_regs, 9, 11);
regs->psw.mask |= PSW_MASK_PER; regs->psw.mask |= PSW_MASK_PER;
regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
} }
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
...@@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, ...@@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
__get_cpu_var(current_kprobe) = p; __get_cpu_var(current_kprobe) = p;
/* Save the interrupt and per flags */ /* Save the interrupt and per flags */
kcb->kprobe_saved_imask = regs->psw.mask & kcb->kprobe_saved_imask = regs->psw.mask &
(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
/* Save the control regs that govern PER */ /* Save the control regs that govern PER */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11); __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
} }
...@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ...@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
return 1; return 1;
ss_probe: ss_probe:
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_disable();
prepare_singlestep(p, regs); prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS; kcb->kprobe_status = KPROBE_HIT_SS;
return 1; return 1;
...@@ -465,8 +464,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) ...@@ -465,8 +464,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
goto out; goto out;
} }
reset_current_kprobe(); reset_current_kprobe();
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_enable();
out: out:
preempt_enable_no_resched(); preempt_enable_no_resched();
...@@ -482,7 +479,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) ...@@ -482,7 +479,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
return 1; return 1;
} }
int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
{ {
struct kprobe *cur = kprobe_running(); struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
...@@ -508,8 +505,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) ...@@ -508,8 +505,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
restore_previous_kprobe(kcb); restore_previous_kprobe(kcb);
else { else {
reset_current_kprobe(); reset_current_kprobe();
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_enable();
} }
preempt_enable_no_resched(); preempt_enable_no_resched();
break; break;
...@@ -553,6 +548,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) ...@@ -553,6 +548,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
return 0; return 0;
} }
int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
int ret;
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_disable();
ret = kprobe_trap_handler(regs, trapnr);
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
return ret;
}
/* /*
* Wrapper routine to for handling exceptions. * Wrapper routine to for handling exceptions.
*/ */
...@@ -560,8 +567,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ...@@ -560,8 +567,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data) unsigned long val, void *data)
{ {
struct die_args *args = (struct die_args *)data; struct die_args *args = (struct die_args *)data;
struct pt_regs *regs = args->regs;
int ret = NOTIFY_DONE; int ret = NOTIFY_DONE;
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_disable();
switch (val) { switch (val) {
case DIE_BPT: case DIE_BPT:
if (kprobe_handler(args->regs)) if (kprobe_handler(args->regs))
...@@ -572,16 +583,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ...@@ -572,16 +583,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP; ret = NOTIFY_STOP;
break; break;
case DIE_TRAP: case DIE_TRAP:
/* kprobe_running() needs smp_processor_id() */ if (!preemptible() && kprobe_running() &&
preempt_disable(); kprobe_trap_handler(args->regs, args->trapnr))
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP; ret = NOTIFY_STOP;
preempt_enable();
break; break;
default: default:
break; break;
} }
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
return ret; return ret;
} }
...@@ -595,6 +607,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -595,6 +607,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
/* setup return addr to the jprobe handler routine */ /* setup return addr to the jprobe handler routine */
regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
/* r14 is the function return address */ /* r14 is the function return address */
kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
......
Markdown is supported
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