diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2010-11-10 04:05:57 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-11-10 04:05:54 -0500 |
commit | adb45839817392102e659c19e5c19aa39530021f (patch) | |
tree | 00a28ba170a4f82e083942863997a55e5389b30a /arch/s390 | |
parent | becf91f18750cf1c60828aa2ee63a36b05c2e4d0 (diff) |
[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: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/kprobes.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index d60fc4398516..70cf73bdba25 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/hardirq.h> | ||
33 | 34 | ||
34 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 35 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
35 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 36 | 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 | /* Set the PER control regs, turns on single step for this address */ | 213 | /* Set the PER control regs, turns on single step for this address */ |
213 | __ctl_load(kprobe_per_regs, 9, 11); | 214 | __ctl_load(kprobe_per_regs, 9, 11); |
214 | regs->psw.mask |= PSW_MASK_PER; | 215 | regs->psw.mask |= PSW_MASK_PER; |
215 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); | 216 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); |
216 | } | 217 | } |
217 | 218 | ||
218 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) | 219 | 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 | __get_cpu_var(current_kprobe) = p; | 240 | __get_cpu_var(current_kprobe) = p; |
240 | /* Save the interrupt and per flags */ | 241 | /* Save the interrupt and per flags */ |
241 | kcb->kprobe_saved_imask = regs->psw.mask & | 242 | kcb->kprobe_saved_imask = regs->psw.mask & |
242 | (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); | 243 | (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT); |
243 | /* Save the control regs that govern PER */ | 244 | /* Save the control regs that govern PER */ |
244 | __ctl_store(kcb->kprobe_saved_ctl, 9, 11); | 245 | __ctl_store(kcb->kprobe_saved_ctl, 9, 11); |
245 | } | 246 | } |
@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
316 | return 1; | 317 | return 1; |
317 | 318 | ||
318 | ss_probe: | 319 | ss_probe: |
319 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
320 | local_irq_disable(); | ||
321 | prepare_singlestep(p, regs); | 320 | prepare_singlestep(p, regs); |
322 | kcb->kprobe_status = KPROBE_HIT_SS; | 321 | kcb->kprobe_status = KPROBE_HIT_SS; |
323 | return 1; | 322 | return 1; |
@@ -465,8 +464,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) | |||
465 | goto out; | 464 | goto out; |
466 | } | 465 | } |
467 | reset_current_kprobe(); | 466 | reset_current_kprobe(); |
468 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
469 | local_irq_enable(); | ||
470 | out: | 467 | out: |
471 | preempt_enable_no_resched(); | 468 | preempt_enable_no_resched(); |
472 | 469 | ||
@@ -482,7 +479,7 @@ out: | |||
482 | return 1; | 479 | return 1; |
483 | } | 480 | } |
484 | 481 | ||
485 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 482 | static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) |
486 | { | 483 | { |
487 | struct kprobe *cur = kprobe_running(); | 484 | struct kprobe *cur = kprobe_running(); |
488 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 485 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
@@ -508,8 +505,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
508 | restore_previous_kprobe(kcb); | 505 | restore_previous_kprobe(kcb); |
509 | else { | 506 | else { |
510 | reset_current_kprobe(); | 507 | reset_current_kprobe(); |
511 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
512 | local_irq_enable(); | ||
513 | } | 508 | } |
514 | preempt_enable_no_resched(); | 509 | preempt_enable_no_resched(); |
515 | break; | 510 | break; |
@@ -553,6 +548,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
553 | return 0; | 548 | return 0; |
554 | } | 549 | } |
555 | 550 | ||
551 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | ||
552 | { | ||
553 | int ret; | ||
554 | |||
555 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
556 | local_irq_disable(); | ||
557 | ret = kprobe_trap_handler(regs, trapnr); | ||
558 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
559 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | ||
560 | return ret; | ||
561 | } | ||
562 | |||
556 | /* | 563 | /* |
557 | * Wrapper routine to for handling exceptions. | 564 | * Wrapper routine to for handling exceptions. |
558 | */ | 565 | */ |
@@ -560,8 +567,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
560 | unsigned long val, void *data) | 567 | unsigned long val, void *data) |
561 | { | 568 | { |
562 | struct die_args *args = (struct die_args *)data; | 569 | struct die_args *args = (struct die_args *)data; |
570 | struct pt_regs *regs = args->regs; | ||
563 | int ret = NOTIFY_DONE; | 571 | int ret = NOTIFY_DONE; |
564 | 572 | ||
573 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
574 | local_irq_disable(); | ||
575 | |||
565 | switch (val) { | 576 | switch (val) { |
566 | case DIE_BPT: | 577 | case DIE_BPT: |
567 | if (kprobe_handler(args->regs)) | 578 | if (kprobe_handler(args->regs)) |
@@ -572,16 +583,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
572 | ret = NOTIFY_STOP; | 583 | ret = NOTIFY_STOP; |
573 | break; | 584 | break; |
574 | case DIE_TRAP: | 585 | case DIE_TRAP: |
575 | /* kprobe_running() needs smp_processor_id() */ | 586 | if (!preemptible() && kprobe_running() && |
576 | preempt_disable(); | 587 | kprobe_trap_handler(args->regs, args->trapnr)) |
577 | if (kprobe_running() && | ||
578 | kprobe_fault_handler(args->regs, args->trapnr)) | ||
579 | ret = NOTIFY_STOP; | 588 | ret = NOTIFY_STOP; |
580 | preempt_enable(); | ||
581 | break; | 589 | break; |
582 | default: | 590 | default: |
583 | break; | 591 | break; |
584 | } | 592 | } |
593 | |||
594 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
595 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | ||
596 | |||
585 | return ret; | 597 | return ret; |
586 | } | 598 | } |
587 | 599 | ||
@@ -595,6 +607,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
595 | 607 | ||
596 | /* setup return addr to the jprobe handler routine */ | 608 | /* setup return addr to the jprobe handler routine */ |
597 | regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; | 609 | regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; |
610 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); | ||
598 | 611 | ||
599 | /* r14 is the function return address */ | 612 | /* r14 is the function return address */ |
600 | kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; | 613 | kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; |