diff options
Diffstat (limited to 'arch/blackfin/kernel/kgdb.c')
-rw-r--r-- | arch/blackfin/kernel/kgdb.c | 711 |
1 files changed, 553 insertions, 158 deletions
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index a1f9641a6425..b795a207742c 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c | |||
@@ -1,32 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * File: arch/blackfin/kernel/kgdb.c | 2 | * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces |
3 | * Based on: | ||
4 | * Author: Sonic Zhang | ||
5 | * | 3 | * |
6 | * Created: | 4 | * Copyright 2005-2008 Analog Devices Inc. |
7 | * Description: | ||
8 | * | 5 | * |
9 | * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $ | 6 | * Licensed under the GPL-2 or later. |
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 | */ | 7 | */ |
31 | 8 | ||
32 | #include <linux/string.h> | 9 | #include <linux/string.h> |
@@ -39,24 +16,29 @@ | |||
39 | #include <linux/kgdb.h> | 16 | #include <linux/kgdb.h> |
40 | #include <linux/console.h> | 17 | #include <linux/console.h> |
41 | #include <linux/init.h> | 18 | #include <linux/init.h> |
42 | #include <linux/debugger.h> | ||
43 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
44 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/uaccess.h> | ||
45 | #include <asm/system.h> | 22 | #include <asm/system.h> |
46 | #include <asm/traps.h> | 23 | #include <asm/traps.h> |
47 | #include <asm/blackfin.h> | 24 | #include <asm/blackfin.h> |
25 | #include <asm/dma.h> | ||
48 | 26 | ||
49 | /* Put the error code here just in case the user cares. */ | 27 | /* Put the error code here just in case the user cares. */ |
50 | int gdb_bf533errcode; | 28 | int gdb_bfin_errcode; |
51 | /* Likewise, the vector number here (since GDB only gets the signal | 29 | /* Likewise, the vector number here (since GDB only gets the signal |
52 | number through the usual means, and that's not very specific). */ | 30 | number through the usual means, and that's not very specific). */ |
53 | int gdb_bf533vector = -1; | 31 | int gdb_bfin_vector = -1; |
54 | 32 | ||
55 | #if KGDB_MAX_NO_CPUS != 8 | 33 | #if KGDB_MAX_NO_CPUS != 8 |
56 | #error change the definition of slavecpulocks | 34 | #error change the definition of slavecpulocks |
57 | #endif | 35 | #endif |
58 | 36 | ||
59 | void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 37 | #ifdef CONFIG_BFIN_WDT |
38 | # error "Please unselect blackfin watchdog driver before build KGDB." | ||
39 | #endif | ||
40 | |||
41 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
60 | { | 42 | { |
61 | gdb_regs[BFIN_R0] = regs->r0; | 43 | gdb_regs[BFIN_R0] = regs->r0; |
62 | gdb_regs[BFIN_R1] = regs->r1; | 44 | gdb_regs[BFIN_R1] = regs->r1; |
@@ -133,7 +115,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
133 | gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat; | 115 | gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat; |
134 | } | 116 | } |
135 | 117 | ||
136 | void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 118 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
137 | { | 119 | { |
138 | regs->r0 = gdb_regs[BFIN_R0]; | 120 | regs->r0 = gdb_regs[BFIN_R0]; |
139 | regs->r1 = gdb_regs[BFIN_R1]; | 121 | regs->r1 = gdb_regs[BFIN_R1]; |
@@ -199,171 +181,208 @@ struct hw_breakpoint { | |||
199 | unsigned int dataacc:2; | 181 | unsigned int dataacc:2; |
200 | unsigned short count; | 182 | unsigned short count; |
201 | unsigned int addr; | 183 | unsigned int addr; |
202 | } breakinfo[HW_BREAKPOINT_NUM]; | 184 | } breakinfo[HW_WATCHPOINT_NUM]; |
203 | 185 | ||
204 | int kgdb_arch_init(void) | 186 | int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type) |
205 | { | ||
206 | debugger_step = 0; | ||
207 | |||
208 | kgdb_remove_all_hw_break(); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int kgdb_set_hw_break(unsigned long addr) | ||
213 | { | 187 | { |
214 | int breakno; | 188 | int breakno; |
215 | for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) | 189 | int bfin_type; |
216 | if (!breakinfo[breakno].occupied) { | 190 | int dataacc = 0; |
191 | |||
192 | switch (type) { | ||
193 | case BP_HARDWARE_BREAKPOINT: | ||
194 | bfin_type = TYPE_INST_WATCHPOINT; | ||
195 | break; | ||
196 | case BP_WRITE_WATCHPOINT: | ||
197 | dataacc = 1; | ||
198 | bfin_type = TYPE_DATA_WATCHPOINT; | ||
199 | break; | ||
200 | case BP_READ_WATCHPOINT: | ||
201 | dataacc = 2; | ||
202 | bfin_type = TYPE_DATA_WATCHPOINT; | ||
203 | break; | ||
204 | case BP_ACCESS_WATCHPOINT: | ||
205 | dataacc = 3; | ||
206 | bfin_type = TYPE_DATA_WATCHPOINT; | ||
207 | break; | ||
208 | default: | ||
209 | return -ENOSPC; | ||
210 | } | ||
211 | |||
212 | /* Becasue hardware data watchpoint impelemented in current | ||
213 | * Blackfin can not trigger an exception event as the hardware | ||
214 | * instrction watchpoint does, we ignaore all data watch point here. | ||
215 | * They can be turned on easily after future blackfin design | ||
216 | * supports this feature. | ||
217 | */ | ||
218 | for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++) | ||
219 | if (bfin_type == breakinfo[breakno].type | ||
220 | && !breakinfo[breakno].occupied) { | ||
217 | breakinfo[breakno].occupied = 1; | 221 | breakinfo[breakno].occupied = 1; |
218 | breakinfo[breakno].enabled = 1; | 222 | breakinfo[breakno].enabled = 1; |
219 | breakinfo[breakno].type = 1; | ||
220 | breakinfo[breakno].addr = addr; | 223 | breakinfo[breakno].addr = addr; |
224 | breakinfo[breakno].dataacc = dataacc; | ||
225 | breakinfo[breakno].count = 0; | ||
221 | return 0; | 226 | return 0; |
222 | } | 227 | } |
223 | 228 | ||
224 | return -ENOSPC; | 229 | return -ENOSPC; |
225 | } | 230 | } |
226 | 231 | ||
227 | int kgdb_remove_hw_break(unsigned long addr) | 232 | int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type) |
228 | { | 233 | { |
229 | int breakno; | 234 | int breakno; |
230 | for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) | 235 | int bfin_type; |
231 | if (breakinfo[breakno].addr == addr) | 236 | |
232 | memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint)); | 237 | switch (type) { |
238 | case BP_HARDWARE_BREAKPOINT: | ||
239 | bfin_type = TYPE_INST_WATCHPOINT; | ||
240 | break; | ||
241 | case BP_WRITE_WATCHPOINT: | ||
242 | case BP_READ_WATCHPOINT: | ||
243 | case BP_ACCESS_WATCHPOINT: | ||
244 | bfin_type = TYPE_DATA_WATCHPOINT; | ||
245 | break; | ||
246 | default: | ||
247 | return 0; | ||
248 | } | ||
249 | for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) | ||
250 | if (bfin_type == breakinfo[breakno].type | ||
251 | && breakinfo[breakno].occupied | ||
252 | && breakinfo[breakno].addr == addr) { | ||
253 | breakinfo[breakno].occupied = 0; | ||
254 | breakinfo[breakno].enabled = 0; | ||
255 | } | ||
233 | 256 | ||
234 | return 0; | 257 | return 0; |
235 | } | 258 | } |
236 | 259 | ||
237 | void kgdb_remove_all_hw_break(void) | 260 | void bfin_remove_all_hw_break(void) |
238 | { | 261 | { |
239 | memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8); | 262 | int breakno; |
240 | } | ||
241 | 263 | ||
242 | /* | 264 | memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM); |
243 | void kgdb_show_info(void) | 265 | |
244 | { | 266 | for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++) |
245 | printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n", | 267 | breakinfo[breakno].type = TYPE_INST_WATCHPOINT; |
246 | bfin_read_WPIA0(), bfin_read_WPIACNT0(), | 268 | for (; breakno < HW_WATCHPOINT_NUM; breakno++) |
247 | bfin_read_WPIACTL(), bfin_read_WPSTAT()); | 269 | breakinfo[breakno].type = TYPE_DATA_WATCHPOINT; |
248 | } | 270 | } |
249 | */ | ||
250 | 271 | ||
251 | void kgdb_correct_hw_break(void) | 272 | void bfin_correct_hw_break(void) |
252 | { | 273 | { |
253 | int breakno; | 274 | int breakno; |
254 | int correctit; | 275 | unsigned int wpiactl = 0; |
255 | uint32_t wpdactl = bfin_read_WPDACTL(); | 276 | unsigned int wpdactl = 0; |
277 | int enable_wp = 0; | ||
278 | |||
279 | for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) | ||
280 | if (breakinfo[breakno].enabled) { | ||
281 | enable_wp = 1; | ||
256 | 282 | ||
257 | correctit = 0; | ||
258 | for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) { | ||
259 | if (breakinfo[breakno].type == 1) { | ||
260 | switch (breakno) { | 283 | switch (breakno) { |
261 | case 0: | 284 | case 0: |
262 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) { | 285 | wpiactl |= WPIAEN0|WPICNTEN0; |
263 | correctit = 1; | 286 | bfin_write_WPIA0(breakinfo[breakno].addr); |
264 | wpdactl &= ~(WPIREN01|EMUSW0); | 287 | bfin_write_WPIACNT0(breakinfo[breakno].count |
265 | wpdactl |= WPIAEN0|WPICNTEN0; | 288 | + breakinfo->skip); |
266 | bfin_write_WPIA0(breakinfo[breakno].addr); | ||
267 | bfin_write_WPIACNT0(breakinfo[breakno].skip); | ||
268 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) { | ||
269 | correctit = 1; | ||
270 | wpdactl &= ~WPIAEN0; | ||
271 | } | ||
272 | break; | 289 | break; |
273 | |||
274 | case 1: | 290 | case 1: |
275 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) { | 291 | wpiactl |= WPIAEN1|WPICNTEN1; |
276 | correctit = 1; | 292 | bfin_write_WPIA1(breakinfo[breakno].addr); |
277 | wpdactl &= ~(WPIREN01|EMUSW1); | 293 | bfin_write_WPIACNT1(breakinfo[breakno].count |
278 | wpdactl |= WPIAEN1|WPICNTEN1; | 294 | + breakinfo->skip); |
279 | bfin_write_WPIA1(breakinfo[breakno].addr); | ||
280 | bfin_write_WPIACNT1(breakinfo[breakno].skip); | ||
281 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) { | ||
282 | correctit = 1; | ||
283 | wpdactl &= ~WPIAEN1; | ||
284 | } | ||
285 | break; | 295 | break; |
286 | |||
287 | case 2: | 296 | case 2: |
288 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) { | 297 | wpiactl |= WPIAEN2|WPICNTEN2; |
289 | correctit = 1; | 298 | bfin_write_WPIA2(breakinfo[breakno].addr); |
290 | wpdactl &= ~(WPIREN23|EMUSW2); | 299 | bfin_write_WPIACNT2(breakinfo[breakno].count |
291 | wpdactl |= WPIAEN2|WPICNTEN2; | 300 | + breakinfo->skip); |
292 | bfin_write_WPIA2(breakinfo[breakno].addr); | ||
293 | bfin_write_WPIACNT2(breakinfo[breakno].skip); | ||
294 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) { | ||
295 | correctit = 1; | ||
296 | wpdactl &= ~WPIAEN2; | ||
297 | } | ||
298 | break; | 301 | break; |
299 | |||
300 | case 3: | 302 | case 3: |
301 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) { | 303 | wpiactl |= WPIAEN3|WPICNTEN3; |
302 | correctit = 1; | 304 | bfin_write_WPIA3(breakinfo[breakno].addr); |
303 | wpdactl &= ~(WPIREN23|EMUSW3); | 305 | bfin_write_WPIACNT3(breakinfo[breakno].count |
304 | wpdactl |= WPIAEN3|WPICNTEN3; | 306 | + breakinfo->skip); |
305 | bfin_write_WPIA3(breakinfo[breakno].addr); | ||
306 | bfin_write_WPIACNT3(breakinfo[breakno].skip); | ||
307 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) { | ||
308 | correctit = 1; | ||
309 | wpdactl &= ~WPIAEN3; | ||
310 | } | ||
311 | break; | 307 | break; |
312 | case 4: | 308 | case 4: |
313 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) { | 309 | wpiactl |= WPIAEN4|WPICNTEN4; |
314 | correctit = 1; | 310 | bfin_write_WPIA4(breakinfo[breakno].addr); |
315 | wpdactl &= ~(WPIREN45|EMUSW4); | 311 | bfin_write_WPIACNT4(breakinfo[breakno].count |
316 | wpdactl |= WPIAEN4|WPICNTEN4; | 312 | + breakinfo->skip); |
317 | bfin_write_WPIA4(breakinfo[breakno].addr); | ||
318 | bfin_write_WPIACNT4(breakinfo[breakno].skip); | ||
319 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) { | ||
320 | correctit = 1; | ||
321 | wpdactl &= ~WPIAEN4; | ||
322 | } | ||
323 | break; | 313 | break; |
324 | case 5: | 314 | case 5: |
325 | if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) { | 315 | wpiactl |= WPIAEN5|WPICNTEN5; |
326 | correctit = 1; | 316 | bfin_write_WPIA5(breakinfo[breakno].addr); |
327 | wpdactl &= ~(WPIREN45|EMUSW5); | 317 | bfin_write_WPIACNT5(breakinfo[breakno].count |
328 | wpdactl |= WPIAEN5|WPICNTEN5; | 318 | + breakinfo->skip); |
329 | bfin_write_WPIA5(breakinfo[breakno].addr); | 319 | break; |
330 | bfin_write_WPIACNT5(breakinfo[breakno].skip); | 320 | case 6: |
331 | } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) { | 321 | wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0; |
332 | correctit = 1; | 322 | wpdactl |= breakinfo[breakno].dataacc |
333 | wpdactl &= ~WPIAEN5; | 323 | << WPDACC0_OFFSET; |
334 | } | 324 | bfin_write_WPDA0(breakinfo[breakno].addr); |
325 | bfin_write_WPDACNT0(breakinfo[breakno].count | ||
326 | + breakinfo->skip); | ||
327 | break; | ||
328 | case 7: | ||
329 | wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1; | ||
330 | wpdactl |= breakinfo[breakno].dataacc | ||
331 | << WPDACC1_OFFSET; | ||
332 | bfin_write_WPDA1(breakinfo[breakno].addr); | ||
333 | bfin_write_WPDACNT1(breakinfo[breakno].count | ||
334 | + breakinfo->skip); | ||
335 | break; | 335 | break; |
336 | } | 336 | } |
337 | } | 337 | } |
338 | } | 338 | |
339 | if (correctit) { | 339 | /* Should enable WPPWR bit first before set any other |
340 | wpdactl &= ~WPAND; | 340 | * WPIACTL and WPDACTL bits */ |
341 | wpdactl |= WPPWR; | 341 | if (enable_wp) { |
342 | /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/ | 342 | bfin_write_WPIACTL(WPPWR); |
343 | CSYNC(); | ||
344 | bfin_write_WPIACTL(wpiactl|WPPWR); | ||
343 | bfin_write_WPDACTL(wpdactl); | 345 | bfin_write_WPDACTL(wpdactl); |
344 | CSYNC(); | 346 | CSYNC(); |
345 | /*kgdb_show_info();*/ | ||
346 | } | 347 | } |
347 | } | 348 | } |
348 | 349 | ||
349 | void kgdb_disable_hw_debug(struct pt_regs *regs) | 350 | void kgdb_disable_hw_debug(struct pt_regs *regs) |
350 | { | 351 | { |
351 | /* Disable hardware debugging while we are in kgdb */ | 352 | /* Disable hardware debugging while we are in kgdb */ |
352 | bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1); | 353 | bfin_write_WPIACTL(0); |
354 | bfin_write_WPDACTL(0); | ||
353 | CSYNC(); | 355 | CSYNC(); |
354 | } | 356 | } |
355 | 357 | ||
356 | void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code) | 358 | #ifdef CONFIG_SMP |
359 | void kgdb_passive_cpu_callback(void *info) | ||
360 | { | ||
361 | kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); | ||
362 | } | ||
363 | |||
364 | void kgdb_roundup_cpus(unsigned long flags) | ||
365 | { | ||
366 | smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0); | ||
367 | } | ||
368 | |||
369 | void kgdb_roundup_cpu(int cpu, unsigned long flags) | ||
370 | { | ||
371 | smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0); | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code) | ||
357 | { | 376 | { |
358 | /* Master processor is completely in the debugger */ | 377 | /* Master processor is completely in the debugger */ |
359 | gdb_bf533vector = eVector; | 378 | gdb_bfin_vector = eVector; |
360 | gdb_bf533errcode = err_code; | 379 | gdb_bfin_errcode = err_code; |
361 | } | 380 | } |
362 | 381 | ||
363 | int kgdb_arch_handle_exception(int exceptionVector, int signo, | 382 | int kgdb_arch_handle_exception(int vector, int signo, |
364 | int err_code, char *remcom_in_buffer, | 383 | int err_code, char *remcom_in_buffer, |
365 | char *remcom_out_buffer, | 384 | char *remcom_out_buffer, |
366 | struct pt_regs *linux_regs) | 385 | struct pt_regs *regs) |
367 | { | 386 | { |
368 | long addr; | 387 | long addr; |
369 | long breakno; | 388 | long breakno; |
@@ -385,44 +404,40 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo, | |||
385 | /* try to read optional parameter, pc unchanged if no parm */ | 404 | /* try to read optional parameter, pc unchanged if no parm */ |
386 | ptr = &remcom_in_buffer[1]; | 405 | ptr = &remcom_in_buffer[1]; |
387 | if (kgdb_hex2long(&ptr, &addr)) { | 406 | if (kgdb_hex2long(&ptr, &addr)) { |
388 | linux_regs->retx = addr; | 407 | regs->retx = addr; |
389 | } | 408 | } |
390 | newPC = linux_regs->retx; | 409 | newPC = regs->retx; |
391 | 410 | ||
392 | /* clear the trace bit */ | 411 | /* clear the trace bit */ |
393 | linux_regs->syscfg &= 0xfffffffe; | 412 | regs->syscfg &= 0xfffffffe; |
394 | 413 | ||
395 | /* set the trace bit if we're stepping */ | 414 | /* set the trace bit if we're stepping */ |
396 | if (remcom_in_buffer[0] == 's') { | 415 | if (remcom_in_buffer[0] == 's') { |
397 | linux_regs->syscfg |= 0x1; | 416 | regs->syscfg |= 0x1; |
398 | debugger_step = linux_regs->ipend; | 417 | kgdb_single_step = regs->ipend; |
399 | debugger_step >>= 6; | 418 | kgdb_single_step >>= 6; |
400 | for (i = 10; i > 0; i--, debugger_step >>= 1) | 419 | for (i = 10; i > 0; i--, kgdb_single_step >>= 1) |
401 | if (debugger_step & 1) | 420 | if (kgdb_single_step & 1) |
402 | break; | 421 | break; |
403 | /* i indicate event priority of current stopped instruction | 422 | /* i indicate event priority of current stopped instruction |
404 | * user space instruction is 0, IVG15 is 1, IVTMR is 10. | 423 | * user space instruction is 0, IVG15 is 1, IVTMR is 10. |
405 | * debugger_step > 0 means in single step mode | 424 | * kgdb_single_step > 0 means in single step mode |
406 | */ | 425 | */ |
407 | debugger_step = i + 1; | 426 | kgdb_single_step = i + 1; |
408 | } else { | ||
409 | debugger_step = 0; | ||
410 | } | 427 | } |
411 | 428 | ||
412 | wp_status = bfin_read_WPSTAT(); | 429 | if (vector == VEC_WATCH) { |
413 | CSYNC(); | 430 | wp_status = bfin_read_WPSTAT(); |
414 | 431 | for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) { | |
415 | if (exceptionVector == VEC_WATCH) { | ||
416 | for (breakno = 0; breakno < 6; ++breakno) { | ||
417 | if (wp_status & (1 << breakno)) { | 432 | if (wp_status & (1 << breakno)) { |
418 | breakinfo->skip = 1; | 433 | breakinfo->skip = 1; |
419 | break; | 434 | break; |
420 | } | 435 | } |
421 | } | 436 | } |
437 | bfin_write_WPSTAT(0); | ||
422 | } | 438 | } |
423 | kgdb_correct_hw_break(); | ||
424 | 439 | ||
425 | bfin_write_WPSTAT(0); | 440 | bfin_correct_hw_break(); |
426 | 441 | ||
427 | return 0; | 442 | return 0; |
428 | } /* switch */ | 443 | } /* switch */ |
@@ -431,5 +446,385 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo, | |||
431 | 446 | ||
432 | struct kgdb_arch arch_kgdb_ops = { | 447 | struct kgdb_arch arch_kgdb_ops = { |
433 | .gdb_bpt_instr = {0xa1}, | 448 | .gdb_bpt_instr = {0xa1}, |
449 | #ifdef CONFIG_SMP | ||
450 | .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP, | ||
451 | #else | ||
434 | .flags = KGDB_HW_BREAKPOINT, | 452 | .flags = KGDB_HW_BREAKPOINT, |
453 | #endif | ||
454 | .set_hw_breakpoint = bfin_set_hw_break, | ||
455 | .remove_hw_breakpoint = bfin_remove_hw_break, | ||
456 | .remove_all_hw_break = bfin_remove_all_hw_break, | ||
457 | .correct_hw_break = bfin_correct_hw_break, | ||
435 | }; | 458 | }; |
459 | |||
460 | static int hex(char ch) | ||
461 | { | ||
462 | if ((ch >= 'a') && (ch <= 'f')) | ||
463 | return ch - 'a' + 10; | ||
464 | if ((ch >= '0') && (ch <= '9')) | ||
465 | return ch - '0'; | ||
466 | if ((ch >= 'A') && (ch <= 'F')) | ||
467 | return ch - 'A' + 10; | ||
468 | return -1; | ||
469 | } | ||
470 | |||
471 | static int validate_memory_access_address(unsigned long addr, int size) | ||
472 | { | ||
473 | int cpu = raw_smp_processor_id(); | ||
474 | |||
475 | if (size < 0) | ||
476 | return EFAULT; | ||
477 | if (addr >= 0x1000 && (addr + size) <= physical_mem_end) | ||
478 | return 0; | ||
479 | if (addr >= SYSMMR_BASE) | ||
480 | return 0; | ||
481 | if (addr >= ASYNC_BANK0_BASE | ||
482 | && addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) | ||
483 | return 0; | ||
484 | if (cpu == 0) { | ||
485 | if (addr >= L1_SCRATCH_START | ||
486 | && (addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)) | ||
487 | return 0; | ||
488 | #if L1_CODE_LENGTH != 0 | ||
489 | if (addr >= L1_CODE_START | ||
490 | && (addr + size <= L1_CODE_START + L1_CODE_LENGTH)) | ||
491 | return 0; | ||
492 | #endif | ||
493 | #if L1_DATA_A_LENGTH != 0 | ||
494 | if (addr >= L1_DATA_A_START | ||
495 | && (addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)) | ||
496 | return 0; | ||
497 | #endif | ||
498 | #if L1_DATA_B_LENGTH != 0 | ||
499 | if (addr >= L1_DATA_B_START | ||
500 | && (addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)) | ||
501 | return 0; | ||
502 | #endif | ||
503 | #ifdef CONFIG_SMP | ||
504 | } else if (cpu == 1) { | ||
505 | if (addr >= COREB_L1_SCRATCH_START | ||
506 | && (addr + size <= COREB_L1_SCRATCH_START | ||
507 | + L1_SCRATCH_LENGTH)) | ||
508 | return 0; | ||
509 | # if L1_CODE_LENGTH != 0 | ||
510 | if (addr >= COREB_L1_CODE_START | ||
511 | && (addr + size <= COREB_L1_CODE_START + L1_CODE_LENGTH)) | ||
512 | return 0; | ||
513 | # endif | ||
514 | # if L1_DATA_A_LENGTH != 0 | ||
515 | if (addr >= COREB_L1_DATA_A_START | ||
516 | && (addr + size <= COREB_L1_DATA_A_START + L1_DATA_A_LENGTH)) | ||
517 | return 0; | ||
518 | # endif | ||
519 | # if L1_DATA_B_LENGTH != 0 | ||
520 | if (addr >= COREB_L1_DATA_B_START | ||
521 | && (addr + size <= COREB_L1_DATA_B_START + L1_DATA_B_LENGTH)) | ||
522 | return 0; | ||
523 | # endif | ||
524 | #endif | ||
525 | } | ||
526 | |||
527 | #if L2_LENGTH != 0 | ||
528 | if (addr >= L2_START | ||
529 | && addr + size <= L2_START + L2_LENGTH) | ||
530 | return 0; | ||
531 | #endif | ||
532 | |||
533 | return EFAULT; | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | * Convert the memory pointed to by mem into hex, placing result in buf. | ||
538 | * Return a pointer to the last char put in buf (null). May return an error. | ||
539 | */ | ||
540 | int kgdb_mem2hex(char *mem, char *buf, int count) | ||
541 | { | ||
542 | char *tmp; | ||
543 | int err = 0; | ||
544 | unsigned char *pch; | ||
545 | unsigned short mmr16; | ||
546 | unsigned long mmr32; | ||
547 | int cpu = raw_smp_processor_id(); | ||
548 | |||
549 | if (validate_memory_access_address((unsigned long)mem, count)) | ||
550 | return EFAULT; | ||
551 | |||
552 | /* | ||
553 | * We use the upper half of buf as an intermediate buffer for the | ||
554 | * raw memory copy. Hex conversion will work against this one. | ||
555 | */ | ||
556 | tmp = buf + count; | ||
557 | |||
558 | if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ | ||
559 | switch (count) { | ||
560 | case 2: | ||
561 | if ((unsigned int)mem % 2 == 0) { | ||
562 | mmr16 = *(unsigned short *)mem; | ||
563 | pch = (unsigned char *)&mmr16; | ||
564 | *tmp++ = *pch++; | ||
565 | *tmp++ = *pch++; | ||
566 | tmp -= 2; | ||
567 | } else | ||
568 | err = EFAULT; | ||
569 | break; | ||
570 | case 4: | ||
571 | if ((unsigned int)mem % 4 == 0) { | ||
572 | mmr32 = *(unsigned long *)mem; | ||
573 | pch = (unsigned char *)&mmr32; | ||
574 | *tmp++ = *pch++; | ||
575 | *tmp++ = *pch++; | ||
576 | *tmp++ = *pch++; | ||
577 | *tmp++ = *pch++; | ||
578 | tmp -= 4; | ||
579 | } else | ||
580 | err = EFAULT; | ||
581 | break; | ||
582 | default: | ||
583 | err = EFAULT; | ||
584 | } | ||
585 | } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && | ||
586 | (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH | ||
587 | #ifdef CONFIG_SMP | ||
588 | || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && | ||
589 | (unsigned int)(mem + count) <= | ||
590 | COREB_L1_CODE_START + L1_CODE_LENGTH | ||
591 | #endif | ||
592 | ) { | ||
593 | /* access L1 instruction SRAM*/ | ||
594 | if (dma_memcpy(tmp, mem, count) == NULL) | ||
595 | err = EFAULT; | ||
596 | } else | ||
597 | err = probe_kernel_read(tmp, mem, count); | ||
598 | |||
599 | if (!err) { | ||
600 | while (count > 0) { | ||
601 | buf = pack_hex_byte(buf, *tmp); | ||
602 | tmp++; | ||
603 | count--; | ||
604 | } | ||
605 | |||
606 | *buf = 0; | ||
607 | } | ||
608 | |||
609 | return err; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * Copy the binary array pointed to by buf into mem. Fix $, #, and | ||
614 | * 0x7d escaped with 0x7d. Return a pointer to the character after | ||
615 | * the last byte written. | ||
616 | */ | ||
617 | int kgdb_ebin2mem(char *buf, char *mem, int count) | ||
618 | { | ||
619 | char *tmp_old; | ||
620 | char *tmp_new; | ||
621 | unsigned short *mmr16; | ||
622 | unsigned long *mmr32; | ||
623 | int err = 0; | ||
624 | int size = 0; | ||
625 | int cpu = raw_smp_processor_id(); | ||
626 | |||
627 | tmp_old = tmp_new = buf; | ||
628 | |||
629 | while (count-- > 0) { | ||
630 | if (*tmp_old == 0x7d) | ||
631 | *tmp_new = *(++tmp_old) ^ 0x20; | ||
632 | else | ||
633 | *tmp_new = *tmp_old; | ||
634 | tmp_new++; | ||
635 | tmp_old++; | ||
636 | size++; | ||
637 | } | ||
638 | |||
639 | if (validate_memory_access_address((unsigned long)mem, size)) | ||
640 | return EFAULT; | ||
641 | |||
642 | if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ | ||
643 | switch (size) { | ||
644 | case 2: | ||
645 | if ((unsigned int)mem % 2 == 0) { | ||
646 | mmr16 = (unsigned short *)buf; | ||
647 | *(unsigned short *)mem = *mmr16; | ||
648 | } else | ||
649 | return EFAULT; | ||
650 | break; | ||
651 | case 4: | ||
652 | if ((unsigned int)mem % 4 == 0) { | ||
653 | mmr32 = (unsigned long *)buf; | ||
654 | *(unsigned long *)mem = *mmr32; | ||
655 | } else | ||
656 | return EFAULT; | ||
657 | break; | ||
658 | default: | ||
659 | return EFAULT; | ||
660 | } | ||
661 | } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && | ||
662 | (unsigned int)(mem + count) < L1_CODE_START + L1_CODE_LENGTH | ||
663 | #ifdef CONFIG_SMP | ||
664 | || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && | ||
665 | (unsigned int)(mem + count) <= | ||
666 | COREB_L1_CODE_START + L1_CODE_LENGTH | ||
667 | #endif | ||
668 | ) { | ||
669 | /* access L1 instruction SRAM */ | ||
670 | if (dma_memcpy(mem, buf, size) == NULL) | ||
671 | err = EFAULT; | ||
672 | } else | ||
673 | err = probe_kernel_write(mem, buf, size); | ||
674 | |||
675 | return err; | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * Convert the hex array pointed to by buf into binary to be placed in mem. | ||
680 | * Return a pointer to the character AFTER the last byte written. | ||
681 | * May return an error. | ||
682 | */ | ||
683 | int kgdb_hex2mem(char *buf, char *mem, int count) | ||
684 | { | ||
685 | char *tmp_raw; | ||
686 | char *tmp_hex; | ||
687 | unsigned short *mmr16; | ||
688 | unsigned long *mmr32; | ||
689 | int cpu = raw_smp_processor_id(); | ||
690 | |||
691 | if (validate_memory_access_address((unsigned long)mem, count)) | ||
692 | return EFAULT; | ||
693 | |||
694 | /* | ||
695 | * We use the upper half of buf as an intermediate buffer for the | ||
696 | * raw memory that is converted from hex. | ||
697 | */ | ||
698 | tmp_raw = buf + count * 2; | ||
699 | |||
700 | tmp_hex = tmp_raw - 1; | ||
701 | while (tmp_hex >= buf) { | ||
702 | tmp_raw--; | ||
703 | *tmp_raw = hex(*tmp_hex--); | ||
704 | *tmp_raw |= hex(*tmp_hex--) << 4; | ||
705 | } | ||
706 | |||
707 | if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ | ||
708 | switch (count) { | ||
709 | case 2: | ||
710 | if ((unsigned int)mem % 2 == 0) { | ||
711 | mmr16 = (unsigned short *)tmp_raw; | ||
712 | *(unsigned short *)mem = *mmr16; | ||
713 | } else | ||
714 | return EFAULT; | ||
715 | break; | ||
716 | case 4: | ||
717 | if ((unsigned int)mem % 4 == 0) { | ||
718 | mmr32 = (unsigned long *)tmp_raw; | ||
719 | *(unsigned long *)mem = *mmr32; | ||
720 | } else | ||
721 | return EFAULT; | ||
722 | break; | ||
723 | default: | ||
724 | return EFAULT; | ||
725 | } | ||
726 | } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && | ||
727 | (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH | ||
728 | #ifdef CONFIG_SMP | ||
729 | || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && | ||
730 | (unsigned int)(mem + count) <= | ||
731 | COREB_L1_CODE_START + L1_CODE_LENGTH | ||
732 | #endif | ||
733 | ) { | ||
734 | /* access L1 instruction SRAM */ | ||
735 | if (dma_memcpy(mem, tmp_raw, count) == NULL) | ||
736 | return EFAULT; | ||
737 | } else | ||
738 | return probe_kernel_write(mem, tmp_raw, count); | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | int kgdb_validate_break_address(unsigned long addr) | ||
743 | { | ||
744 | int cpu = raw_smp_processor_id(); | ||
745 | |||
746 | if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end) | ||
747 | return 0; | ||
748 | if (addr >= ASYNC_BANK0_BASE | ||
749 | && addr + BREAK_INSTR_SIZE <= ASYNC_BANK3_BASE + ASYNC_BANK3_BASE) | ||
750 | return 0; | ||
751 | #if L1_CODE_LENGTH != 0 | ||
752 | if (cpu == 0 && addr >= L1_CODE_START | ||
753 | && addr + BREAK_INSTR_SIZE <= L1_CODE_START + L1_CODE_LENGTH) | ||
754 | return 0; | ||
755 | # ifdef CONFIG_SMP | ||
756 | else if (cpu == 1 && addr >= COREB_L1_CODE_START | ||
757 | && addr + BREAK_INSTR_SIZE <= COREB_L1_CODE_START + L1_CODE_LENGTH) | ||
758 | return 0; | ||
759 | # endif | ||
760 | #endif | ||
761 | #if L2_LENGTH != 0 | ||
762 | if (addr >= L2_START | ||
763 | && addr + BREAK_INSTR_SIZE <= L2_START + L2_LENGTH) | ||
764 | return 0; | ||
765 | #endif | ||
766 | |||
767 | return EFAULT; | ||
768 | } | ||
769 | |||
770 | int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) | ||
771 | { | ||
772 | int err; | ||
773 | int cpu = raw_smp_processor_id(); | ||
774 | |||
775 | if ((cpu == 0 && (unsigned int)addr >= L1_CODE_START | ||
776 | && (unsigned int)(addr + BREAK_INSTR_SIZE) | ||
777 | < L1_CODE_START + L1_CODE_LENGTH) | ||
778 | #ifdef CONFIG_SMP | ||
779 | || (cpu == 1 && (unsigned int)addr >= COREB_L1_CODE_START | ||
780 | && (unsigned int)(addr + BREAK_INSTR_SIZE) | ||
781 | < COREB_L1_CODE_START + L1_CODE_LENGTH) | ||
782 | #endif | ||
783 | ) { | ||
784 | /* access L1 instruction SRAM */ | ||
785 | if (dma_memcpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE) | ||
786 | == NULL) | ||
787 | return -EFAULT; | ||
788 | |||
789 | if (dma_memcpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr, | ||
790 | BREAK_INSTR_SIZE) == NULL) | ||
791 | return -EFAULT; | ||
792 | |||
793 | return 0; | ||
794 | } else { | ||
795 | err = probe_kernel_read(saved_instr, (char *)addr, | ||
796 | BREAK_INSTR_SIZE); | ||
797 | if (err) | ||
798 | return err; | ||
799 | |||
800 | return probe_kernel_write((char *)addr, | ||
801 | arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) | ||
806 | { | ||
807 | if ((unsigned int)addr >= L1_CODE_START && | ||
808 | (unsigned int)(addr + BREAK_INSTR_SIZE) < | ||
809 | L1_CODE_START + L1_CODE_LENGTH) { | ||
810 | /* access L1 instruction SRAM */ | ||
811 | if (dma_memcpy((void *)addr, bundle, BREAK_INSTR_SIZE) == NULL) | ||
812 | return -EFAULT; | ||
813 | |||
814 | return 0; | ||
815 | } else | ||
816 | return probe_kernel_write((char *)addr, | ||
817 | (char *)bundle, BREAK_INSTR_SIZE); | ||
818 | } | ||
819 | |||
820 | int kgdb_arch_init(void) | ||
821 | { | ||
822 | kgdb_single_step = 0; | ||
823 | |||
824 | bfin_remove_all_hw_break(); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | void kgdb_arch_exit(void) | ||
829 | { | ||
830 | } | ||