Skip to content

Commit

Permalink
[S390] kprobes: disable interrupts throughout
Browse files Browse the repository at this point in the history
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: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Martin Schwidefsky authored and Martin Schwidefsky committed Nov 10, 2010
1 parent becf91f commit adb4583
Showing 1 changed file with 27 additions and 14 deletions.
41 changes: 27 additions & 14 deletions arch/s390/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <asm/sections.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/hardirq.h>

DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
Expand Down Expand Up @@ -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 */
__ctl_load(kprobe_per_regs, 9, 11);
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)
Expand All @@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
__get_cpu_var(current_kprobe) = p;
/* Save the interrupt and per flags */
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 */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
}
Expand Down Expand Up @@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
return 1;

ss_probe:
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_disable();
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
Expand Down Expand Up @@ -465,8 +464,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
goto out;
}
reset_current_kprobe();
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_enable();
out:
preempt_enable_no_resched();

Expand All @@ -482,7 +479,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
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_ctlblk *kcb = get_kprobe_ctlblk();
Expand All @@ -508,8 +505,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
restore_previous_kprobe(kcb);
else {
reset_current_kprobe();
if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
local_irq_enable();
}
preempt_enable_no_resched();
break;
Expand Down Expand Up @@ -553,15 +548,31 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
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.
*/
int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
struct pt_regs *regs = args->regs;
int ret = NOTIFY_DONE;

if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_disable();

switch (val) {
case DIE_BPT:
if (kprobe_handler(args->regs))
Expand All @@ -572,16 +583,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP;
break;
case DIE_TRAP:
/* kprobe_running() needs smp_processor_id() */
preempt_disable();
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
if (!preemptible() && kprobe_running() &&
kprobe_trap_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP;
preempt_enable();
break;
default:
break;
}

if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);

return ret;
}

Expand All @@ -595,6 +607,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)

/* setup return addr to the jprobe handler routine */
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 */
kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
Expand Down

0 comments on commit adb4583

Please sign in to comment.