Commit e460d64405c04581e42aa9cbae76815a2d4e9abe

Authored by David Howells
1 parent 67ddb4052d

MN10300: Use KGDB

Showing 6 changed files with 289 additions and 2 deletions Side-by-side Diff

arch/mn10300/Kconfig
... ... @@ -3,6 +3,8 @@
3 3 select HAVE_OPROFILE
4 4 select HAVE_GENERIC_HARDIRQS
5 5 select GENERIC_HARDIRQS_NO_DEPRECATED
  6 + select HAVE_ARCH_TRACEHOOK
  7 + select HAVE_ARCH_KGDB
6 8  
7 9 config AM33_2
8 10 def_bool n
arch/mn10300/Kconfig.debug
... ... @@ -153,5 +153,5 @@
153 153  
154 154 config KERNEL_DEBUGGER
155 155 def_bool y
156   - depends on GDBSTUB
  156 + depends on GDBSTUB || KGDB
arch/mn10300/include/asm/kgdb.h
  1 +/* Kernel debugger for MN10300
  2 + *
  3 + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public Licence
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the Licence, or (at your option) any later version.
  10 + */
  11 +
  12 +#ifndef _ASM_KGDB_H
  13 +#define _ASM_KGDB_H
  14 +
  15 +/*
  16 + * BUFMAX defines the maximum number of characters in inbound/outbound
  17 + * buffers at least NUMREGBYTES*2 are needed for register packets
  18 + * Longer buffer is needed to list all threads
  19 + */
  20 +#define BUFMAX 1024
  21 +
  22 +/*
  23 + * Note that this register image is in a different order than the register
  24 + * image that Linux produces at interrupt time.
  25 + */
  26 +enum regnames {
  27 + GDB_FR_D0 = 0,
  28 + GDB_FR_D1 = 1,
  29 + GDB_FR_D2 = 2,
  30 + GDB_FR_D3 = 3,
  31 + GDB_FR_A0 = 4,
  32 + GDB_FR_A1 = 5,
  33 + GDB_FR_A2 = 6,
  34 + GDB_FR_A3 = 7,
  35 +
  36 + GDB_FR_SP = 8,
  37 + GDB_FR_PC = 9,
  38 + GDB_FR_MDR = 10,
  39 + GDB_FR_EPSW = 11,
  40 + GDB_FR_LIR = 12,
  41 + GDB_FR_LAR = 13,
  42 + GDB_FR_MDRQ = 14,
  43 +
  44 + GDB_FR_E0 = 15,
  45 + GDB_FR_E1 = 16,
  46 + GDB_FR_E2 = 17,
  47 + GDB_FR_E3 = 18,
  48 + GDB_FR_E4 = 19,
  49 + GDB_FR_E5 = 20,
  50 + GDB_FR_E6 = 21,
  51 + GDB_FR_E7 = 22,
  52 +
  53 + GDB_FR_SSP = 23,
  54 + GDB_FR_MSP = 24,
  55 + GDB_FR_USP = 25,
  56 + GDB_FR_MCRH = 26,
  57 + GDB_FR_MCRL = 27,
  58 + GDB_FR_MCVF = 28,
  59 +
  60 + GDB_FR_FPCR = 29,
  61 + GDB_FR_DUMMY0 = 30,
  62 + GDB_FR_DUMMY1 = 31,
  63 +
  64 + GDB_FR_FS0 = 32,
  65 +
  66 + GDB_FR_SIZE = 64,
  67 +};
  68 +
  69 +#define GDB_ORIG_D0 41
  70 +#define NUMREGBYTES (GDB_FR_SIZE*4)
  71 +
  72 +static inline void arch_kgdb_breakpoint(void)
  73 +{
  74 + asm(".globl __arch_kgdb_breakpoint; __arch_kgdb_breakpoint: break");
  75 +}
  76 +extern u8 __arch_kgdb_breakpoint;
  77 +
  78 +#define BREAK_INSTR_SIZE 1
  79 +#define CACHE_FLUSH_IS_SAFE 1
  80 +
  81 +#endif /* _ASM_KGDB_H */
arch/mn10300/include/asm/smp.h
... ... @@ -62,8 +62,9 @@
62 62 * An alternate way of dealing with this could be to use the EPSW.S bits to
63 63 * cache this information for systems with up to four CPUs.
64 64 */
  65 +#define arch_smp_processor_id() (CPUID)
65 66 #if 0
66   -#define raw_smp_processor_id() (CPUID)
  67 +#define raw_smp_processor_id() (arch_smp_processor_id())
