aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2007-06-29 04:35:17 -0400
committerBryan Wu <bryan.wu@analog.com>2007-06-29 04:35:17 -0400
commit474f1a667d4bd40b6dcacc6870b70f4d2ba4e155 (patch)
tree42814169b151897ae679c543d0bc11aecde80b86
parent1c5d2265a82f8d3fa0471a60ca98072b3c53c299 (diff)
Blackfin arch: kgdb specific code
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
-rw-r--r--Documentation/blackfin/kgdb.txt155
-rw-r--r--arch/blackfin/kernel/Makefile1
-rw-r--r--arch/blackfin/kernel/kgdb.c421
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/bfin_5xx.c105
-rw-r--r--include/asm-blackfin/kgdb.h183
6 files changed, 866 insertions, 1 deletions
diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt
new file mode 100644
index 000000000000..84f6a484ae9a
--- /dev/null
+++ b/Documentation/blackfin/kgdb.txt
@@ -0,0 +1,155 @@
1 A Simple Guide to Configure KGDB
2
3 Sonic Zhang <sonic.zhang@analog.com>
4 Aug. 24th 2006
5
6
7This KGDB patch enables the kernel developer to do source level debugging on
8the kernel for the Blackfin architecture. The debugging works over either the
9ethernet interface or one of the uarts. Both software breakpoints and
10hardware breakpoints are supported in this version.
11http://docs.blackfin.uclinux.org/doku.php?id=kgdb
12
13
142 known issues:
151. This bug:
16 http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145
17 The GDB client for Blackfin uClinux causes incorrect values of local
18 variables to be displayed when the user breaks the running of kernel in GDB.
192. Because of a hardware bug in Blackfin 533 v1.0.3:
20 05000067 - Watchpoints (Hardware Breakpoints) are not supported
21 Hardware breakpoints cannot be set properly.
22
23
24Debug over Ethernet:
25
261. Compile and install the cross platform version of gdb for blackfin, which
27 can be found at $(BINROOT)/bfin-elf-gdb.
28
292. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
30 "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
31 With this selected, option "Full Symbolic/Source Debugging support" and
32 "Compile the kernel with frame pointers" are also selected.
33
343. Select option "KGDB: connect over (Ethernet)". Add "kgdboe=@target-IP/,@host-IP/" to
35 the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking".
36
374. Connect minicom to the serial port and boot the kernel image.
38
395. Configure the IP "/> ifconfig eth0 target-IP"
40
416. Start GDB client "bfin-elf-gdb vmlinux".
42
437. Connect to the target "(gdb) target remote udp:target-IP:6443".
44
458. Set software breakpoint "(gdb) break sys_open".
46
479. Continue "(gdb) c".
48
4910. Run ls in the target console "/> ls".
50
5111. Breakpoint hits. "Breakpoint 1: sys_open(..."
52
5312. Display local variables and function paramters.
54 (*) This operation gives wrong results, see known issue 1.
55
5613. Single stepping "(gdb) si".
57
5814. Remove breakpoint 1. "(gdb) del 1"
59
6015. Set hardware breakpoint "(gdb) hbreak sys_open".
61
6216. Continue "(gdb) c".
63
6417. Run ls in the target console "/> ls".
65
6618. Hardware breakpoint hits. "Breakpoint 1: sys_open(...".
67 (*) This hardware breakpoint will not be hit, see known issue 2.
68
6919. Continue "(gdb) c".
70
7120. Interrupt the target in GDB "Ctrl+C".
72
7321. Detach from the target "(gdb) detach".
74
7522. Exit GDB "(gdb) quit".
76
77
78Debug over the UART:
79
801. Compile and install the cross platform version of gdb for blackfin, which
81 can be found at $(BINROOT)/bfin-elf-gdb.
82
832. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
84 "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
85 With this selected, option "Full Symbolic/Source Debugging support" and
86 "Compile the kernel with frame pointers" are also selected.
87
883. Select option "KGDB: connect over (UART)". Set "KGDB: UART port number" to be
89 a different one from the console. Don't forget to change the mode of
90 blackfin serial driver to PIO. Otherwise kgdb works incorrectly on UART.
91
924. If you want connect to kgdb when the kernel boots, enable
93 "KGDB: Wait for gdb connection early"
94
955. Compile kernel.
96
976. Connect minicom to the serial port of the console and boot the kernel image.
98
997. Start GDB client "bfin-elf-gdb vmlinux".
100
1018. Set the baud rate in GDB "(gdb) set remotebaud 57600".
102
1039. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1".
104
10510. Set software breakpoint "(gdb) break sys_open".
106
10711. Continue "(gdb) c".
108
10912. Run ls in the target console "/> ls".
110
11113. A breakpoint is hit. "Breakpoint 1: sys_open(..."
112
11314. All other operations are the same as that in KGDB over Ethernet.
114
115
116Debug over the same UART as console:
117
1181. Compile and install the cross platform version of gdb for blackfin, which
119 can be found at $(BINROOT)/bfin-elf-gdb.
120
1212. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
122 "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
123 With this selected, option "Full Symbolic/Source Debugging support" and
124 "Compile the kernel with frame pointers" are also selected.
125
1263. Select option "KGDB: connect over UART". Set "KGDB: UART port number" to console.
127 Don't forget to change the mode of blackfin serial driver to PIO.
128 Otherwise kgdb works incorrectly on UART.
129
1304. If you want connect to kgdb when the kernel boots, enable
131 "KGDB: Wait for gdb connection early"
132
1335. Connect minicom to the serial port and boot the kernel image.
134
1356. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A.
136
1377. Start GDB client "bfin-elf-gdb vmlinux".
138
1398. Set the baud rate in GDB "(gdb) set remotebaud 57600".
140
1419. Connect to the target "(gdb) target remote /dev/ttyS0".
142
14310. Set software breakpoint "(gdb) break sys_open".
144
14511. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection.
146
14712. Run ls in the target console "/> ls". Dummy string can be seen on the console.
148
14913. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0".
150 Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..."
151
15214. All other operations are the same as that in KGDB over Ethernet. The only
153 difference is that after continue command in GDB, please stop GDB
154 connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or
155 Ctrl+A is entered.
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index b7b6de824011..6fac57f6ce06 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_BF561) += bfin_gpio.o
14obj-$(CONFIG_MODULES) += module.o 14obj-$(CONFIG_MODULES) += module.o
15obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o 15obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
16obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o 16obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
17obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
new file mode 100644
index 000000000000..a9c15515bfd7
--- /dev/null
+++ b/arch/blackfin/kernel/kgdb.c
@@ -0,0 +1,421 @@
1/*
2 * File: arch/blackfin/kernel/kgdb.c
3 * Based on:
4 * Author: Sonic Zhang
5 *
6 * Created:
7 * Description:
8 *
9 * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
10 *
11 * Modified:
12 * Copyright 2005-2006 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <linux/string.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/smp.h>
36#include <linux/spinlock.h>
37#include <linux/delay.h>
38#include <linux/ptrace.h> /* for linux pt_regs struct */
39#include <linux/kgdb.h>
40#include <linux/console.h>
41#include <linux/init.h>
42#include <linux/debugger.h>
43#include <linux/errno.h>
44#include <linux/irq.h>
45#include <asm/system.h>
46#include <asm/traps.h>
47#include <asm/blackfin.h>
48
49/* Put the error code here just in case the user cares. */
50int gdb_bf533errcode;
51/* Likewise, the vector number here (since GDB only gets the signal
52 number through the usual means, and that's not very specific). */
53int gdb_bf533vector = -1;
54
55#if KGDB_MAX_NO_CPUS != 8
56#error change the definition of slavecpulocks
57#endif
58
59void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
60{
61 gdb_regs[BFIN_R0] = regs->r0;
62 gdb_regs[BFIN_R1] = regs->r1;
63 gdb_regs[BFIN_R2] = regs->r2;
64 gdb_regs[BFIN_R3] = regs->r3;
65 gdb_regs[BFIN_R4] = regs->r4;
66 gdb_regs[BFIN_R5] = regs->r5;
67 gdb_regs[BFIN_R6] = regs->r6;
68 gdb_regs[BFIN_R7] = regs->r7;
69 gdb_regs[BFIN_P0] = regs->p0;
70 gdb_regs[BFIN_P1] = regs->p1;
71 gdb_regs[BFIN_P2] = regs->p2;
72 gdb_regs[BFIN_P3] = regs->p3;
73 gdb_regs[BFIN_P4] = regs->p4;
74 gdb_regs[BFIN_P5] = regs->p5;
75 gdb_regs[BFIN_SP] = regs->reserved;
76 gdb_regs[BFIN_FP] = regs->fp;
77 gdb_regs[BFIN_I0] = regs->i0;
78 gdb_regs[BFIN_I1] = regs->i1;
79 gdb_regs[BFIN_I2] = regs->i2;
80 gdb_regs[BFIN_I3] = regs->i3;
81 gdb_regs[BFIN_M0] = regs->m0;
82 gdb_regs[BFIN_M1] = regs->m1;
83 gdb_regs[BFIN_M2] = regs->m2;
84 gdb_regs[BFIN_M3] = regs->m3;
85 gdb_regs[BFIN_B0] = regs->b0;
86 gdb_regs[BFIN_B1] = regs->b1;
87 gdb_regs[BFIN_B2] = regs->b2;
88 gdb_regs[BFIN_B3] = regs->b3;
89 gdb_regs[BFIN_L0] = regs->l0;
90 gdb_regs[BFIN_L1] = regs->l1;
91 gdb_regs[BFIN_L2] = regs->l2;
92 gdb_regs[BFIN_L3] = regs->l3;
93 gdb_regs[BFIN_A0_DOT_X] = regs->a0x;
94 gdb_regs[BFIN_A0_DOT_W] = regs->a0w;
95 gdb_regs[BFIN_A1_DOT_X] = regs->a1x;
96 gdb_regs[BFIN_A1_DOT_W] = regs->a1w;
97 gdb_regs[BFIN_ASTAT] = regs->astat;
98 gdb_regs[BFIN_RETS] = regs->rets;
99 gdb_regs[BFIN_LC0] = regs->lc0;
100 gdb_regs[BFIN_LT0] = regs->lt0;
101 gdb_regs[BFIN_LB0] = regs->lb0;
102 gdb_regs[BFIN_LC1] = regs->lc1;
103 gdb_regs[BFIN_LT1] = regs->lt1;
104 gdb_regs[BFIN_LB1] = regs->lb1;
105 gdb_regs[BFIN_CYCLES] = 0;
106 gdb_regs[BFIN_CYCLES2] = 0;
107 gdb_regs[BFIN_USP] = regs->usp;
108 gdb_regs[BFIN_SEQSTAT] = regs->seqstat;
109 gdb_regs[BFIN_SYSCFG] = regs->syscfg;
110 gdb_regs[BFIN_RETI] = regs->pc;
111 gdb_regs[BFIN_RETX] = regs->retx;
112 gdb_regs[BFIN_RETN] = regs->retn;
113 gdb_regs[BFIN_RETE] = regs->rete;
114 gdb_regs[BFIN_PC] = regs->pc;
115 gdb_regs[BFIN_CC] = 0;
116 gdb_regs[BFIN_EXTRA1] = 0;
117 gdb_regs[BFIN_EXTRA2] = 0;
118 gdb_regs[BFIN_EXTRA3] = 0;
119 gdb_regs[BFIN_IPEND] = regs->ipend;
120}
121
122/*
123 * Extracts ebp, esp and eip values understandable by gdb from the values
124 * saved by switch_to.
125 * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
126 * prior to entering switch_to is 8 greater then the value that is saved.
127 * If switch_to changes, change following code appropriately.
128 */
129void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
130{
131 gdb_regs[BFIN_SP] = p->thread.ksp;
132 gdb_regs[BFIN_PC] = p->thread.pc;
133 gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
134}
135
136void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
137{
138 regs->r0 = gdb_regs[BFIN_R0];
139 regs->r1 = gdb_regs[BFIN_R1];
140 regs->r2 = gdb_regs[BFIN_R2];
141 regs->r3 = gdb_regs[BFIN_R3];
142 regs->r4 = gdb_regs[BFIN_R4];
143 regs->r5 = gdb_regs[BFIN_R5];
144 regs->r6 = gdb_regs[BFIN_R6];
145 regs->r7 = gdb_regs[BFIN_R7];
146 regs->p0 = gdb_regs[BFIN_P0];
147 regs->p1 = gdb_regs[BFIN_P1];
148 regs->p2 = gdb_regs[BFIN_P2];
149 regs->p3 = gdb_regs[BFIN_P3];
150 regs->p4 = gdb_regs[BFIN_P4];
151 regs->p5 = gdb_regs[BFIN_P5];
152 regs->fp = gdb_regs[BFIN_FP];
153 regs->i0 = gdb_regs[BFIN_I0];
154 regs->i1 = gdb_regs[BFIN_I1];
155 regs->i2 = gdb_regs[BFIN_I2];
156 regs->i3 = gdb_regs[BFIN_I3];
157 regs->m0 = gdb_regs[BFIN_M0];
158 regs->m1 = gdb_regs[BFIN_M1];
159 regs->m2 = gdb_regs[BFIN_M2];
160 regs->m3 = gdb_regs[BFIN_M3];
161 regs->b0 = gdb_regs[BFIN_B0];
162 regs->b1 = gdb_regs[BFIN_B1];
163 regs->b2 = gdb_regs[BFIN_B2];
164 regs->b3 = gdb_regs[BFIN_B3];
165 regs->l0 = gdb_regs[BFIN_L0];
166 regs->l1 = gdb_regs[BFIN_L1];
167 regs->l2 = gdb_regs[BFIN_L2];
168 regs->l3 = gdb_regs[BFIN_L3];
169 regs->a0x = gdb_regs[BFIN_A0_DOT_X];
170 regs->a0w = gdb_regs[BFIN_A0_DOT_W];
171 regs->a1x = gdb_regs[BFIN_A1_DOT_X];
172 regs->a1w = gdb_regs[BFIN_A1_DOT_W];
173 regs->rets = gdb_regs[BFIN_RETS];
174 regs->lc0 = gdb_regs[BFIN_LC0];
175 regs->lt0 = gdb_regs[BFIN_LT0];
176 regs->lb0 = gdb_regs[BFIN_LB0];
177 regs->lc1 = gdb_regs[BFIN_LC1];
178 regs->lt1 = gdb_regs[BFIN_LT1];
179 regs->lb1 = gdb_regs[BFIN_LB1];
180 regs->usp = gdb_regs[BFIN_USP];
181 regs->syscfg = gdb_regs[BFIN_SYSCFG];
182 regs->retx = gdb_regs[BFIN_PC];
183 regs->retn = gdb_regs[BFIN_RETN];
184 regs->rete = gdb_regs[BFIN_RETE];
185 regs->pc = gdb_regs[BFIN_PC];
186
187#if 0 /* can't change these */
188 regs->astat = gdb_regs[BFIN_ASTAT];
189 regs->seqstat = gdb_regs[BFIN_SEQSTAT];
190 regs->ipend = gdb_regs[BFIN_IPEND];
191#endif
192}
193
194struct hw_breakpoint {
195 unsigned int occupied:1;
196 unsigned int skip:1;
197 unsigned int enabled:1;
198 unsigned int type:1;
199 unsigned int dataacc:2;
200 unsigned short count;
201 unsigned int addr;
202} breakinfo[HW_BREAKPOINT_NUM];
203
204int kgdb_arch_init(void)
205{
206 kgdb_remove_all_hw_break();
207 return 0;
208}
209
210int kgdb_set_hw_break(unsigned long addr)
211{
212 int breakno;
213 for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
214 if (!breakinfo[breakno].occupied) {
215 breakinfo[breakno].occupied = 1;
216 breakinfo[breakno].enabled = 1;
217 breakinfo[breakno].type = 1;
218 breakinfo[breakno].addr = addr;
219 return 0;
220 }
221
222 return -ENOSPC;
223}
224
225int kgdb_remove_hw_break(unsigned long addr)
226{
227 int breakno;
228 for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
229 if (breakinfo[breakno].addr == addr)
230 memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
231
232 return 0;
233}
234
235void kgdb_remove_all_hw_break(void)
236{
237 memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
238}
239
240/*
241void kgdb_show_info(void)
242{
243 printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
244 bfin_read_WPIA0(), bfin_read_WPIACNT0(),
245 bfin_read_WPIACTL(), bfin_read_WPSTAT());
246}
247*/
248
249void kgdb_correct_hw_break(void)
250{
251 int breakno;
252 int correctit;
253 uint32_t wpdactl = bfin_read_WPDACTL();
254
255 correctit = 0;
256 for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
257 if (breakinfo[breakno].type == 1) {
258 switch (breakno) {
259 case 0:
260 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
261 correctit = 1;
262 wpdactl &= ~(WPIREN01|EMUSW0);
263 wpdactl |= WPIAEN0|WPICNTEN0;
264 bfin_write_WPIA0(breakinfo[breakno].addr);
265 bfin_write_WPIACNT0(breakinfo[breakno].skip);
266 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
267 correctit = 1;
268 wpdactl &= ~WPIAEN0;
269 }
270 break;
271
272 case 1:
273 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
274 correctit = 1;
275 wpdactl &= ~(WPIREN01|EMUSW1);
276 wpdactl |= WPIAEN1|WPICNTEN1;
277 bfin_write_WPIA1(breakinfo[breakno].addr);
278 bfin_write_WPIACNT1(breakinfo[breakno].skip);
279 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
280 correctit = 1;
281 wpdactl &= ~WPIAEN1;
282 }
283 break;
284
285 case 2:
286 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
287 correctit = 1;
288 wpdactl &= ~(WPIREN23|EMUSW2);
289 wpdactl |= WPIAEN2|WPICNTEN2;
290 bfin_write_WPIA2(breakinfo[breakno].addr);
291 bfin_write_WPIACNT2(breakinfo[breakno].skip);
292 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
293 correctit = 1;
294 wpdactl &= ~WPIAEN2;
295 }
296 break;
297
298 case 3:
299 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
300 correctit = 1;
301 wpdactl &= ~(WPIREN23|EMUSW3);
302 wpdactl |= WPIAEN3|WPICNTEN3;
303 bfin_write_WPIA3(breakinfo[breakno].addr);
304 bfin_write_WPIACNT3(breakinfo[breakno].skip);
305 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
306 correctit = 1;
307 wpdactl &= ~WPIAEN3;
308 }
309 break;
310 case 4:
311 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
312 correctit = 1;
313 wpdactl &= ~(WPIREN45|EMUSW4);
314 wpdactl |= WPIAEN4|WPICNTEN4;
315 bfin_write_WPIA4(breakinfo[breakno].addr);
316 bfin_write_WPIACNT4(breakinfo[breakno].skip);
317 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
318 correctit = 1;
319 wpdactl &= ~WPIAEN4;
320 }
321 break;
322 case 5:
323 if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
324 correctit = 1;
325 wpdactl &= ~(WPIREN45|EMUSW5);
326 wpdactl |= WPIAEN5|WPICNTEN5;
327 bfin_write_WPIA5(breakinfo[breakno].addr);
328 bfin_write_WPIACNT5(breakinfo[breakno].skip);
329 } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
330 correctit = 1;
331 wpdactl &= ~WPIAEN5;
332 }
333 break;
334 }
335 }
336 }
337 if (correctit) {
338 wpdactl &= ~WPAND;
339 wpdactl |= WPPWR;
340 /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
341 bfin_write_WPDACTL(wpdactl);
342 CSYNC();
343 /*kgdb_show_info();*/
344 }
345}
346
347void kgdb_disable_hw_debug(struct pt_regs *regs)
348{
349 /* Disable hardware debugging while we are in kgdb */
350 bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
351 CSYNC();
352}
353
354void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
355{
356 /* Master processor is completely in the debugger */
357 gdb_bf533vector = eVector;
358 gdb_bf533errcode = err_code;
359}
360
361int kgdb_arch_handle_exception(int exceptionVector, int signo,
362 int err_code, char *remcom_in_buffer,
363 char *remcom_out_buffer,
364 struct pt_regs *linux_regs)
365{
366 long addr;
367 long breakno;
368 char *ptr;
369 int newPC;
370 int wp_status;
371
372 switch (remcom_in_buffer[0]) {
373 case 'c':
374 case 's':
375 if (kgdb_contthread && kgdb_contthread != current) {
376 strcpy(remcom_out_buffer, "E00");
377 break;
378 }
379
380 kgdb_contthread = NULL;
381
382 /* try to read optional parameter, pc unchanged if no parm */
383 ptr = &remcom_in_buffer[1];
384 if (kgdb_hex2long(&ptr, &addr)) {
385 linux_regs->retx = addr;
386 }
387 newPC = linux_regs->retx;
388
389 /* clear the trace bit */
390 linux_regs->syscfg &= 0xfffffffe;
391
392 /* set the trace bit if we're stepping */
393 if (remcom_in_buffer[0] == 's') {
394 linux_regs->syscfg |= 0x1;
395 debugger_step = 1;
396 }
397
398 wp_status = bfin_read_WPSTAT();
399 CSYNC();
400
401 if (exceptionVector == VEC_WATCH) {
402 for (breakno = 0; breakno < 6; ++breakno) {
403 if (wp_status & (1 << breakno)) {
404 breakinfo->skip = 1;
405 break;
406 }
407 }
408 }
409 kgdb_correct_hw_break();
410
411 bfin_write_WPSTAT(0);
412
413 return 0;
414 } /* switch */
415 return -1; /* this means that we do not want to exit from the handler */
416}
417
418struct kgdb_arch arch_kgdb_ops = {
419 .gdb_bpt_instr = {0xa1},
420 .flags = KGDB_HW_BREAKPOINT,
421};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 315ea9916456..71a4ac53a7ef 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -556,7 +556,7 @@ choice
556 556
557config SERIAL_BFIN_DMA 557config SERIAL_BFIN_DMA
558 bool "DMA mode" 558 bool "DMA mode"
559 depends on DMA_UNCACHED_1M 559 depends on DMA_UNCACHED_1M && !KGDB_UART
560 help 560 help
561 This driver works under DMA mode. If this option is selected, the 561 This driver works under DMA mode. If this option is selected, the
562 blackfin simple dma driver is also enabled. 562 blackfin simple dma driver is also enabled.
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 22569bd5d821..f7926dc7fa78 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -41,6 +41,11 @@
41#include <linux/tty_flip.h> 41#include <linux/tty_flip.h>
42#include <linux/serial_core.h> 42#include <linux/serial_core.h>
43 43
44#ifdef CONFIG_KGDB_UART
45#include <linux/kgdb.h>
46#include <asm/irq_regs.h>
47#endif
48
44#include <asm/gpio.h> 49#include <asm/gpio.h>
45#include <asm/mach/bfin_serial_5xx.h> 50#include <asm/mach/bfin_serial_5xx.h>
46 51
@@ -119,6 +124,9 @@ static void bfin_serial_stop_rx(struct uart_port *port)
119 unsigned short ier; 124 unsigned short ier;
120 125
121 ier = UART_GET_IER(uart); 126 ier = UART_GET_IER(uart);
127#ifdef CONFIG_KGDB_UART
128 if (uart->port.line != CONFIG_KGDB_UART_PORT)
129#endif
122 ier &= ~ERBFI; 130 ier &= ~ERBFI;
123 UART_PUT_IER(uart, ier); 131 UART_PUT_IER(uart, ier);
124} 132}
@@ -130,6 +138,49 @@ static void bfin_serial_enable_ms(struct uart_port *port)
130{ 138{
131} 139}
132 140
141#ifdef CONFIG_KGDB_UART
142static int kgdb_entry_state;
143
144void kgdb_put_debug_char(int chr)
145{
146 struct bfin_serial_port *uart;
147
148 if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
149 uart = &bfin_serial_ports[0];
150 else
151 uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
152
153 while (!(UART_GET_LSR(uart) & THRE)) {
154 __builtin_bfin_ssync();
155 }
156 UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
157 __builtin_bfin_ssync();
158 UART_PUT_CHAR(uart, (unsigned char)chr);
159 __builtin_bfin_ssync();
160}
161
162int kgdb_get_debug_char(void)
163{
164 struct bfin_serial_port *uart;
165 unsigned char chr;
166
167 if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
168 uart = &bfin_serial_ports[0];
169 else
170 uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
171
172 while(!(UART_GET_LSR(uart) & DR)) {
173 __builtin_bfin_ssync();
174 }
175 UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
176 __builtin_bfin_ssync();
177 chr = UART_GET_CHAR(uart);
178 __builtin_bfin_ssync();
179
180 return chr;
181}
182#endif
183
133#ifdef CONFIG_SERIAL_BFIN_PIO 184#ifdef CONFIG_SERIAL_BFIN_PIO
134static void local_put_char(struct bfin_serial_port *uart, char ch) 185static void local_put_char(struct bfin_serial_port *uart, char ch)
135{ 186{
@@ -152,6 +203,9 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
152{ 203{
153 struct tty_struct *tty = uart->port.info->tty; 204 struct tty_struct *tty = uart->port.info->tty;
154 unsigned int status, ch, flg; 205 unsigned int status, ch, flg;
206#ifdef CONFIG_KGDB_UART
207 struct pt_regs *regs = get_irq_regs();
208#endif
155#ifdef BF533_FAMILY 209#ifdef BF533_FAMILY
156 static int in_break = 0; 210 static int in_break = 0;
157#endif 211#endif
@@ -160,6 +214,27 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
160 ch = UART_GET_CHAR(uart); 214 ch = UART_GET_CHAR(uart);
161 uart->port.icount.rx++; 215 uart->port.icount.rx++;
162 216
217#ifdef CONFIG_KGDB_UART
218 if (uart->port.line == CONFIG_KGDB_UART_PORT) {
219 if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
220 kgdb_breakkey_pressed(regs);
221 return;
222 } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
223 kgdb_entry_state = 1;
224 } else if (kgdb_entry_state == 1 && ch == 'q') {
225 kgdb_entry_state = 0;
226 kgdb_breakkey_pressed(regs);
227 return;
228 } else if (ch == 0x3) {/* Ctrl + C */
229 kgdb_entry_state = 0;
230 kgdb_breakkey_pressed(regs);
231 return;
232 } else {
233 kgdb_entry_state = 0;
234 }
235 }
236#endif
237
163#ifdef BF533_FAMILY 238#ifdef BF533_FAMILY
164 /* The BF533 family of processors have a nice misbehavior where 239 /* The BF533 family of processors have a nice misbehavior where
165 * they continuously generate characters for a "single" break. 240 * they continuously generate characters for a "single" break.
@@ -571,7 +646,11 @@ static int bfin_serial_startup(struct uart_port *port)
571 uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; 646 uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
572 add_timer(&(uart->rx_dma_timer)); 647 add_timer(&(uart->rx_dma_timer));
573#else 648#else
649# ifdef CONFIG_KGDB_UART
650 if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq
651# else
574 if (request_irq 652 if (request_irq
653# endif
575 (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, 654 (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
576 "BFIN_UART_RX", uart)) { 655 "BFIN_UART_RX", uart)) {
577 printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); 656 printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
@@ -601,6 +680,9 @@ static void bfin_serial_shutdown(struct uart_port *port)
601 free_dma(uart->rx_dma_channel); 680 free_dma(uart->rx_dma_channel);
602 del_timer(&(uart->rx_dma_timer)); 681 del_timer(&(uart->rx_dma_timer));
603#else 682#else
683#ifdef CONFIG_KGDB_UART
684 if (uart->port.line != CONFIG_KGDB_UART_PORT)
685#endif
604 free_irq(uart->port.irq, uart); 686 free_irq(uart->port.irq, uart);
605 free_irq(uart->port.irq+1, uart); 687 free_irq(uart->port.irq+1, uart);
606#endif 688#endif
@@ -931,6 +1013,10 @@ static int __init bfin_serial_rs_console_init(void)
931{ 1013{
932 bfin_serial_init_ports(); 1014 bfin_serial_init_ports();
933 register_console(&bfin_serial_console); 1015 register_console(&bfin_serial_console);
1016#ifdef CONFIG_KGDB_UART
1017 kgdb_entry_state = 0;
1018 init_kgdb_uart();
1019#endif
934 return 0; 1020 return 0;
935} 1021}
936console_initcall(bfin_serial_rs_console_init); 1022console_initcall(bfin_serial_rs_console_init);
@@ -1023,6 +1109,10 @@ static struct platform_driver bfin_serial_driver = {
1023static int __init bfin_serial_init(void) 1109static int __init bfin_serial_init(void)
1024{ 1110{
1025 int ret; 1111 int ret;
1112#ifdef CONFIG_KGDB_UART
1113 struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
1114 struct termios t;
1115#endif
1026 1116
1027 pr_info("Serial: Blackfin serial driver\n"); 1117 pr_info("Serial: Blackfin serial driver\n");
1028 1118
@@ -1036,6 +1126,21 @@ static int __init bfin_serial_init(void)
1036 uart_unregister_driver(&bfin_serial_reg); 1126 uart_unregister_driver(&bfin_serial_reg);
1037 } 1127 }
1038 } 1128 }
1129#ifdef CONFIG_KGDB_UART
1130 if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
1131 request_irq(uart->port.irq, bfin_serial_int,
1132 IRQF_DISABLED, "BFIN_UART_RX", uart);
1133 pr_info("Request irq for kgdb uart port\n");
1134 UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
1135 __builtin_bfin_ssync();
1136 t.c_cflag = CS8|B57600;
1137 t.c_iflag = 0;
1138 t.c_oflag = 0;
1139 t.c_lflag = ICANON;
1140 t.c_line = CONFIG_KGDB_UART_PORT;
1141 bfin_serial_set_termios(&uart->port, &t, &t);
1142 }
1143#endif
1039 return ret; 1144 return ret;
1040} 1145}
1041 1146
diff --git a/include/asm-blackfin/kgdb.h b/include/asm-blackfin/kgdb.h
new file mode 100644
index 000000000000..532bd9052004
--- /dev/null
+++ b/include/asm-blackfin/kgdb.h
@@ -0,0 +1,183 @@
1/*
2 * File: include/asm-blackfin/kgdb.h
3 * Based on:
4 * Author: Sonic Zhang
5 *
6 * Created:
7 * Description:
8 *
9 * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
10 *
11 * Modified:
12 * Copyright 2005-2006 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#ifndef __ASM_BLACKFIN_KGDB_H__
33#define __ASM_BLACKFIN_KGDB_H__
34
35#include <linux/ptrace.h>
36
37/* gdb locks */
38#define KGDB_MAX_NO_CPUS 8
39
40/************************************************************************/
41/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
42/* at least NUMREGBYTES*2 are needed for register packets */
43/* Longer buffer is needed to list all threads */
44#define BUFMAX 2048
45
46/*
47 * Note that this register image is different from
48 * the register image that Linux produces at interrupt time.
49 *
50 * Linux's register image is defined by struct pt_regs in ptrace.h.
51 */
52enum regnames {
53 /* Core Registers */
54 BFIN_R0 = 0,
55 BFIN_R1,
56 BFIN_R2,
57 BFIN_R3,
58 BFIN_R4,
59 BFIN_R5,
60 BFIN_R6,
61 BFIN_R7,
62 BFIN_P0,
63 BFIN_P1,
64 BFIN_P2,
65 BFIN_P3,
66 BFIN_P4,
67 BFIN_P5,
68 BFIN_SP,
69 BFIN_FP,
70 BFIN_I0,
71 BFIN_I1,
72 BFIN_I2,
73 BFIN_I3,
74 BFIN_M0,
75 BFIN_M1,
76 BFIN_M2,
77 BFIN_M3,
78 BFIN_B0,
79 BFIN_B1,
80 BFIN_B2,
81 BFIN_B3,
82 BFIN_L0,
83 BFIN_L1,
84 BFIN_L2,
85 BFIN_L3,
86 BFIN_A0_DOT_X,
87 BFIN_A0_DOT_W,
88 BFIN_A1_DOT_X,
89 BFIN_A1_DOT_W,
90 BFIN_ASTAT,
91 BFIN_RETS,
92 BFIN_LC0,
93 BFIN_LT0,
94 BFIN_LB0,
95 BFIN_LC1,
96 BFIN_LT1,
97 BFIN_LB1,
98 BFIN_CYCLES,
99 BFIN_CYCLES2,
100 BFIN_USP,
101 BFIN_SEQSTAT,
102 BFIN_SYSCFG,
103 BFIN_RETI,
104 BFIN_RETX,
105 BFIN_RETN,
106 BFIN_RETE,
107
108 /* Pseudo Registers */
109 BFIN_PC,
110 BFIN_CC,
111 BFIN_EXTRA1, /* Address of .text section. */
112 BFIN_EXTRA2, /* Address of .data section. */
113 BFIN_EXTRA3, /* Address of .bss section. */
114 BFIN_FDPIC_EXEC,
115 BFIN_FDPIC_INTERP,
116
117 /* MMRs */
118 BFIN_IPEND,
119
120 /* LAST ENTRY SHOULD NOT BE CHANGED. */
121 BFIN_NUM_REGS /* The number of all registers. */
122};
123
124/* Number of bytes of registers. */
125#define NUMREGBYTES BFIN_NUM_REGS*4
126
127#define BREAKPOINT() asm(" EXCPT 2;");
128#define BREAK_INSTR_SIZE 2
129#define HW_BREAKPOINT_NUM 6
130
131/* Instruction watchpoint address control register bits mask */
132#define WPPWR 0x1
133#define WPIREN01 0x2
134#define WPIRINV01 0x4
135#define WPIAEN0 0x8
136#define WPIAEN1 0x10
137#define WPICNTEN0 0x20
138#define WPICNTEN1 0x40
139#define EMUSW0 0x80
140#define EMUSW1 0x100
141#define WPIREN23 0x200
142#define WPIRINV23 0x400
143#define WPIAEN2 0x800
144#define WPIAEN3 0x1000
145#define WPICNTEN2 0x2000
146#define WPICNTEN3 0x4000
147#define EMUSW2 0x8000
148#define EMUSW3 0x10000
149#define WPIREN45 0x20000
150#define WPIRINV45 0x40000
151#define WPIAEN4 0x80000
152#define WPIAEN5 0x100000
153#define WPICNTEN4 0x200000
154#define WPICNTEN5 0x400000
155#define EMUSW4 0x800000
156#define EMUSW5 0x1000000
157#define WPAND 0x2000000
158
159/* Data watchpoint address control register bits mask */
160#define WPDREN01 0x1
161#define WPDRINV01 0x2
162#define WPDAEN0 0x4
163#define WPDAEN1 0x8
164#define WPDCNTEN0 0x10
165#define WPDCNTEN1 0x20
166#define WPDSRC0 0xc0
167#define WPDACC0 0x300
168#define WPDSRC1 0xc00
169#define WPDACC1 0x3000
170
171/* Watchpoint status register bits mask */
172#define STATIA0 0x1
173#define STATIA1 0x2
174#define STATIA2 0x4
175#define STATIA3 0x8
176#define STATIA4 0x10
177#define STATIA5 0x20
178#define STATDA0 0x40
179#define STATDA1 0x80
180
181extern void kgdb_print(const char *fmt, ...);
182
183#endif