diff options
| -rw-r--r-- | arch/sh/kernel/process.c | 15 | ||||
| -rw-r--r-- | arch/sh/kernel/traps.c | 19 | ||||
| -rw-r--r-- | arch/sh/mm/fault.c | 39 | ||||
| -rw-r--r-- | include/asm-sh/kdebug.h | 35 | ||||
| -rw-r--r-- | include/asm-sh/system.h | 3 |
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 | ||
| 78 | DEFINE_SPINLOCK(die_lock); | 79 | ATOMIC_NOTIFIER_HEAD(shdie_chain); |
| 80 | |||
| 81 | int register_die_notifier(struct notifier_block *nb) | ||
| 82 | { | ||
| 83 | return atomic_notifier_chain_register(&shdie_chain, nb); | ||
| 84 | } | ||
| 85 | EXPORT_SYMBOL(register_die_notifier); | ||
| 86 | |||
| 87 | int unregister_die_notifier(struct notifier_block *nb) | ||
| 88 | { | ||
| 89 | return atomic_notifier_chain_unregister(&shdie_chain, nb); | ||
| 90 | } | ||
| 91 | EXPORT_SYMBOL(unregister_die_notifier); | ||
| 92 | |||
| 93 | static DEFINE_SPINLOCK(die_lock); | ||
| 79 | 94 | ||
| 80 | void die(const char * str, struct pt_regs * regs, long err) | 95 | void 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 | ||
| 23 | extern void die(const char *,struct pt_regs *,long); | 24 | #ifdef CONFIG_KPROBES |
| 25 | ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); | ||
| 26 | |||
| 27 | /* Hook to register for page fault notifications */ | ||
| 28 | int register_page_fault_notifier(struct notifier_block *nb) | ||
| 29 | { | ||
| 30 | return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); | ||
| 31 | } | ||
| 32 | |||
| 33 | int unregister_page_fault_notifier(struct notifier_block *nb) | ||
| 34 | { | ||
| 35 | return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); | ||
| 36 | } | ||
| 37 | |||
| 38 | static 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(¬ify_page_fault_chain, val, &args); | ||
| 46 | } | ||
| 47 | #else | ||
| 48 | static 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 | |||
| 6 | struct pt_regs; | ||
| 7 | |||
| 8 | struct die_args { | ||
| 9 | struct pt_regs *regs; | ||
| 10 | int trapnr; | ||
| 11 | }; | ||
| 12 | |||
| 13 | int register_die_notifier(struct notifier_block *nb); | ||
| 14 | int unregister_die_notifier(struct notifier_block *nb); | ||
| 15 | int register_page_fault_notifier(struct notifier_block *nb); | ||
| 16 | int unregister_page_fault_notifier(struct notifier_block *nb); | ||
| 17 | extern struct atomic_notifier_head shdie_chain; | ||
| 18 | |||
| 19 | /* Grossly misnamed. */ | ||
| 20 | enum die_val { | ||
| 21 | DIE_TRAP, | ||
| 22 | DIE_PAGE_FAULT, | ||
| 23 | }; | ||
| 24 | |||
| 25 | static 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 | ||
| 259 | extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn)); | ||
| 260 | |||
| 258 | extern void *set_exception_table_vec(unsigned int vec, void *handler); | 261 | extern void *set_exception_table_vec(unsigned int vec, void *handler); |
| 259 | 262 | ||
| 260 | static inline void *set_exception_table_evt(unsigned int evt, void *handler) | 263 | static inline void *set_exception_table_evt(unsigned int evt, void *handler) |
