Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Blackfin arch: kgdb specific code

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>

authored by

Sonic Zhang and committed by
Bryan Wu
474f1a66 1c5d2265

+866 -1
+155
Documentation/blackfin/kgdb.txt
··· 1 + A Simple Guide to Configure KGDB 2 + 3 + Sonic Zhang <sonic.zhang@analog.com> 4 + Aug. 24th 2006 5 + 6 + 7 + This KGDB patch enables the kernel developer to do source level debugging on 8 + the kernel for the Blackfin architecture. The debugging works over either the 9 + ethernet interface or one of the uarts. Both software breakpoints and 10 + hardware breakpoints are supported in this version. 11 + http://docs.blackfin.uclinux.org/doku.php?id=kgdb 12 + 13 + 14 + 2 known issues: 15 + 1. 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. 19 + 2. 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 + 24 + Debug over Ethernet: 25 + 26 + 1. Compile and install the cross platform version of gdb for blackfin, which 27 + can be found at $(BINROOT)/bfin-elf-gdb. 28 + 29 + 2. 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 + 34 + 3. 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 + 37 + 4. Connect minicom to the serial port and boot the kernel image. 38 + 39 + 5. Configure the IP "/> ifconfig eth0 target-IP" 40 + 41 + 6. Start GDB client "bfin-elf-gdb vmlinux". 42 + 43 + 7. Connect to the target "(gdb) target remote udp:target-IP:6443". 44 + 45 + 8. Set software breakpoint "(gdb) break sys_open". 46 + 47 + 9. Continue "(gdb) c". 48 + 49 + 10. Run ls in the target console "/> ls". 50 + 51 + 11. Breakpoint hits. "Breakpoint 1: sys_open(..." 52 + 53 + 12. Display local variables and function paramters. 54 + (*) This operation gives wrong results, see known issue 1. 55 + 56 + 13. Single stepping "(gdb) si". 57 + 58 + 14. Remove breakpoint 1. "(gdb) del 1" 59 + 60 + 15. Set hardware breakpoint "(gdb) hbreak sys_open". 61 + 62 + 16. Continue "(gdb) c". 63 + 64 + 17. Run ls in the target console "/> ls". 65 + 66 + 18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...". 67 + (*) This hardware breakpoint will not be hit, see known issue 2. 68 + 69 + 19. Continue "(gdb) c". 70 + 71 + 20. Interrupt the target in GDB "Ctrl+C". 72 + 73 + 21. Detach from the target "(gdb) detach". 74 + 75 + 22. Exit GDB "(gdb) quit". 76 + 77 + 78 + Debug over the UART: 79 + 80 + 1. Compile and install the cross platform version of gdb for blackfin, which 81 + can be found at $(BINROOT)/bfin-elf-gdb. 82 + 83 + 2. 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 + 88 + 3. 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 + 92 + 4. If you want connect to kgdb when the kernel boots, enable 93 + "KGDB: Wait for gdb connection early" 94 + 95 + 5. Compile kernel. 96 + 97 + 6. Connect minicom to the serial port of the console and boot the kernel image. 98 + 99 + 7. Start GDB client "bfin-elf-gdb vmlinux". 100 + 101 + 8. Set the baud rate in GDB "(gdb) set remotebaud 57600". 102 + 103 + 9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1". 104 + 105 + 10. Set software breakpoint "(gdb) break sys_open". 106 + 107 + 11. Continue "(gdb) c". 108 + 109 + 12. Run ls in the target console "/> ls". 110 + 111 + 13. A breakpoint is hit. "Breakpoint 1: sys_open(..." 112 + 113 + 14. All other operations are the same as that in KGDB over Ethernet. 114 + 115 + 116 + Debug over the same UART as console: 117 + 118 + 1. Compile and install the cross platform version of gdb for blackfin, which 119 + can be found at $(BINROOT)/bfin-elf-gdb. 120 + 121 + 2. 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 + 126 + 3. 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 + 130 + 4. If you want connect to kgdb when the kernel boots, enable 131 + "KGDB: Wait for gdb connection early" 132 + 133 + 5. Connect minicom to the serial port and boot the kernel image. 134 + 135 + 6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A. 136 + 137 + 7. Start GDB client "bfin-elf-gdb vmlinux". 138 + 139 + 8. Set the baud rate in GDB "(gdb) set remotebaud 57600". 140 + 141 + 9. Connect to the target "(gdb) target remote /dev/ttyS0". 142 + 143 + 10. Set software breakpoint "(gdb) break sys_open". 144 + 145 + 11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection. 146 + 147 + 12. Run ls in the target console "/> ls". Dummy string can be seen on the console. 148 + 149 + 13. 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 + 152 + 14. 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.
+1
arch/blackfin/kernel/Makefile
··· 14 14 obj-$(CONFIG_MODULES) += module.o 15 15 obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o 16 16 obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o 17 + obj-$(CONFIG_KGDB) += kgdb.o
+421
arch/blackfin/kernel/kgdb.c
··· 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. */ 50 + int 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). */ 53 + int gdb_bf533vector = -1; 54 + 55 + #if KGDB_MAX_NO_CPUS != 8 56 + #error change the definition of slavecpulocks 57 + #endif 58 + 59 + void 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 + */ 129 + void 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 + 136 + void 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 + 194 + struct 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 + 204 + int kgdb_arch_init(void) 205 + { 206 + kgdb_remove_all_hw_break(); 207 + return 0; 208 + } 209 + 210 + int 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 + 225 + int 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 + 235 + void kgdb_remove_all_hw_break(void) 236 + { 237 + memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8); 238 + } 239 + 240 + /* 241 + void 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 + 249 + void 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 + 347 + void 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 + 354 + void 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 + 361 + int 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 + 418 + struct kgdb_arch arch_kgdb_ops = { 419 + .gdb_bpt_instr = {0xa1}, 420 + .flags = KGDB_HW_BREAKPOINT, 421 + };
+1 -1
drivers/serial/Kconfig
··· 556 556 557 557 config SERIAL_BFIN_DMA 558 558 bool "DMA mode" 559 - depends on DMA_UNCACHED_1M 559 + depends on DMA_UNCACHED_1M && !KGDB_UART 560 560 help 561 561 This driver works under DMA mode. If this option is selected, the 562 562 blackfin simple dma driver is also enabled.
+105
drivers/serial/bfin_5xx.c
··· 41 41 #include <linux/tty_flip.h> 42 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 49 #include <asm/gpio.h> 45 50 #include <asm/mach/bfin_serial_5xx.h> 46 51 ··· 124 119 unsigned short ier; 125 120 126 121 ier = UART_GET_IER(uart); 122 + #ifdef CONFIG_KGDB_UART 123 + if (uart->port.line != CONFIG_KGDB_UART_PORT) 124 + #endif 127 125 ier &= ~ERBFI; 128 126 UART_PUT_IER(uart, ier); 129 127 } ··· 137 129 static void bfin_serial_enable_ms(struct uart_port *port) 138 130 { 139 131 } 132 + 133 + #ifdef CONFIG_KGDB_UART 134 + static int kgdb_entry_state; 135 + 136 + void kgdb_put_debug_char(int chr) 137 + { 138 + struct bfin_serial_port *uart; 139 + 140 + if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS) 141 + uart = &bfin_serial_ports[0]; 142 + else 143 + uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; 144 + 145 + while (!(UART_GET_LSR(uart) & THRE)) { 146 + __builtin_bfin_ssync(); 147 + } 148 + UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); 149 + __builtin_bfin_ssync(); 150 + UART_PUT_CHAR(uart, (unsigned char)chr); 151 + __builtin_bfin_ssync(); 152 + } 153 + 154 + int kgdb_get_debug_char(void) 155 + { 156 + struct bfin_serial_port *uart; 157 + unsigned char chr; 158 + 159 + if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS) 160 + uart = &bfin_serial_ports[0]; 161 + else 162 + uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; 163 + 164 + while(!(UART_GET_LSR(uart) & DR)) { 165 + __builtin_bfin_ssync(); 166 + } 167 + UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); 168 + __builtin_bfin_ssync(); 169 + chr = UART_GET_CHAR(uart); 170 + __builtin_bfin_ssync(); 171 + 172 + return chr; 173 + } 174 + #endif 140 175 141 176 #ifdef CONFIG_SERIAL_BFIN_PIO 142 177 static void local_put_char(struct bfin_serial_port *uart, char ch) ··· 203 152 { 204 153 struct tty_struct *tty = uart->port.info->tty; 205 154 unsigned int status, ch, flg; 155 + #ifdef CONFIG_KGDB_UART 156 + struct pt_regs *regs = get_irq_regs(); 157 + #endif 206 158 #ifdef BF533_FAMILY 207 159 static int in_break = 0; 208 160 #endif ··· 214 160 ch = UART_GET_CHAR(uart); 215 161 uart->port.icount.rx++; 216 162 163 + #ifdef CONFIG_KGDB_UART 164 + if (uart->port.line == CONFIG_KGDB_UART_PORT) { 165 + if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */ 166 + kgdb_breakkey_pressed(regs); 167 + return; 168 + } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */ 169 + kgdb_entry_state = 1; 170 + } else if (kgdb_entry_state == 1 && ch == 'q') { 171 + kgdb_entry_state = 0; 172 + kgdb_breakkey_pressed(regs); 173 + return; 174 + } else if (ch == 0x3) {/* Ctrl + C */ 175 + kgdb_entry_state = 0; 176 + kgdb_breakkey_pressed(regs); 177 + return; 178 + } else { 179 + kgdb_entry_state = 0; 180 + } 181 + } 182 + #endif 183 + 217 184 #ifdef BF533_FAMILY 218 185 /* The BF533 family of processors have a nice misbehavior where 219 186 * they continuously generate characters for a "single" break. ··· 646 571 uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; 647 572 add_timer(&(uart->rx_dma_timer)); 648 573 #else 574 + # ifdef CONFIG_KGDB_UART 575 + if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq 576 + # else 649 577 if (request_irq 578 + # endif 650 579 (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, 651 580 "BFIN_UART_RX", uart)) { 652 581 printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); ··· 680 601 free_dma(uart->rx_dma_channel); 681 602 del_timer(&(uart->rx_dma_timer)); 682 603 #else 604 + #ifdef CONFIG_KGDB_UART 605 + if (uart->port.line != CONFIG_KGDB_UART_PORT) 606 + #endif 683 607 free_irq(uart->port.irq, uart); 684 608 free_irq(uart->port.irq+1, uart); 685 609 #endif ··· 1013 931 { 1014 932 bfin_serial_init_ports(); 1015 933 register_console(&bfin_serial_console); 934 + #ifdef CONFIG_KGDB_UART 935 + kgdb_entry_state = 0; 936 + init_kgdb_uart(); 937 + #endif 1016 938 return 0; 1017 939 } 1018 940 console_initcall(bfin_serial_rs_console_init); ··· 1109 1023 static int __init bfin_serial_init(void) 1110 1024 { 1111 1025 int ret; 1026 + #ifdef CONFIG_KGDB_UART 1027 + struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; 1028 + struct termios t; 1029 + #endif 1112 1030 1113 1031 pr_info("Serial: Blackfin serial driver\n"); 1114 1032 ··· 1126 1036 uart_unregister_driver(&bfin_serial_reg); 1127 1037 } 1128 1038 } 1039 + #ifdef CONFIG_KGDB_UART 1040 + if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) { 1041 + request_irq(uart->port.irq, bfin_serial_int, 1042 + IRQF_DISABLED, "BFIN_UART_RX", uart); 1043 + pr_info("Request irq for kgdb uart port\n"); 1044 + UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); 1045 + __builtin_bfin_ssync(); 1046 + t.c_cflag = CS8|B57600; 1047 + t.c_iflag = 0; 1048 + t.c_oflag = 0; 1049 + t.c_lflag = ICANON; 1050 + t.c_line = CONFIG_KGDB_UART_PORT; 1051 + bfin_serial_set_termios(&uart->port, &t, &t); 1052 + } 1053 + #endif 1129 1054 return ret; 1130 1055 } 1131 1056
+183
include/asm-blackfin/kgdb.h
··· 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 + */ 52 + enum 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 + 181 + extern void kgdb_print(const char *fmt, ...); 182 + 183 + #endif