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
* 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/mm.h>
@ -15,6 +15,7 @@
#include <linux/pm.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>
#include <asm/kdebug.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/ubc.h>
@ -299,8 +300,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
ctrl_outl(0, UBC_BAMRA);
if (current_cpu_data.type == CPU_SH7729 ||
current_cpu_data.type == CPU_SH7710 ||
current_cpu_data.type == CPU_SH7712 ) {
current_cpu_data.type == CPU_SH7710 ||
current_cpu_data.type == CPU_SH7712) {
ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
} else {
@ -496,6 +497,10 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */
regs->pc -= 2;
if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
force_sig(SIGTRAP, current);
}
@ -511,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */
regs->pc -= 2;
if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
#ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) {
u16 insn = *(u16 *)instruction_pointer(regs);

View file

@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* 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
* License. See the file "COPYING" in the main directory of this archive
@ -23,6 +23,7 @@
#include <linux/limits.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/kdebug.h>
#ifdef CONFIG_SH_KGDB
#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)
{

View file

@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU.
*
* Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2003 Paul Mundt
* Copyright (C) 2003 - 2007 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
@ -15,12 +15,42 @@
#include <linux/mm.h>
#include <linux/hardirq.h>
#include <linux/kprobes.h>
#include <asm/kdebug.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.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,
@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
siginfo_t info;
trace_hardirqs_on();
if (notify_page_fault(DIE_PAGE_FAULT, regs,
writeaccess, SIGSEGV) == NOTIFY_STOP)
return;
local_irq_enable();
#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/compiler.h>
#include <asm/types.h>
#include <asm/ptrace.h>
/*
* 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))); \
})
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);
static inline void *set_exception_table_evt(unsigned int evt, void *handler)