MN10300: Create generic kernel debugger hooks
authorDavid Howells <dhowells@redhat.com>
Fri, 18 Mar 2011 16:54:30 +0000 (16:54 +0000)
committerDavid Howells <dhowells@redhat.com>
Fri, 18 Mar 2011 16:54:30 +0000 (16:54 +0000)
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>
14 files changed:
arch/mn10300/Kconfig
arch/mn10300/include/asm/debugger.h
arch/mn10300/include/asm/fpu.h
arch/mn10300/include/asm/irqflags.h
arch/mn10300/include/asm/smp.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/fpu.c
arch/mn10300/kernel/gdb-io-ttysm.c
arch/mn10300/kernel/gdb-stub.c
arch/mn10300/kernel/internal.h
arch/mn10300/kernel/irq.c
arch/mn10300/kernel/smp.c
arch/mn10300/kernel/traps.c
arch/mn10300/mm/fault.c

index 25e6a0b..6e9cac9 100644 (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.
 
index 4517f83..e1d3b08 100644 (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 */
index b7625de..738ff72 100644 (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;
index 7a7ae12..678f68d 100644 (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
index a3930e4..e3d13a8 100644 (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
index 8e79a04..fb93ad7 100644 (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)
index 5f9c3fa..bb5fa7d 100644 (file)
@@ -70,24 +70,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
 }
 
 /*
- * 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
  */
 int fpu_setup_sigcontext(struct fpucontext *fpucontext)
index abdeea1..c859cac 100644 (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));
 }
 
 /*
index 1e8f24f..538266b 100644 (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;
 }
index ea94661..a5ac755 100644 (file)
@@ -30,6 +30,13 @@ extern void mn10300_low_ipi_handler(void);
 #endif
 
 /*
+ * smp.c
+ */
+#ifdef CONFIG_SMP
+extern void smp_jump_to_debugger(void);
+#endif
+
+/*
  * time.c
  */
 extern irqreturn_t local_timer_interrupt(void);
index f09fed5..5f7fc3e 100644 (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:
index 1ebb79f..51c02f9 100644 (file)
@@ -440,6 +440,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
 }
 
 /**
+ * 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
index b90c3f1..f03cb27 100644 (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)
-
-#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);                              \
-}
+int die_if_no_fixup(const char *str, struct pt_regs *regs,
+                   enum exception_code code)
+{
+       u8 opcode;
+       int signo, si_code;
+
+       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;
 
-#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);                  \
+       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;
+       }
+
+       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);
-
-DO_ERROR(SIGTRAP,
-#ifndef CONFIG_MN10300_USING_JTAG
-        DCR &= ~0x0001,
-#else
-        {},
-#endif
-        "single step", istep);
+/*
+ * General exception handler
+ */
+asmlinkage void handle_exception(struct pt_regs *regs, u32 intcode)
+{
+       siginfo_t info;
+
+       /* 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;
-
-       printk(KERN_EMERG "\nCall Trace:");
-
-       stack = sp;
-       i = 0;
-       module_start = VMALLOC_START;
-       module_end = VMALLOC_END;
+       unsigned long bottom, stack, addr, fp, raslot;
+
+       printk(KERN_EMERG "\nCall Trace:\n");
+
+       //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
                }
        }
 
@@ -323,86 +435,6 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code)
 }
 
 /*
- * 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
  */
 asmlinkage void do_double_fault(struct pt_regs *regs)
@@ -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_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_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,          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);
 }
 
 /*
index 59c3da4..0945409 100644 (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];