MN10300: Create generic kernel debugger hooks

Create generic kernel debugger hooks in the MN10300 arch and make gdbstub use
them.  This is a preparation for KGDB support.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2011-03-18 16:54:30 +00:00
parent 7f386ac327
commit 67ddb4052d
14 changed files with 313 additions and 244 deletions

View File

@ -401,8 +401,8 @@ comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highes
comment "____Non-maskable interrupt levels____"
comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial"
config GDBSTUB_IRQ_LEVEL
int "GDBSTUB interrupt priority"
config DEBUGGER_IRQ_LEVEL
int "DEBUGGER interrupt priority"
depends on KERNEL_DEBUGGER
range 0 1 if LINUX_CLI_LEVEL = 2
range 0 2 if LINUX_CLI_LEVEL = 3
@ -437,7 +437,7 @@ config LINUX_CLI_LEVEL
EPSW.IM from 7. Any interrupt is permitted for which the level is
lower than EPSW.IM.
Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip
Certain interrupts, such as DEBUGGER and virtual MN10300 on-chip
serial DMA interrupts are allowed to interrupt normal disabled
sections.

View File

@ -14,6 +14,9 @@
#if defined(CONFIG_KERNEL_DEBUGGER)
extern int debugger_intercept(enum exception_code, int, int, struct pt_regs *);
extern int at_debugger_breakpoint(struct pt_regs *);
#ifndef CONFIG_MN10300_DEBUGGER_CACHE_NO_FLUSH
extern void debugger_local_cache_flushinv(void);
extern void debugger_local_cache_flushinv_one(u8 *);
@ -24,5 +27,17 @@ static inline void debugger_local_cache_flushinv_one(u8 *addr) {}
#else /* CONFIG_KERNEL_DEBUGGER */
static inline int debugger_intercept(enum exception_code excep,
int signo, int si_code,
struct pt_regs *regs)
{
return 0;
}
static inline int at_debugger_breakpoint(struct pt_regs *regs)
{
return 0;
}
#endif /* CONFIG_KERNEL_DEBUGGER */
#endif /* _ASM_DEBUGGER_H */

View File

@ -55,7 +55,6 @@ static inline void clear_using_fpu(struct task_struct *tsk)
extern asmlinkage void fpu_kill_state(struct task_struct *);
extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code);
extern asmlinkage void fpu_init_state(void);
extern asmlinkage void fpu_save(struct fpu_state_struct *);
extern int fpu_setup_sigcontext(struct fpucontext *buf);
@ -113,7 +112,6 @@ static inline void flush_fpu(void)
extern asmlinkage
void unexpected_fpu_exception(struct pt_regs *, enum exception_code);
#define fpu_invalid_op unexpected_fpu_exception
#define fpu_exception unexpected_fpu_exception
struct task_struct;

View File