67 68 #else
68 69 #define raw_smp_processor_id() (current_thread_info()->cpu)
69 70 #endif
arch/mn10300/kernel/Makefile
... ... @@ -25,4 +25,5 @@
25 25 obj-$(CONFIG_PROFILE) += profile.o profile-low.o
26 26 obj-$(CONFIG_MODULES) += module.o
27 27 obj-$(CONFIG_KPROBES) += kprobes.o
  28 +obj-$(CONFIG_KGDB) += kgdb.o
arch/mn10300/kernel/kgdb.c
  1 +/* kgdb support for MN10300
  2 + *
  3 + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public Licence
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the Licence, or (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/ptrace.h>
  13 +#include <linux/kgdb.h>
  14 +#include <linux/uaccess.h>
  15 +#include <unit/leds.h>
  16 +#include <unit/serial.h>
  17 +#include <asm/debugger.h>
  18 +#include <asm/serial-regs.h>
  19 +#include "internal.h"
  20 +
  21 +/*
  22 + * Copy kernel exception frame registers to the GDB register file
  23 + */
  24 +void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
  25 +{
  26 + unsigned long ssp = (unsigned long) (regs + 1);
  27 +
  28 + gdb_regs[GDB_FR_D0] = regs->d0;
  29 + gdb_regs[GDB_FR_D1] = regs->d1;
  30 + gdb_regs[GDB_FR_D2] = regs->d2;
  31 + gdb_regs[GDB_FR_D3] = regs->d3;
  32 + gdb_regs[GDB_FR_A0] = regs->a0;
  33 + gdb_regs[GDB_FR_A1] = regs->a1;
  34 + gdb_regs[GDB_FR_A2] = regs->a2;
  35 + gdb_regs[GDB_FR_A3] = regs->a3;
  36 + gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp;
  37 + gdb_regs[GDB_FR_PC] = regs->pc;
  38 + gdb_regs[GDB_FR_MDR] = regs->mdr;
  39 + gdb_regs[GDB_FR_EPSW] = regs->epsw;
  40 + gdb_regs[GDB_FR_LIR] = regs->lir;
  41 + gdb_regs[GDB_FR_LAR] = regs->lar;
  42 + gdb_regs[GDB_FR_MDRQ] = regs->mdrq;
  43 + gdb_regs[GDB_FR_E0] = regs->e0;
  44 + gdb_regs[GDB_FR_E1] = regs->e1;
  45 + gdb_regs[GDB_FR_E2] = regs->e2;
  46 + gdb_regs[GDB_FR_E3] = regs->e3;
  47 + gdb_regs[GDB_FR_E4] = regs->e4;
  48 + gdb_regs[GDB_FR_E5] = regs->e5;
  49 + gdb_regs[GDB_FR_E6] = regs->e6;
  50 + gdb_regs[GDB_FR_E7] = regs->e7;
  51 + gdb_regs[GDB_FR_SSP] = ssp;
  52 + gdb_regs[GDB_FR_MSP] = 0;
  53 + gdb_regs[GDB_FR_USP] = regs->sp;
  54 + gdb_regs[GDB_FR_MCRH] = regs->mcrh;
  55 + gdb_regs[GDB_FR_MCRL] = regs->mcrl;
  56 + gdb_regs[GDB_FR_MCVF] = regs->mcvf;
  57 + gdb_regs[GDB_FR_DUMMY0] = 0;
  58 + gdb_regs[GDB_FR_DUMMY1] = 0;
  59 + gdb_regs[GDB_FR_FS0] = 0;
  60 +}
  61 +
  62 +/*
  63 + * Extracts kernel SP/PC values understandable by gdb from the values
  64 + * saved by switch_to().
  65 + */
  66 +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
  67 +{
  68 + gdb_regs[GDB_FR_SSP] = p->thread.sp;
  69 + gdb_regs[GDB_FR_PC] = p->thread.pc;
  70 + gdb_regs[GDB_FR_A3] = p->thread.a3;
  71 + gdb_regs[GDB_FR_USP] = p->thread.usp;
  72 + gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr;
  73 +}
  74 +
  75 +/*
  76 + * Fill kernel exception frame registers from the GDB register file
  77 + */
  78 +void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
  79 +{
  80 + regs->d0 = gdb_regs[GDB_FR_D0];
  81 + regs->d1 = gdb_regs[GDB_FR_D1];
  82 + regs->d2 = gdb_regs[GDB_FR_D2];
  83 + regs->d3 = gdb_regs[GDB_FR_D3];
  84 + regs->a0 = gdb_regs[GDB_FR_A0];
  85 + regs->a1 = gdb_regs[GDB_FR_A1];
  86 + regs->a2 = gdb_regs[GDB_FR_A2];
  87 + regs->a3 = gdb_regs[GDB_FR_A3];
  88 + regs->sp = gdb_regs[GDB_FR_SP];
  89 + regs->pc = gdb_regs[GDB_FR_PC];
  90 + regs->mdr = gdb_regs[GDB_FR_MDR];
  91 + regs->epsw = gdb_regs[GDB_FR_EPSW];
  92 + regs->lir = gdb_regs[GDB_FR_LIR];
  93 + regs->lar = gdb_regs[GDB_FR_LAR];
  94 + regs->mdrq = gdb_regs[GDB_FR_MDRQ];
  95 + regs->e0 = gdb_regs[GDB_FR_E0];
  96 + regs->e1 = gdb_regs[GDB_FR_E1];
  97 + regs->e2 = gdb_regs[GDB_FR_E2];
  98 + regs->e3 = gdb_regs[GDB_FR_E3];
  99 + regs->e4 = gdb_regs[GDB_FR_E4];
  100 + regs->e5 = gdb_regs[GDB_FR_E5];
  101 + regs->e6 = gdb_regs[GDB_FR_E6];
  102 + regs->e7 = gdb_regs[GDB_FR_E7];
  103 + regs->sp = gdb_regs[GDB_FR_SSP];
  104 + /* gdb_regs[GDB_FR_MSP]; */
  105 + // regs->usp = gdb_regs[GDB_FR_USP];
  106 + regs->mcrh = gdb_regs[GDB_FR_MCRH];
  107 + regs->mcrl = gdb_regs[GDB_FR_MCRL];
  108 + regs->mcvf = gdb_regs[GDB_FR_MCVF];
  109 + /* gdb_regs[GDB_FR_DUMMY0]; */
  110 + /* gdb_regs[GDB_FR_DUMMY1]; */
  111 +
  112 + // regs->fpcr = gdb_regs[GDB_FR_FPCR];
  113 + // regs->fs0 = gdb_regs[GDB_FR_FS0];
  114 +}
  115 +
  116 +struct kgdb_arch arch_kgdb_ops = {
  117 + .gdb_bpt_instr = { 0xff },
  118 + .flags = KGDB_HW_BREAKPOINT,
  119 +};
  120 +
  121 +/*
  122 + * Handle unknown packets and [Ccs] packets
  123 + */
  124 +int kgdb_arch_handle_exception(int vector, int signo, int err_code,
  125 + char *remcom_in_buffer, char *remcom_out_buffer,
  126 + struct pt_regs *regs)
  127 +{
  128 + long addr;
  129 + char *ptr;
  130 +
  131 + switch (remcom_in_buffer[0]) {
  132 + case 'c':
  133 + if (kgdb_contthread && kgdb_contthread != current) {
  134 + strcpy(remcom_out_buffer, "E00");
  135 + break;
  136 + }
  137 +
  138 + kgdb_contthread = NULL;
  139 +
  140 + /* try to read optional parameter, pc unchanged if no parm */
  141 + ptr = &remcom_in_buffer[1];
  142 + if (kgdb_hex2long(&ptr, &addr))
  143 + regs->pc = addr;
  144 + return 0;
  145 +
  146 + case 's':
  147 + break; /* we don't do hardware single stepping */
  148 + }
  149 + return -1; /* this means that we do not want to exit from the handler */
  150 +}
  151 +
  152 +/*
  153 + * Handle event interception
  154 + * - returns 0 if the exception should be skipped, -ERROR otherwise.
  155 + */
  156 +int debugger_intercept(enum exception_code excep, int signo, int si_code,
  157 + struct pt_regs *regs)
  158 +{
  159 + int ret;
  160 +
  161 + ret = kgdb_handle_exception(excep, signo, si_code, regs);
  162 +
  163 + debugger_local_cache_flushinv();
  164 +
  165 + return ret;
  166 +}
  167 +
  168 +/*
  169 + * Determine if we've hit a debugger special breakpoint
  170 + */
  171 +int at_debugger_breakpoint(struct pt_regs *regs)
  172 +{
  173 + return regs->pc == (unsigned long)&__arch_kgdb_breakpoint;
  174 +}
  175 +
  176 +/*
  177 + * Initialise kgdb
  178 + */
  179 +int kgdb_arch_init(void)
  180 +{
  181 + return 0;
  182 +}
  183 +
  184 +/*
  185 + * Do something, perhaps, but don't know what.
  186 + */
  187 +void kgdb_arch_exit(void)
  188 +{
  189 +}
  190 +
  191 +#ifdef CONFIG_SMP
  192 +void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code)
  193 +{
  194 + kgdb_nmicallback(arch_smp_processor_id(), regs);
  195 + debugger_local_cache_flushinv();
  196 +}
  197 +
  198 +void kgdb_roundup_cpus(unsigned long flags)
  199 +{
  200 + smp_jump_to_debugger();
  201 +}
  202 +#endif