Commit 67ddb405 authored by David Howells's avatar 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: default avatarDavid Howells <dhowells@redhat.com>
parent 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
......
This diff is collapsed.
...@@ -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%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment