aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-05-01 03:33:10 -0400
committerPaul Mundt <lethal@hera.kernel.org>2007-05-06 22:11:57 -0400
commit3a2e117e220f000f95187ea1e1bbe83b0ed5fdfb (patch)
tree57fab5755138283793647b5d0d2a2c872f00a430
parent3dde7a3c74bcc25c6fc31b836fec8c91fb0b2b8f (diff)
sh: Add die chain notifiers.
Add the atomic die chains in, kprobes needs these. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/process.c15
-rw-r--r--arch/sh/kernel/traps.c19
-rw-r--r--arch/sh/mm/fault.c39
-rw-r--r--include/asm-sh/kdebug.h35
-rw-r--r--include/asm-sh/system.h3
5 files changed, 104 insertions, 7 deletions
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 286c80388bf5..329b3f3051de 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima 8 * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
9 * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC 9 * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
10 * Copyright (C) 2002 - 2006 Paul Mundt 10 * Copyright (C) 2002 - 2007 Paul Mundt
11 */ 11 */
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/mm.h> 13#include <linux/mm.h>
@@ -15,6 +15,7 @@
15#include <linux/pm.h> 15#include <linux/pm.h>
16#include <linux/kallsyms.h> 16#include <linux/kallsyms.h>
17#include <linux/kexec.h> 17#include <linux/kexec.h>
18#include <asm/kdebug.h>
18#include <asm/uaccess.h> 19#include <asm/uaccess.h>
19#include <asm/mmu_context.h> 20#include <asm/mmu_context.h>
20#include <asm/ubc.h> 21#include <asm/ubc.h>
@@ -299,8 +300,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
299 ctrl_outl(0, UBC_BAMRA); 300 ctrl_outl(0, UBC_BAMRA);
300 301
301 if (current_cpu_data.type == CPU_SH7729 || 302 if (current_cpu_data.type == CPU_SH7729 ||
302 current_cpu_data.type == CPU_SH7710 || 303 current_cpu_data.type == CPU_SH7710 ||
303 current_cpu_data.type == CPU_SH7712 ) { 304 current_cpu_data.type == CPU_SH7712) {
304 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); 305 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
305 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); 306 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
306 } else { 307 } else {
@@ -496,6 +497,10 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
496 /* Rewind */ 497 /* Rewind */
497 regs->pc -= 2; 498 regs->pc -= 2;
498 499
500 if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
501 SIGTRAP) == NOTIFY_STOP)
502 return;
503
499 force_sig(SIGTRAP, current); 504 force_sig(SIGTRAP, current);
500} 505}
501 506
@@ -511,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
511 /* Rewind */ 516 /* Rewind */
512 regs->pc -= 2; 517 regs->pc -= 2;
513 518
519 if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
520 SIGTRAP) == NOTIFY_STOP)
521 return;
522
514#ifdef CONFIG_BUG 523#ifdef CONFIG_BUG
515 if (__kernel_text_address(instruction_pointer(regs))) { 524 if (__kernel_text_address(instruction_pointer(regs))) {
516 u16 insn = *(u16 *)instruction_pointer(regs); 525 u16 insn = *(u16 *)instruction_pointer(regs);
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 77107838271f..7b40f0ff3dfc 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -5,7 +5,7 @@
5 * SuperH version: Copyright (C) 1999 Niibe Yutaka 5 * SuperH version: Copyright (C) 1999 Niibe Yutaka
6 * Copyright (C) 2000 Philipp Rumpf 6 * Copyright (C) 2000 Philipp Rumpf
7 * Copyright (C) 2000 David Howells 7 * Copyright (C) 2000 David Howells
8 * Copyright (C) 2002 - 2006 Paul Mundt 8 * Copyright (C) 2002 - 2007 Paul Mundt
9 * 9 *
10 * This file is subject to the terms and conditions of the GNU General Public 10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file "COPYING" in the main directory of this archive 11 * License. See the file "COPYING" in the main directory of this archive
@@ -23,6 +23,7 @@
23#include <linux/limits.h> 23#include <linux/limits.h>
24#include <asm/system.h> 24#include <asm/system.h>
25#include <asm/uaccess.h> 25#include <asm/uaccess.h>
26#include <asm/kdebug.h>
26 27
27#ifdef CONFIG_SH_KGDB 28#ifdef CONFIG_SH_KGDB
28#include <asm/kgdb.h> 29#include <asm/kgdb.h>
@@ -75,7 +76,21 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
75 } 76 }
76} 77}
77 78
78DEFINE_SPINLOCK(die_lock); 79ATOMIC_NOTIFIER_HEAD(shdie_chain);
80
81int register_die_notifier(struct notifier_block *nb)
82{
83 return atomic_notifier_chain_register(&shdie_chain, nb);
84}
85EXPORT_SYMBOL(register_die_notifier);
86
87int unregister_die_notifier(struct notifier_block *nb)
88{
89 return atomic_notifier_chain_unregister(&shdie_chain, nb);
90}
91EXPORT_SYMBOL(unregister_die_notifier);
92
93static DEFINE_SPINLOCK(die_lock);
79 94
80void die(const char * str, struct pt_regs * regs, long err) 95void die(const char * str, struct pt_regs * regs, long err)
81{ 96{
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index fa5d7f0b9f18..0ecc117cade4 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -2,7 +2,7 @@
2 * Page fault handler for SH with an MMU. 2 * Page fault handler for SH with an MMU.
3 * 3 *
4 * Copyright (C) 1999 Niibe Yutaka 4 * Copyright (C) 1999 Niibe Yutaka
5 * Copyright (C) 2003 Paul Mundt 5 * Copyright (C) 2003 - 2007 Paul Mundt
6 * 6 *
7 * Based on linux/arch/i386/mm/fault.c: 7 * Based on linux/arch/i386/mm/fault.c:
8 * Copyright (C) 1995 Linus Torvalds 8 * Copyright (C) 1995 Linus Torvalds
@@ -15,12 +15,42 @@
15#include <linux/mm.h> 15#include <linux/mm.h>
16#include <linux/hardirq.h> 16#include <linux/hardirq.h>
17#include <linux/kprobes.h> 17#include <linux/kprobes.h>
18#include <asm/kdebug.h>
18#include <asm/system.h> 19#include <asm/system.h>
19#include <asm/mmu_context.h> 20#include <asm/mmu_context.h>
20#include <asm/tlbflush.h> 21#include <asm/tlbflush.h>
21#include <asm/kgdb.h> 22#include <asm/kgdb.h>
22 23
23extern void die(const char *,struct pt_regs *,long); 24#ifdef CONFIG_KPROBES
25ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
26
27/* Hook to register for page fault notifications */
28int register_page_fault_notifier(struct notifier_block *nb)
29{
30 return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
31}
32
33int unregister_page_fault_notifier(struct notifier_block *nb)
34{
35 return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
36}
37
38static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
39 int trap, int sig)
40{
41 struct die_args args = {
42 .regs = regs,
43 .trapnr = trap,
44 };
45 return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
46}
47#else
48static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
49 int trap, int sig)
50{
51 return NOTIFY_DONE;
52}
53#endif
24 54
25/* 55/*
26 * This routine handles page faults. It determines the address, 56 * This routine handles page faults. It determines the address,
@@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
39 siginfo_t info; 69 siginfo_t info;
40 70
41 trace_hardirqs_on(); 71 trace_hardirqs_on();
72
73 if (notify_page_fault(DIE_PAGE_FAULT, regs,
74 writeaccess, SIGSEGV) == NOTIFY_STOP)
75 return;
76
42 local_irq_enable(); 77 local_irq_enable();
43 78
44#ifdef CONFIG_SH_KGDB 79#ifdef CONFIG_SH_KGDB
diff --git a/include/asm-sh/kdebug.h b/include/asm-sh/kdebug.h
new file mode 100644
index 000000000000..ef009baf5a11
--- /dev/null
+++ b/include/asm-sh/kdebug.h
@@ -0,0 +1,35 @@
1#ifndef __ASM_SH_KDEBUG_H
2#define __ASM_SH_KDEBUG_H
3
4#include <linux/notifier.h>
5
6struct pt_regs;
7
8struct die_args {
9 struct pt_regs *regs;
10 int trapnr;
11};
12
13int register_die_notifier(struct notifier_block *nb);
14int unregister_die_notifier(struct notifier_block *nb);
15int register_page_fault_notifier(struct notifier_block *nb);
16int unregister_page_fault_notifier(struct notifier_block *nb);
17extern struct atomic_notifier_head shdie_chain;
18
19/* Grossly misnamed. */
20enum die_val {
21 DIE_TRAP,
22 DIE_PAGE_FAULT,
23};
24
25static inline int notify_die(enum die_val val, struct pt_regs *regs,
26 int trap, int sig)
27{
28 struct die_args args = {
29 .regs = regs,
30 .trapnr = trap,
31 };
32
33 return atomic_notifier_call_chain(&shdie_chain, val, &args);
34}
35#endif /* __ASM_SH_KDEBUG_H */
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index 4a6a19f4f8a4..127af304865f 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -9,6 +9,7 @@
9#include <linux/irqflags.h> 9#include <linux/irqflags.h>
10#include <linux/compiler.h> 10#include <linux/compiler.h>
11#include <asm/types.h> 11#include <asm/types.h>
12#include <asm/ptrace.h>
12 13
13/* 14/*
14 * switch_to() should switch tasks to task nr n, first 15 * switch_to() should switch tasks to task nr n, first
@@ -255,6 +256,8 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
255 (unsigned long)_n_, sizeof(*(ptr))); \ 256 (unsigned long)_n_, sizeof(*(ptr))); \
256 }) 257 })
257 258
259extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
260
258extern void *set_exception_table_vec(unsigned int vec, void *handler); 261extern void *set_exception_table_vec(unsigned int vec, void *handler);
259 262
260static inline void *set_exception_table_evt(unsigned int evt, void *handler) 263static inline void *set_exception_table_evt(unsigned int evt, void *handler)