@ -20,7 +20,7 @@
/*
* interrupt control
* - "disabled": run in IM1/2
* - level 0 - GDB stub
* - level 0 - kernel debugger
* - level 1 - virtual serial DMA (if present)
* - level 5 - normal interrupt priority
* - level 6 - timer interrupt

View File

@ -34,7 +34,7 @@
#define LOCAL_TIMER_IPI 193
#define FLUSH_CACHE_IPI 194
#define CALL_FUNCTION_NMI_IPI 195
#define GDB_NMI_IPI 196
#define DEBUGGER_NMI_IPI 196
#define SMP_BOOT_IRQ 195
@ -43,6 +43,7 @@
#define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4
#define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0
#define SMP_BOOT_GxICR_LV GxICR_LEVEL_0
#define DEBUGGER_GxICR_LV CONFIG_DEBUGGER_IRQ_LEVEL
#define TIME_OUT_COUNT_BOOT_IPI 100
#define DELAY_TIME_BOOT_IPI 75000

View File

@ -266,7 +266,11 @@ ENTRY(raw_bus_error)
###############################################################################
#
# Miscellaneous exception entry points
# NMI exception entry points
#
# This is used by ordinary interrupt channels that have the GxICR_NMI bit set
# in addition to the main NMI and Watchdog channels. SMP NMI IPIs use this
# facility.
#
###############################################################################
ENTRY(nmi_handler)
@ -281,7 +285,7 @@ ENTRY(nmi_handler)
and NMIAGR_GN,d0
lsr 0x2,d0
cmp CALL_FUNCTION_NMI_IPI,d0
bne 5f # if not call function, jump
bne nmi_not_smp_callfunc # if not call function, jump
# function call nmi ipi
add 4,sp # no need to store TBR
@ -295,30 +299,38 @@ ENTRY(nmi_handler)
call smp_nmi_call_function_interrupt[],0
RESTORE_ALL
5:
#ifdef CONFIG_GDBSTUB
cmp GDB_NMI_IPI,d0
bne 3f # if not gdb nmi ipi, jump
nmi_not_smp_callfunc:
#ifdef CONFIG_KERNEL_DEBUGGER
cmp DEBUGGER_NMI_IPI,d0
bne nmi_not_debugger # if not kernel debugger NMI IPI, jump
# gdb nmi ipi
# kernel debugger NMI IPI
add 4,sp # no need to store TBR
mov GxICR_DETECT,d0 # clear NMI
movbu d0,(GxICR(GDB_NMI_IPI))
movhu (GxICR(GDB_NMI_IPI)),d0
movbu d0,(GxICR(DEBUGGER_NMI_IPI))
movhu (GxICR(DEBUGGER_NMI_IPI)),d0
and ~EPSW_NMID,epsw # enable NMI
mov (sp),d0
SAVE_ALL
call gdbstub_nmi_wait[],0
mov fp,d0 # arg 0: stacked register file
mov a2,d1 # arg 1: exception number
call debugger_nmi_interrupt[],0
RESTORE_ALL
3:
#endif /* CONFIG_GDBSTUB */
nmi_not_debugger:
#endif /* CONFIG_KERNEL_DEBUGGER */
mov (sp),d0 # restore TBR to d0
add 4,sp
#endif /* CONFIG_SMP */
bra __common_exception_nonmi
###############################################################################
#
# General exception entry point
#
###############################################################################
ENTRY(__common_exception)
add -4,sp
mov d0,(sp)

View File

@ -69,24 +69,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
force_sig_info(SIGFPE, &info, tsk);
}
/*
* handle an FPU invalid_op exception
* - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c
*/
asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code)
{
siginfo_t info;
if (!user_mode(regs))
die_if_no_fixup("FPU invalid opcode", regs, code);
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_COPROC;
info.si_addr = (void *) regs->pc;
force_sig_info(info.si_signo, &info, current);
}
/*
* save the FPU state to a signal context
*/

View File

