sh: Add die chain notifiers.

Add the atomic die chains in, kprobes needs these.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Paul Mundt 2007-05-01 16:33:10 +09:00 committed by Paul Mundt
parent 3dde7a3c74
commit 3a2e117e22
5 changed files with 104 additions and 7 deletions

View File

@ -7,7 +7,7 @@
* *
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
* Copyright (C) 2002 - 2006 Paul Mundt * Copyright (C) 2002 - 2007 Paul Mundt
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
@ -15,6 +15,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <asm/kdebug.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/ubc.h> #include <asm/ubc.h>
@ -299,8 +300,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
ctrl_outl(0, UBC_BAMRA); ctrl_outl(0, UBC_BAMRA);
if (current_cpu_data.type == CPU_SH7729 || if (current_cpu_data.type == CPU_SH7729 ||
current_cpu_data.type == CPU_SH7710 || current_cpu_data.type == CPU_SH7710 ||
current_cpu_data.type == CPU_SH7712 ) { current_cpu_data.type == CPU_SH7712) {
ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
} else { } else {
@ -496,6 +497,10 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */ /* Rewind */
regs->pc -= 2; regs->pc -= 2;
if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
force_sig(SIGTRAP, current); force_sig(SIGTRAP, current);
} }
@ -511,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */ /* Rewind */
regs->pc -= 2; regs->pc -= 2;
if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
#ifdef CONFIG_BUG #ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) { if (__kernel_text_address(instruction_pointer(regs))) {
u16 insn = *(u16 *)instruction_pointer(regs); u16 insn = *(u16 *)instruction_pointer(regs);

View File

@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka * SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf * Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells * Copyright (C) 2000 David Howells
* Copyright (C) 2002 - 2006 Paul Mundt * Copyright (C) 2002 - 2007 Paul Mundt
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
@ -23,6 +23,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/kdebug.h>
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
#include <asm/kgdb.h> #include <asm/kgdb.h>
@ -75,7 +76,21 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
} }
} }
DEFINE_SPINLOCK(die_lock); ATOMIC_NOTIFIER_HEAD(shdie_chain);
int register_die_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&shdie_chain, nb);
}
EXPORT_SYMBOL(register_die_notifier);
int unregister_die_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&shdie_chain, nb);
}
EXPORT_SYMBOL(unregister_die_notifier);
static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err) void die(const char * str, struct pt_regs * regs, long err)
{ {

View File

@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU. * Page fault handler for SH with an MMU.
* *
* Copyright (C) 1999 Niibe Yutaka * Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2003 Paul Mundt * Copyright (C) 2003 - 2007 Paul Mundt
* *
* Based on linux/arch/i386/mm/fault.c: * Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds * Copyright (C) 1995 Linus Torvalds
@ -15,12 +15,42 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <asm/kdebug.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/kgdb.h> #include <asm/kgdb.h>
extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES
ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
/* Hook to register for page fault notifications */
int register_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
}
int unregister_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
}
static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
int trap, int sig)
{
struct die_args args = {
.regs = regs,
.trapnr = trap,
};
return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
}
#else
static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
int trap, int sig)
{
return NOTIFY_DONE;
}
#endif
/* /*
* This routine handles page faults. It determines the address, * This routine handles page faults. It determines the address,
@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
siginfo_t info; siginfo_t info;
trace_hardirqs_on(); trace_hardirqs_on();
if (notify_page_fault(DIE_PAGE_FAULT, regs,
writeaccess, SIGSEGV) == NOTIFY_STOP)
return;
local_irq_enable(); local_irq_enable();
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB

35
include/asm-sh/kdebug.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __ASM_SH_KDEBUG_H
#define __ASM_SH_KDEBUG_H
#include <linux/notifier.h>
struct pt_regs;
struct die_args {
struct pt_regs *regs;
int trapnr;
};
int register_die_notifier(struct notifier_block *nb);
int unregister_die_notifier(struct notifier_block *nb);
int register_page_fault_notifier(struct notifier_block *nb);
int unregister_page_fault_notifier(struct notifier_block *nb);
extern struct atomic_notifier_head shdie_chain;
/* Grossly misnamed. */
enum die_val {
DIE_TRAP,
DIE_PAGE_FAULT,
};
static inline int notify_die(enum die_val val, struct pt_regs *regs,
int trap, int sig)
{
struct die_args args = {
.regs = regs,
.trapnr = trap,
};
return atomic_notifier_call_chain(&shdie_chain, val, &args);
}
#endif /* __ASM_SH_KDEBUG_H */

View File

@ -9,6 +9,7 @@
#include <linux/irqflags.h> #include <linux/irqflags.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/ptrace.h>
/* /*
* switch_to() should switch tasks to task nr n, first * 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,
(unsigned long)_n_, sizeof(*(ptr))); \ (unsigned long)_n_, sizeof(*(ptr))); \
}) })
extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
extern void *set_exception_table_vec(unsigned int vec, void *handler); extern void *set_exception_table_vec(unsigned int vec, void *handler);
static inline void *set_exception_table_evt(unsigned int evt, void *handler) static inline void *set_exception_table_evt(unsigned int evt, void *handler)