提交 67ddb405 编写于 作者: D David Howells

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: NDavid Howells <dhowells@redhat.com>
上级 7f386ac3
...@@ -401,8 +401,8 @@ comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highes ...@@ -401,8 +401,8 @@ comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highes
comment "____Non-maskable interrupt levels____" comment "____Non-maskable interrupt levels____"
comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial" comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial"
config GDBSTUB_IRQ_LEVEL config DEBUGGER_IRQ_LEVEL
int "GDBSTUB interrupt priority" int "DEBUGGER interrupt priority"
depends on KERNEL_DEBUGGER depends on KERNEL_DEBUGGER
range 0 1 if LINUX_CLI_LEVEL = 2 range 0 1 if LINUX_CLI_LEVEL = 2
range 0 2 if LINUX_CLI_LEVEL = 3 range 0 2 if LINUX_CLI_LEVEL = 3
...@@ -437,7 +437,7 @@ config LINUX_CLI_LEVEL ...@@ -437,7 +437,7 @@ config LINUX_CLI_LEVEL
EPSW.IM from 7. Any interrupt is permitted for which the level is EPSW.IM from 7. Any interrupt is permitted for which the level is
lower than EPSW.IM. 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 serial DMA interrupts are allowed to interrupt normal disabled
sections. sections.
......
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#if defined(CONFIG_KERNEL_DEBUGGER) #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 #ifndef CONFIG_MN10300_DEBUGGER_CACHE_NO_FLUSH
extern void debugger_local_cache_flushinv(void); extern void debugger_local_cache_flushinv(void);
extern void debugger_local_cache_flushinv_one(u8 *); extern void debugger_local_cache_flushinv_one(u8 *);
...@@ -24,5 +27,17 @@ static inline void debugger_local_cache_flushinv_one(u8 *addr) {} ...@@ -24,5 +27,17 @@ static inline void debugger_local_cache_flushinv_one(u8 *addr) {}
#else /* CONFIG_KERNEL_DEBUGGER */ #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 /* CONFIG_KERNEL_DEBUGGER */
#endif /* _ASM_DEBUGGER_H */ #endif /* _ASM_DEBUGGER_H */
...@@ -55,7 +55,6 @@ static inline void clear_using_fpu(struct task_struct *tsk) ...@@ -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_kill_state(struct task_struct *);
extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code); 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_init_state(void);
extern asmlinkage void fpu_save(struct fpu_state_struct *); extern asmlinkage void fpu_save(struct fpu_state_struct *);
extern int fpu_setup_sigcontext(struct fpucontext *buf); extern int fpu_setup_sigcontext(struct fpucontext *buf);
...@@ -113,7 +112,6 @@ static inline void flush_fpu(void) ...@@ -113,7 +112,6 @@ static inline void flush_fpu(void)
extern asmlinkage extern asmlinkage
void unexpected_fpu_exception(struct pt_regs *, enum exception_code); void unexpected_fpu_exception(struct pt_regs *, enum exception_code);
#define fpu_invalid_op unexpected_fpu_exception
#define fpu_exception unexpected_fpu_exception #define fpu_exception unexpected_fpu_exception
struct task_struct; struct task_struct;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/* /*
* interrupt control * interrupt control
* - "disabled": run in IM1/2 * - "disabled": run in IM1/2
* - level 0 - GDB stub * - level 0 - kernel debugger
* - level 1 - virtual serial DMA (if present) * - level 1 - virtual serial DMA (if present)
* - level 5 - normal interrupt priority * - level 5 - normal interrupt priority
* - level 6 - timer interrupt * - level 6 - timer interrupt
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#define LOCAL_TIMER_IPI 193 #define LOCAL_TIMER_IPI 193
#define FLUSH_CACHE_IPI 194 #define FLUSH_CACHE_IPI 194
#define CALL_FUNCTION_NMI_IPI 195 #define CALL_FUNCTION_NMI_IPI 195
#define GDB_NMI_IPI 196 #define DEBUGGER_NMI_IPI 196
#define SMP_BOOT_IRQ 195 #define SMP_BOOT_IRQ 195
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4 #define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4
#define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0 #define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0
#define SMP_BOOT_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 TIME_OUT_COUNT_BOOT_IPI 100
#define DELAY_TIME_BOOT_IPI 75000 #define DELAY_TIME_BOOT_IPI 75000
......
...@@ -266,7 +266,11 @@ ENTRY(raw_bus_error) ...@@ -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) ENTRY(nmi_handler)
...@@ -281,7 +285,7 @@ ENTRY(nmi_handler) ...@@ -281,7 +285,7 @@ ENTRY(nmi_handler)
and NMIAGR_GN,d0 and NMIAGR_GN,d0
lsr 0x2,d0 lsr 0x2,d0
cmp CALL_FUNCTION_NMI_IPI,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 # function call nmi ipi
add 4,sp # no need to store TBR add 4,sp # no need to store TBR
...@@ -295,30 +299,38 @@ ENTRY(nmi_handler) ...@@ -295,30 +299,38 @@ ENTRY(nmi_handler)
call smp_nmi_call_function_interrupt[],0 call smp_nmi_call_function_interrupt[],0
RESTORE_ALL RESTORE_ALL
5: nmi_not_smp_callfunc:
#ifdef CONFIG_GDBSTUB #ifdef CONFIG_KERNEL_DEBUGGER
cmp GDB_NMI_IPI,d0 cmp DEBUGGER_NMI_IPI,d0
bne 3f # if not gdb nmi ipi, jump 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 add 4,sp # no need to store TBR
mov GxICR_DETECT,d0 # clear NMI mov GxICR_DETECT,d0 # clear NMI
movbu d0,(GxICR(GDB_NMI_IPI)) movbu d0,(GxICR(DEBUGGER_NMI_IPI))
movhu (GxICR(GDB_NMI_IPI)),d0 movhu (GxICR(DEBUGGER_NMI_IPI)),d0
and ~EPSW_NMID,epsw # enable NMI and ~EPSW_NMID,epsw # enable NMI
mov (sp),d0 mov (sp),d0
SAVE_ALL 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 RESTORE_ALL
3:
#endif /* CONFIG_GDBSTUB */ nmi_not_debugger:
#endif /* CONFIG_KERNEL_DEBUGGER */
mov (sp),d0 # restore TBR to d0 mov (sp),d0 # restore TBR to d0
add 4,sp add 4,sp
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
bra __common_exception_nonmi bra __common_exception_nonmi
###############################################################################
#
# General exception entry point
#
###############################################################################
ENTRY(__common_exception) ENTRY(__common_exception)
add -4,sp add -4,sp
mov d0,(sp) mov d0,(sp)
......
...@@ -69,24 +69,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) ...@@ -69,24 +69,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
force_sig_info(SIGFPE, &info, tsk); 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 * save the FPU state to a signal context
*/ */
......
...@@ -59,10 +59,10 @@ void __init gdbstub_io_init(void) ...@@ -59,10 +59,10 @@ void __init gdbstub_io_init(void)
/* we want to get serial receive interrupts */ /* we want to get serial receive interrupts */
set_intr_level(gdbstub_port->rx_irq, 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, set_intr_level(gdbstub_port->tx_irq,
NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),
gdbstub_io_rx_handler); gdbstub_io_rx_handler);
*gdbstub_port->rx_icr |= GxICR_ENABLE; *gdbstub_port->rx_icr |= GxICR_ENABLE;
...@@ -88,7 +88,7 @@ void __init gdbstub_io_init(void) ...@@ -88,7 +88,7 @@ void __init gdbstub_io_init(void)
/* permit level 0 IRQs only */ /* permit level 0 IRQs only */
arch_local_change_intr_mask_level( arch_local_change_intr_mask_level(
NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
} }
/* /*
......
...@@ -1173,7 +1173,7 @@ int gdbstub_clear_breakpoint(u8 *addr, int len) ...@@ -1173,7 +1173,7 @@ int gdbstub_clear_breakpoint(u8 *addr, int len)
/* /*
* This function does all command processing for interfacing to gdb * 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) 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) ...@@ -1188,7 +1188,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
int loop; int loop;
if (excep == EXCEP_FPU_DISABLED) if (excep == EXCEP_FPU_DISABLED)
return 0; return -ENOTSUPP;
gdbstub_flush_caches = 0; gdbstub_flush_caches = 0;
...@@ -1197,7 +1197,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) ...@@ -1197,7 +1197,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
asm volatile("mov mdr,%0" : "=d"(mdr)); asm volatile("mov mdr,%0" : "=d"(mdr));
local_save_flags(epsw); local_save_flags(epsw);
arch_local_change_intr_mask_level( arch_local_change_intr_mask_level(
NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
gdbstub_store_fpu(); gdbstub_store_fpu();
...@@ -1675,14 +1675,23 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) ...@@ -1675,14 +1675,23 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
touch_softlockup_watchdog(); touch_softlockup_watchdog();
local_irq_restore(epsw); 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 * handle event interception
*/ */
asmlinkage int gdbstub_intercept(struct pt_regs *regs, asmlinkage int debugger_intercept(enum exception_code excep,
enum exception_code excep) int signo, int si_code, struct pt_regs *regs)
{ {
static u8 notfirst = 1; static u8 notfirst = 1;
int ret; int ret;
...@@ -1696,7 +1705,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs, ...@@ -1696,7 +1705,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
asm("mov mdr,%0" : "=d"(mdr)); asm("mov mdr,%0" : "=d"(mdr));
gdbstub_entry( 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); regs, excep, mdr, regs->pc);
gdbstub_entry( gdbstub_entry(
...@@ -1730,7 +1739,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs, ...@@ -1730,7 +1739,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
ret = gdbstub(regs, excep); ret = gdbstub(regs, excep);
gdbstub_entry("<-- gdbstub_intercept()\n"); gdbstub_entry("<-- debugger_intercept()\n");
gdbstub_busy = 0; gdbstub_busy = 0;
return ret; return ret;
} }
......
...@@ -29,6 +29,13 @@ extern void ret_from_fork(struct task_struct *) __attribute__((noreturn)); ...@@ -29,6 +29,13 @@ extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
extern void mn10300_low_ipi_handler(void); extern void mn10300_low_ipi_handler(void);
#endif #endif
/*
* smp.c
*/
#ifdef CONFIG_SMP
extern void smp_jump_to_debugger(void);
#endif
/* /*
* time.c * time.c
*/ */
......
...@@ -153,7 +153,7 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask, ...@@ -153,7 +153,7 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
case LOCAL_TIMER_IPI: case LOCAL_TIMER_IPI:
case FLUSH_CACHE_IPI: case FLUSH_CACHE_IPI:
case CALL_FUNCTION_NMI_IPI: case CALL_FUNCTION_NMI_IPI:
case GDB_NMI_IPI: case DEBUGGER_NMI_IPI:
#ifdef CONFIG_MN10300_TTYSM0 #ifdef CONFIG_MN10300_TTYSM0
case SC0RXIRQ: case SC0RXIRQ:
case SC0TXIRQ: case SC0TXIRQ:
......
...@@ -439,6 +439,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait) ...@@ -439,6 +439,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
return ret; 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. * stop_this_cpu - Callback to stop a CPU.
* @unused: Callback context (ignored). * @unused: Callback context (ignored).
...@@ -603,7 +619,7 @@ static void __init smp_cpu_init(void) ...@@ -603,7 +619,7 @@ static void __init smp_cpu_init(void)
/** /**
* smp_prepare_cpu_init - Initialise CPU in startup_secondary * 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) void smp_prepare_cpu_init(void)
{ {
...@@ -622,15 +638,15 @@ void smp_prepare_cpu_init(void) ...@@ -622,15 +638,15 @@ void smp_prepare_cpu_init(void)
for (loop = 0; loop < GxICR_NUM_IRQS; loop++) for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
#ifdef CONFIG_GDBSTUB #ifdef CONFIG_KERNEL_DEBUGGER
/* initialise GDB-stub */ /* initialise the kernel debugger interrupt */
do { do {
unsigned long flags; unsigned long flags;
u16 tmp16; u16 tmp16;
flags = arch_local_cli_save(); flags = arch_local_cli_save();
GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; GxICR(DEBUGGER_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
tmp16 = GxICR(GDB_NMI_IPI); tmp16 = GxICR(DEBUGGER_NMI_IPI);
arch_local_irq_restore(flags); arch_local_irq_restore(flags);
} while (0); } while (0);
#endif #endif
......
...@@ -38,8 +38,9 @@ ...@@ -38,8 +38,9 @@
#include <asm/busctl-regs.h> #include <asm/busctl-regs.h>
#include <unit/leds.h> #include <unit/leds.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#include <asm/gdb-stub.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/debugger.h>
#include "internal.h"
#if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff) #if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff)
#error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!" #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
...@@ -49,63 +50,169 @@ int kstack_depth_to_print = 24; ...@@ -49,63 +50,169 @@ int kstack_depth_to_print = 24;
spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock); 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 * Handle kernel exceptions.
* segments. MODULE_RANGE is a guess of how much space is likely *
* to be vmalloced. * 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)
#define DO_ERROR(signr, prologue, str, name) \ {
asmlinkage void name(struct pt_regs *regs, u32 intcode) \ u8 opcode;
{ \ int signo, si_code;
prologue; \
if (die_if_no_fixup(str, regs, intcode)) \ if (user_mode(regs))
return; \ return 0;
force_sig(signr, current); \
} 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;
#define DO_EINFO(signr, prologue, str, name, sicode) \ case EXCEP_TRAP:
asmlinkage void name(struct pt_regs *regs, u32 intcode) \ case EXCEP_UNIMPINS:
{ \ if (get_user(opcode, (uint8_t __user *)regs->pc) != 0)
siginfo_t info; \ break;
prologue; \ if (opcode == 0xff) {
if (die_if_no_fixup(str, regs, intcode)) \ if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
return; \ return 1;
info.si_signo = signr; \ if (at_debugger_breakpoint(regs))
if (signr == SIGILL && sicode == ILL_ILLOPC) { \ regs->pc++;
uint8_t opcode; \ signo = SIGTRAP;
if (get_user(opcode, (uint8_t __user *)regs->pc) == 0) \ si_code = TRAP_BRKPT;
if (opcode == 0xff) \ }
info.si_signo = SIGTRAP; \ break;
} \
info.si_errno = 0; \ case EXCEP_SYSCALL1 ... EXCEP_SYSCALL14:
info.si_code = sicode; \ /* syscall return addr is _after_ the instruction */
info.si_addr = (void *) regs->pc; \ regs->pc -= 2;
force_sig_info(info.si_signo, &info, current); \ 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;
}
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); * General exception handler
DO_ERROR(SIGSEGV, {}, "obreak", obreak); */
DO_EINFO(SIGSEGV, {}, "access error", access_error, SEGV_ACCERR); asmlinkage void handle_exception(struct pt_regs *regs, u32 intcode)
DO_EINFO(SIGSEGV, {}, "insn access error", insn_acc_error, SEGV_ACCERR); {
DO_EINFO(SIGSEGV, {}, "data access error", data_acc_error, SEGV_ACCERR); siginfo_t info;
DO_EINFO(SIGILL, {}, "privileged opcode", priv_op, ILL_PRVOPC);
DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC); /* deal with kernel exceptions here */
DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC); if (die_if_no_fixup(NULL, regs, intcode))
DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR); return;
DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR);
/* otherwise it's a userspace exception */
DO_ERROR(SIGTRAP, info.si_signo = exception_to_signal_map[intcode >> 3].signo;
#ifndef CONFIG_MN10300_USING_JTAG info.si_code = exception_to_signal_map[intcode >> 3].si_code;
DCR &= ~0x0001, info.si_errno = 0;
#else info.si_addr = (void *) regs->pc;
{}, force_sig_info(info.si_signo, &info, current);
#endif }
"single step", istep);
/* /*
* handle NMI * handle NMI
...@@ -113,10 +220,8 @@ DO_ERROR(SIGTRAP, ...@@ -113,10 +220,8 @@ DO_ERROR(SIGTRAP,
asmlinkage void nmi(struct pt_regs *regs, enum exception_code code) asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
{ {
/* see if gdbstub wants to deal with it */ /* see if gdbstub wants to deal with it */
#ifdef CONFIG_GDBSTUB if (debugger_intercept(code, SIGQUIT, 0, regs))
if (gdbstub_intercept(regs, code))
return; return;
#endif
printk(KERN_WARNING "--- Register Dump ---\n"); printk(KERN_WARNING "--- Register Dump ---\n");
show_registers(regs); show_registers(regs);
...@@ -128,29 +233,36 @@ asmlinkage void nmi(struct pt_regs *regs, enum exception_code code) ...@@ -128,29 +233,36 @@ asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
*/ */
void show_trace(unsigned long *sp) void show_trace(unsigned long *sp)
{ {
unsigned long *stack, addr, module_start, module_end; unsigned long bottom, stack, addr, fp, raslot;
int i;
printk(KERN_EMERG "\nCall Trace:\n");
printk(KERN_EMERG "\nCall Trace:");
//stack = (unsigned long)sp;
stack = sp; asm("mov sp,%0" : "=a"(stack));
i = 0; asm("mov a3,%0" : "=r"(fp));
module_start = VMALLOC_START;
module_end = VMALLOC_END; 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 (__kernel_text_address(addr)) {
#if 1
printk(" [<%08lx>]", addr); printk(" [<%08lx>]", addr);
if (stack >= raslot)
raslot = ULONG_MAX;
else
printk(" ?");
print_symbol(" %s", addr); print_symbol(" %s", addr);
printk("\n"); 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) ...@@ -322,86 +434,6 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code)
do_exit(SIGSEGV); 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 * display the register file when the stack pointer gets clobbered
*/ */
...@@ -481,10 +513,8 @@ asmlinkage void uninitialised_exception(struct pt_regs *regs, ...@@ -481,10 +513,8 @@ asmlinkage void uninitialised_exception(struct pt_regs *regs,
{ {
/* see if gdbstub wants to deal with it */ /* see if gdbstub wants to deal with it */
#ifdef CONFIG_GDBSTUB if (debugger_intercept(code, SIGSYS, 0, regs) == 0)
if (gdbstub_intercept(regs, code))
return; return;
#endif
peripheral_leds_display_exception(code); peripheral_leds_display_exception(code);
printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF); 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) ...@@ -549,43 +579,43 @@ void __init set_intr_stub(enum exception_code code, void *handler)
*/ */
void __init trap_init(void) void __init trap_init(void)
{ {
set_excp_vector(EXCEP_TRAP, trap); set_excp_vector(EXCEP_TRAP, handle_exception);
set_excp_vector(EXCEP_ISTEP, istep); set_excp_vector(EXCEP_ISTEP, handle_exception);
set_excp_vector(EXCEP_IBREAK, ibreak); set_excp_vector(EXCEP_IBREAK, handle_exception);
set_excp_vector(EXCEP_OBREAK, obreak); set_excp_vector(EXCEP_OBREAK, handle_exception);
set_excp_vector(EXCEP_PRIVINS, priv_op); set_excp_vector(EXCEP_PRIVINS, handle_exception);
set_excp_vector(EXCEP_UNIMPINS, invalid_op); set_excp_vector(EXCEP_UNIMPINS, handle_exception);
set_excp_vector(EXCEP_UNIMPEXINS, invalid_exop); set_excp_vector(EXCEP_UNIMPEXINS, handle_exception);
set_excp_vector(EXCEP_MEMERR, mem_error); set_excp_vector(EXCEP_MEMERR, handle_exception);
set_excp_vector(EXCEP_MISALIGN, misalignment); set_excp_vector(EXCEP_MISALIGN, misalignment);
set_excp_vector(EXCEP_BUSERROR, bus_error); set_excp_vector(EXCEP_BUSERROR, handle_exception);
set_excp_vector(EXCEP_ILLINSACC, insn_acc_error); set_excp_vector(EXCEP_ILLINSACC, handle_exception);
set_excp_vector(EXCEP_ILLDATACC, data_acc_error); set_excp_vector(EXCEP_ILLDATACC, handle_exception);
set_excp_vector(EXCEP_IOINSACC, insn_acc_error); set_excp_vector(EXCEP_IOINSACC, handle_exception);
set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error); set_excp_vector(EXCEP_PRIVINSACC, handle_exception);
set_excp_vector(EXCEP_PRIVDATACC, data_acc_error); set_excp_vector(EXCEP_PRIVDATACC, handle_exception);
set_excp_vector(EXCEP_DATINSACC, insn_acc_error); set_excp_vector(EXCEP_DATINSACC, handle_exception);
set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op); set_excp_vector(EXCEP_FPU_UNIMPINS, handle_exception);
set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception);
set_excp_vector(EXCEP_NMI, nmi); set_excp_vector(EXCEP_NMI, nmi);
set_excp_vector(EXCEP_SYSCALL1, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL1, handle_exception);
set_excp_vector(EXCEP_SYSCALL2, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL2, handle_exception);
set_excp_vector(EXCEP_SYSCALL3, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL3, handle_exception);
set_excp_vector(EXCEP_SYSCALL4, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL4, handle_exception);
set_excp_vector(EXCEP_SYSCALL5, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL5, handle_exception);
set_excp_vector(EXCEP_SYSCALL6, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL6, handle_exception);
set_excp_vector(EXCEP_SYSCALL7, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL7, handle_exception);
set_excp_vector(EXCEP_SYSCALL8, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL8, handle_exception);
set_excp_vector(EXCEP_SYSCALL9, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL9, handle_exception);
set_excp_vector(EXCEP_SYSCALL10, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL10, handle_exception);
set_excp_vector(EXCEP_SYSCALL11, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL11, handle_exception);
set_excp_vector(EXCEP_SYSCALL12, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL12, handle_exception);
set_excp_vector(EXCEP_SYSCALL13, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL13, handle_exception);
set_excp_vector(EXCEP_SYSCALL14, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL14, handle_exception);
set_excp_vector(EXCEP_SYSCALL15, unsupported_syscall); set_excp_vector(EXCEP_SYSCALL15, handle_exception);
} }
/* /*
......
...@@ -28,8 +28,9 @@ ...@@ -28,8 +28,9 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <asm/gdb-stub.h>
#include <asm/cpu-regs.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 * Unlock any spinlocks which will prevent us from getting the
...@@ -306,10 +307,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code, ...@@ -306,10 +307,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
printk(" printing pc:\n"); printk(" printing pc:\n");
printk(KERN_ALERT "%08lx\n", regs->pc); printk(KERN_ALERT "%08lx\n", regs->pc);
#ifdef CONFIG_GDBSTUB debugger_intercept(fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR,
gdbstub_intercept( SIGSEGV, SEGV_ACCERR, regs);
regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR);
#endif
page = PTBR; page = PTBR;
page = ((unsigned long *) __va(page))[address >> 22]; page = ((unsigned long *) __va(page))[address >> 22];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册