@ -59,10 +59,10 @@ void __init gdbstub_io_init(void)
/* we want to get serial receive interrupts */
set_intr_level(gdbstub_port->rx_irq,
NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
set_intr_level(gdbstub_port->tx_irq,
NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),
gdbstub_io_rx_handler);
*gdbstub_port->rx_icr |= GxICR_ENABLE;
@ -88,7 +88,7 @@ void __init gdbstub_io_init(void)
/* permit level 0 IRQs only */
arch_local_change_intr_mask_level(
NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
}
/*

View File

@ -1173,7 +1173,7 @@ int gdbstub_clear_breakpoint(u8 *addr, int len)
/*
* This function does all command processing for interfacing to gdb
* - returns 1 if the exception should be skipped, 0 otherwise.
* - returns 0 if the exception should be skipped, -ERROR otherwise.
*/
static int gdbstub(struct pt_regs *regs, enum exception_code excep)
{
@ -1188,7 +1188,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
int loop;
if (excep == EXCEP_FPU_DISABLED)
return 0;
return -ENOTSUPP;
gdbstub_flush_caches = 0;
@ -1197,7 +1197,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
asm volatile("mov mdr,%0" : "=d"(mdr));
local_save_flags(epsw);
arch_local_change_intr_mask_level(
NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
gdbstub_store_fpu();
@ -1675,14 +1675,23 @@ done:
touch_softlockup_watchdog();
local_irq_restore(epsw);
return 1;
return 0;
}
/*
* Determine if we hit a debugger special breakpoint that needs skipping over
* automatically.
*/
int at_debugger_breakpoint(struct pt_regs *regs)
{
return 0;
}
/*
* handle event interception
*/
asmlinkage int gdbstub_intercept(struct pt_regs *regs,
enum exception_code excep)
asmlinkage int debugger_intercept(enum exception_code excep,
int signo, int si_code, struct pt_regs *regs)
{
static u8 notfirst = 1;
int ret;
@ -1696,7 +1705,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
asm("mov mdr,%0" : "=d"(mdr));
gdbstub_entry(
"--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
"--> debugger_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
regs, excep, mdr, regs->pc);
gdbstub_entry(
@ -1730,7 +1739,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
ret = gdbstub(regs, excep);
gdbstub_entry("<-- gdbstub_intercept()\n");
gdbstub_entry("<-- debugger_intercept()\n");
gdbstub_busy = 0;
return ret;
}

View File

@ -29,6 +29,13 @@ extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
extern void mn10300_low_ipi_handler(void);
#endif
/*
* smp.c
*/
#ifdef CONFIG_SMP
extern void smp_jump_to_debugger(void);
#endif
/*
* time.c
*/

View File

@ -153,7 +153,7 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
case LOCAL_TIMER_IPI:
case FLUSH_CACHE_IPI:
case CALL_FUNCTION_NMI_IPI:
case GDB_NMI_IPI:
case DEBUGGER_NMI_IPI:
#ifdef CONFIG_MN10300_TTYSM0
case SC0RXIRQ:
case SC0TXIRQ:

View File

@ -439,6 +439,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
return ret;
}
/**
* smp_jump_to_debugger - Make other CPUs enter the debugger by sending an IPI
*
* Send a non-maskable request to all other CPUs in the system, instructing
* them to jump into the debugger. The caller is responsible for checking that
* the other CPUs responded to the instruction.
*
* The caller should make sure that this CPU's debugger IPI is disabled.
*/
void smp_jump_to_debugger(void)
{
if (num_online_cpus() > 1)
/* Send a message to all other CPUs */
send_IPI_allbutself(DEBUGGER_NMI_IPI);
}
/**
* stop_this_cpu - Callback to stop a CPU.
* @unused: Callback context (ignored).
@ -603,7 +619,7 @@ static void __init smp_cpu_init(void)
/**
* smp_prepare_cpu_init - Initialise CPU in startup_secondary
*
* Set interrupt level 0-6 setting and init ICR of gdbstub.
* Set interrupt level 0-6 setting and init ICR of the kernel debugger.
*/
void smp_prepare_cpu_init(void)
{
@ -622,15 +638,15 @@ void smp_prepare_cpu_init(void)
for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
#ifdef CONFIG_GDBSTUB
/* initialise GDB-stub */
#ifdef CONFIG_KERNEL_DEBUGGER
/* initialise the kernel debugger interrupt */
do {
unsigned long flags;
u16 tmp16;
flags = arch_local_cli_save();
GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
tmp16 = GxICR(GDB_NMI_IPI);
GxICR(DEBUGGER_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
tmp16 = GxICR(DEBUGGER_NMI_IPI);
arch_local_irq_restore(flags);
} while (0);
#endif

View File

@ -38,8 +38,9 @@
#include <asm/busctl-regs.h>
#include <unit/leds.h>
#include <asm/fpu.h>
#include <asm/gdb-stub.h>
#include <asm/sections.h>
#include <asm/debugger.h>
#include "internal.h"
#if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff)
#error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
@ -49,63 +50,169 @@ int kstack_depth_to_print = 24;
spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock);
ATOMIC_NOTIFIER_HEAD(mn10300_die_chain);
struct exception_to_signal_map {
u8 signo;
u32 si_code;
};
static const struct exception_to_signal_map exception_to_signal_map[256] = {
/* MMU exceptions */
[EXCEP_ITLBMISS >> 3] = { 0, 0 },
[EXCEP_DTLBMISS >> 3] = { 0, 0 },
[EXCEP_IAERROR >> 3] = { 0, 0 },
[EXCEP_DAERROR >> 3] = { 0, 0 },
/* system exceptions */
[EXCEP_TRAP >> 3] = { SIGTRAP, TRAP_BRKPT },
[EXCEP_ISTEP >> 3] = { SIGTRAP, TRAP_TRACE }, /* Monitor */
[EXCEP_IBREAK >> 3] = { SIGTRAP, TRAP_HWBKPT }, /* Monitor */
[EXCEP_OBREAK >> 3] = { SIGTRAP, TRAP_HWBKPT }, /* Monitor */
[EXCEP_PRIVINS >> 3] = { SIGILL, ILL_PRVOPC },
[EXCEP_UNIMPINS >> 3] = { SIGILL, ILL_ILLOPC },
[EXCEP_UNIMPEXINS >> 3] = { SIGILL, ILL_ILLOPC },
[EXCEP_MEMERR >> 3] = { SIGSEGV, SEGV_ACCERR },
[EXCEP_MISALIGN >> 3] = { SIGBUS, BUS_ADRALN },
[EXCEP_BUSERROR >> 3] = { SIGBUS, BUS_ADRERR },
[EXCEP_ILLINSACC >> 3] = { SIGSEGV, SEGV_ACCERR },
[EXCEP_ILLDATACC >> 3] = { SIGSEGV, SEGV_ACCERR },
[EXCEP_IOINSACC >> 3] = { SIGSEGV, SEGV_ACCERR },
[EXCEP_PRIVINSACC >> 3] = { SIGSEGV, SEGV_ACCERR }, /* userspace */
[EXCEP_PRIVDATACC >> 3] = { SIGSEGV, SEGV_ACCERR }, /* userspace */
[EXCEP_DATINSACC >> 3] = { SIGSEGV, SEGV_ACCERR },
[EXCEP_DOUBLE_FAULT >> 3] = { SIGILL, ILL_BADSTK },
/* FPU exceptions */
[EXCEP_FPU_DISABLED >> 3] = { SIGILL, ILL_COPROC },
[EXCEP_FPU_UNIMPINS >> 3] = { SIGILL, ILL_COPROC },
[EXCEP_FPU_OPERATION >> 3] = { SIGFPE, FPE_INTDIV },
/* interrupts */
[EXCEP_WDT >> 3] = { SIGALRM, 0 },
[EXCEP_NMI >> 3] = { SIGQUIT, 0 },
[EXCEP_IRQ_LEVEL0 >> 3] = { SIGINT, 0 },
[EXCEP_IRQ_LEVEL1 >> 3] = { 0, 0 },
[EXCEP_IRQ_LEVEL2 >> 3] = { 0, 0 },
[EXCEP_IRQ_LEVEL3 >> 3] = { 0, 0 },
[EXCEP_IRQ_LEVEL4 >> 3] = { 0, 0 },
[EXCEP_IRQ_LEVEL5 >> 3] = { 0, 0 },
[EXCEP_IRQ_LEVEL6 >> 3] = { 0, 0 },
/* system calls */
[EXCEP_SYSCALL0 >> 3] = { 0, 0 },
[EXCEP_SYSCALL1 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL2 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL3 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL4 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL5 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL6 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL7 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL8 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL9 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL10 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL11 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL12 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL13 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL14 >> 3] = { SIGILL, ILL_ILLTRP },
[EXCEP_SYSCALL15 >> 3] = { SIGABRT, 0 },
};
/*
* These constants are for searching for possible module text
* segments. MODULE_RANGE is a guess of how much space is likely
* to be vmalloced.
* Handle kernel exceptions.
*
* See if there's a fixup handler we can force a jump to when an exception
* happens due to something kernel code did
*/
#define MODULE_RANGE (8 * 1024 * 1024)
int die_if_no_fixup(const char *str, struct pt_regs *regs,
enum exception_code code)
{
u8 opcode;
int signo, si_code;
#define DO_ERROR(signr, prologue, str, name) \
asmlinkage void name(struct pt_regs *regs, u32 intcode) \
{ \
prologue; \
if (die_if_no_fixup(str, regs, intcode)) \
return; \
force_sig(signr, current); \
if (user_mode(regs))
return 0;
peripheral_leds_display_exception(code);
signo = exception_to_signal_map[code >> 3].signo;
si_code = exception_to_signal_map[code >> 3].si_code;
switch (code) {
/* see if we can fixup the kernel accessing memory */
case EXCEP_ITLBMISS:
case EXCEP_DTLBMISS:
case EXCEP_IAERROR:
case EXCEP_DAERROR:
case EXCEP_MEMERR:
case EXCEP_MISALIGN:
case EXCEP_BUSERROR:
case EXCEP_ILLDATACC:
case EXCEP_IOINSACC:
case EXCEP_PRIVINSACC:
case EXCEP_PRIVDATACC:
case EXCEP_DATINSACC:
if (fixup_exception(regs))
return 1;
break;
case EXCEP_TRAP:
case EXCEP_UNIMPINS:
if (get_user(opcode, (uint8_t __user *)regs->pc) != 0)
break;
if (opcode == 0xff) {
if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
return 1;
if (at_debugger_breakpoint(regs))
regs->pc++;
signo = SIGTRAP;
si_code = TRAP_BRKPT;
}
break;
case EXCEP_SYSCALL1 ... EXCEP_SYSCALL14:
/* syscall return addr is _after_ the instruction */
regs->pc -= 2;
break;
case EXCEP_SYSCALL15:
if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_WARN)
return 1;
/* syscall return addr is _after_ the instruction */
regs->pc -= 2;
break;
default:
break;
}
#define DO_EINFO(signr, prologue, str, name, sicode) \
asmlinkage void name(struct pt_regs *regs, u32 intcode) \
{ \
siginfo_t info; \
prologue; \
if (die_if_no_fixup(str, regs, intcode)) \
return; \
info.si_signo = signr; \
if (signr == SIGILL && sicode == ILL_ILLOPC) { \
uint8_t opcode; \
if (get_user(opcode, (uint8_t __user *)regs->pc) == 0) \
if (opcode == 0xff) \
info.si_signo = SIGTRAP; \
} \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void *) regs->pc; \
force_sig_info(info.si_signo, &info, current); \
if (debugger_intercept(code, signo, si_code, regs) == 0)
return 1;
if (notify_die(DIE_GPF, str, regs, code, 0, 0))
return 1;
/* make the process die as the last resort */
die(str, regs, code);
}
DO_ERROR(SIGTRAP, {}, "trap", trap);
DO_ERROR(SIGSEGV, {}, "ibreak", ibreak);
DO_ERROR(SIGSEGV, {}, "obreak", obreak);
DO_EINFO(SIGSEGV, {}, "access error", access_error, SEGV_ACCERR);
DO_EINFO(SIGSEGV, {}, "insn access error", insn_acc_error, SEGV_ACCERR);
DO_EINFO(SIGSEGV, {}, "data access error", data_acc_error, SEGV_ACCERR);
DO_EINFO(SIGILL, {}, "privileged opcode", priv_op, ILL_PRVOPC);
DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC);
DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC);
DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR);
DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR);
/*
* General exception handler
*/
asmlinkage void handle_exception(struct pt_regs *regs, u32 intcode)
{
siginfo_t info;
DO_ERROR(SIGTRAP,
#ifndef CONFIG_MN10300_USING_JTAG
DCR &= ~0x0001,
#else
{},
#endif
"single step", istep);
/* deal with kernel exceptions here */
if (die_if_no_fixup(NULL, regs, intcode))
return;
/* otherwise it's a userspace exception */
info.si_signo = exception_to_signal_map[intcode >> 3].signo;
info.si_code = exception_to_signal_map[intcode >> 3].si_code;
info.si_errno = 0;
info.si_addr = (void *) regs->pc;
force_sig_info(info.si_signo, &info, current);
}
/*
* handle NMI
@ -113,10 +220,8 @@ DO_ERROR(SIGTRAP,
asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
{
/* see if gdbstub wants to deal with it */
#ifdef CONFIG_GDBSTUB
if (gdbstub_intercept(regs, code))
if (debugger_intercept(code, SIGQUIT, 0, regs))
return;
#endif
printk(KERN_WARNING "--- Register Dump ---\n");
show_registers(regs);
@ -128,29 +233,36 @@ asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
*/
void show_trace(unsigned long *sp)
{
unsigned long *stack, addr, module_start, module_end;
int i;
unsigned long bottom, stack, addr, fp, raslot;
printk(KERN_EMERG "\nCall Trace:");
printk(KERN_EMERG "\nCall Trace:\n");
stack = sp;
i = 0;
module_start = VMALLOC_START;
module_end = VMALLOC_END;
//stack = (unsigned long)sp;
asm("mov sp,%0" : "=a"(stack));
asm("mov a3,%0" : "=r"(fp));
raslot = ULONG_MAX;
bottom = (stack + THREAD_SIZE) & ~(THREAD_SIZE - 1);
for (; stack < bottom; stack += sizeof(addr)) {
addr = *(unsigned long *)stack;
if (stack == fp) {
if (addr > stack && addr < bottom) {
fp = addr;
raslot = stack + sizeof(addr);
continue;
}
fp = 0;
raslot = ULONG_MAX;
}
while (((long) stack & (THREAD_SIZE - 1)) != 0) {
addr = *stack++;
if (__kernel_text_address(addr)) {
#if 1
printk(" [<%08lx>]", addr);
if (stack >= raslot)
raslot = ULONG_MAX;
else
printk(" ?");
print_symbol(" %s", addr);
printk("\n");
#else
if ((i % 6) == 0)
printk(KERN_EMERG " ");
printk("[<%08lx>] ", addr);
i++;
#endif
}
}
@ -322,86 +434,6 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code)
do_exit(SIGSEGV);
}
/*
* see if there's a fixup handler we can force a jump to when an exception
* happens due to something kernel code did
*/
int die_if_no_fixup(const char *str, struct pt_regs *regs,
enum exception_code code)
{
if (user_mode(regs))
return 0;
peripheral_leds_display_exception(code);
switch (code) {
/* see if we can fixup the kernel accessing memory */
case EXCEP_ITLBMISS:
case EXCEP_DTLBMISS:
case EXCEP_IAERROR:
case EXCEP_DAERROR:
case EXCEP_MEMERR:
case EXCEP_MISALIGN:
case EXCEP_BUSERROR:
case EXCEP_ILLDATACC:
case EXCEP_IOINSACC:
case EXCEP_PRIVINSACC:
case EXCEP_PRIVDATACC:
case EXCEP_DATINSACC:
if (fixup_exception(regs))
return 1;
case EXCEP_UNIMPINS:
if (regs->pc && *(uint8_t *)regs->pc == 0xff)
if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
return 1;
break;
default:
break;
}
/* see if gdbstub wants to deal with it */
#ifdef CONFIG_GDBSTUB
if (gdbstub_intercept(regs, code))
return 1;
#endif
if (notify_die(DIE_GPF, str, regs, code, 0, 0))
return 1;
/* make the process die as the last resort */
die(str, regs, code);
}
/*
* handle unsupported syscall instructions (syscall 1-15)
*/
static asmlinkage void unsupported_syscall(struct pt_regs *regs,
enum exception_code code)
{
struct task_struct *tsk = current;
siginfo_t info;
/* catch a kernel BUG() */
if (code == EXCEP_SYSCALL15 && !user_mode(regs)) {
if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_BUG) {
#ifdef CONFIG_GDBSTUB
gdbstub_intercept(regs, code);
#endif
}
}
regs->pc -= 2; /* syscall return addr is _after_ the instruction */
die_if_no_fixup("An unsupported syscall insn was used by the kernel\n",
regs, code);
info.si_signo = SIGILL;
info.si_errno = ENOSYS;
info.si_code = ILL_ILLTRP;
info.si_addr = (void *) regs->pc;
force_sig_info(SIGILL, &info, tsk);
}
/*
* display the register file when the stack pointer gets clobbered
*/
@ -481,10 +513,8 @@ asmlinkage void uninitialised_exception(struct pt_regs *regs,
{
/* see if gdbstub wants to deal with it */
#ifdef CONFIG_GDBSTUB
if (gdbstub_intercept(regs, code))
if (debugger_intercept(code, SIGSYS, 0, regs) == 0)
return;
#endif
peripheral_leds_display_exception(code);
printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF);
@ -549,43 +579,43 @@ void __init set_intr_stub(enum exception_code code, void *handler)
*/
void __init trap_init(void)
{
set_excp_vector(EXCEP_TRAP, trap);
set_excp_vector(EXCEP_ISTEP, istep);
set_excp_vector(EXCEP_IBREAK, ibreak);
set_excp_vector(EXCEP_OBREAK, obreak);
set_excp_vector(EXCEP_TRAP, handle_exception);
set_excp_vector(EXCEP_ISTEP, handle_exception);
set_excp_vector(EXCEP_IBREAK, handle_exception);
set_excp_vector(EXCEP_OBREAK, handle_exception);
set_excp_vector(EXCEP_PRIVINS, priv_op);
set_excp_vector(EXCEP_UNIMPINS, invalid_op);
set_excp_vector(EXCEP_UNIMPEXINS, invalid_exop);
set_excp_vector(EXCEP_MEMERR, mem_error);
set_excp_vector(EXCEP_PRIVINS, handle_exception);
set_excp_vector(EXCEP_UNIMPINS, handle_exception);
set_excp_vector(EXCEP_UNIMPEXINS, handle_exception);
set_excp_vector(EXCEP_MEMERR, handle_exception);
set_excp_vector(EXCEP_MISALIGN, misalignment);
set_excp_vector(EXCEP_BUSERROR, bus_error);
set_excp_vector(EXCEP_ILLINSACC, insn_acc_error);
set_excp_vector(EXCEP_ILLDATACC, data_acc_error);
set_excp_vector(EXCEP_IOINSACC, insn_acc_error);
set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error);
set_excp_vector(EXCEP_PRIVDATACC, data_acc_error);
set_excp_vector(EXCEP_DATINSACC, insn_acc_error);
set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op);
set_excp_vector(EXCEP_BUSERROR, handle_exception);
set_excp_vector(EXCEP_ILLINSACC, handle_exception);
set_excp_vector(EXCEP_ILLDATACC, handle_exception);
set_excp_vector(EXCEP_IOINSACC, handle_exception);
set_excp_vector(EXCEP_PRIVINSACC, handle_exception);
set_excp_vector(EXCEP_PRIVDATACC, handle_exception);
set_excp_vector(EXCEP_DATINSACC, handle_exception);
set_excp_vector(EXCEP_FPU_UNIMPINS, handle_exception);
set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception);
set_excp_vector(EXCEP_NMI, nmi);
set_excp_vector(EXCEP_SYSCALL1, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL2, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL3, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL4, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL5, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL6, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL7, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL8, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL9, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL10, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL11, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL12, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL13, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL14, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL15, unsupported_syscall);
set_excp_vector(EXCEP_SYSCALL1, handle_exception);
set_excp_vector(EXCEP_SYSCALL2, handle_exception);
set_excp_vector(EXCEP_SYSCALL3, handle_exception);
set_excp_vector(EXCEP_SYSCALL4, handle_exception);
set_excp_vector(EXCEP_SYSCALL5, handle_exception);
set_excp_vector(EXCEP_SYSCALL6, handle_exception);
set_excp_vector(EXCEP_SYSCALL7, handle_exception);
set_excp_vector(EXCEP_SYSCALL8, handle_exception);
set_excp_vector(EXCEP_SYSCALL9, handle_exception);
set_excp_vector(EXCEP_SYSCALL10, handle_exception);
set_excp_vector(EXCEP_SYSCALL11, handle_exception);
set_excp_vector(EXCEP_SYSCALL12, handle_exception);
set_excp_vector(EXCEP_SYSCALL13, handle_exception);
set_excp_vector(EXCEP_SYSCALL14, handle_exception);
set_excp_vector(EXCEP_SYSCALL15, handle_exception);
}
/*

View File

@ -28,8 +28,9 @@
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/hardirq.h>
#include <asm/gdb-stub.h>
#include <asm/cpu-regs.h>
#include <asm/debugger.h>
#include <asm/gdb-stub.h>
/*
* Unlock any spinlocks which will prevent us from getting the
@ -306,10 +307,8 @@ no_context:
printk(" printing pc:\n");
printk(KERN_ALERT "%08lx\n", regs->pc);
#ifdef CONFIG_GDBSTUB
gdbstub_intercept(
regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR);
#endif
debugger_intercept(fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR,
SIGSEGV, SEGV_ACCERR, regs);
page = PTBR;
page = ((unsigned long *) __va(page))[address >> 22];