aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-03-18 12:54:31 -0400
committerDavid Howells <dhowells@redhat.com>2011-03-18 12:54:31 -0400
commite460d64405c04581e42aa9cbae76815a2d4e9abe (patch)
tree5c3deddaaf6d7883d6d39344b5a00857299f115b /arch/mn10300/kernel
parent67ddb4052daac9d449caf2643ac365d42a04219a (diff)
MN10300: Use KGDB
Diffstat (limited to 'arch/mn10300/kernel')
-rw-r--r--arch/mn10300/kernel/Makefile1
-rw-r--r--arch/mn10300/kernel/kgdb.c202
2 files changed, 203 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
index 48ab4017434d..47ed30fe8178 100644
--- a/arch/mn10300/kernel/Makefile
+++ b/arch/mn10300/kernel/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_MN10300_RTC) += rtc.o
25obj-$(CONFIG_PROFILE) += profile.o profile-low.o 25obj-$(CONFIG_PROFILE) += profile.o profile-low.o
26obj-$(CONFIG_MODULES) += module.o 26obj-$(CONFIG_MODULES) += module.o
27obj-$(CONFIG_KPROBES) += kprobes.o 27obj-$(CONFIG_KPROBES) += kprobes.o
28obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/mn10300/kernel/kgdb.c b/arch/mn10300/kernel/kgdb.c
new file mode 100644
index 000000000000..7d575f553099
--- /dev/null
+++ b/arch/mn10300/kernel/kgdb.c
@@ -0,0 +1,202 @@
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 */
24void 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 */
66void 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 */
78void 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
116struct 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 */
124int 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 */
156int 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 */
171int at_debugger_breakpoint(struct pt_regs *regs)
172{
173 return regs->pc == (unsigned long)&__arch_kgdb_breakpoint;
174}
175
176/*
177 * Initialise kgdb
178 */
179int kgdb_arch_init(void)
180{
181 return 0;
182}
183
184/*
185 * Do something, perhaps, but don't know what.
186 */
187void kgdb_arch_exit(void)
188{
189}
190
191#ifdef CONFIG_SMP
192void 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
198void kgdb_roundup_cpus(unsigned long flags)
199{
200 smp_jump_to_debugger();
201}
202#endif