ARM: core DPM support for watchpoints
[openocd.git] / src / target / arm_dpm.c
1 /*
2 * Copyright (C) 2009 by David Brownell
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "armv4_5.h" /* REVISIT to become arm.h */
25 #include "arm_dpm.h"
26 #include "jtag.h"
27 #include "register.h"
28 #include "breakpoints.h"
29 #include "target_type.h"
30
31
32 /**
33 * @file
34 * Implements various ARM DPM operations using architectural debug registers.
35 * These routines layer over core-specific communication methods to cope with
36 * implementation differences between cores like ARM1136 and Cortex-A8.
37 */
38
39 /*----------------------------------------------------------------------*/
40
41 /*
42 * Coprocessor support
43 */
44
45 /* Read coprocessor */
46 static int dpm_mrc(struct target *target, int cpnum,
47 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
48 uint32_t *value)
49 {
50 struct arm *arm = target_to_arm(target);
51 struct arm_dpm *dpm = arm->dpm;
52 int retval;
53
54 retval = dpm->prepare(dpm);
55 if (retval != ERROR_OK)
56 return retval;
57
58 LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, op1, CRn, CRm, op2);
59
60 /* read coprocessor register into R0; return via DCC */
61 retval = dpm->instr_read_data_r0(dpm,
62 ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2),
63 value);
64
65 /* (void) */ dpm->finish(dpm);
66 return retval;
67 }
68
69 static int dpm_mcr(struct target *target, int cpnum,
70 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
71 uint32_t value)
72 {
73 struct arm *arm = target_to_arm(target);
74 struct arm_dpm *dpm = arm->dpm;
75 int retval;
76
77 retval = dpm->prepare(dpm);
78 if (retval != ERROR_OK)
79 return retval;
80
81 LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, op1, CRn, CRm, op2);
82
83 /* read DCC into r0; then write coprocessor register from R0 */
84 retval = dpm->instr_write_data_r0(dpm,
85 ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
86 value);
87
88 /* (void) */ dpm->finish(dpm);
89 return retval;
90 }
91
92 /*----------------------------------------------------------------------*/
93
94 /*
95 * Register access utilities
96 */
97
98 /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
99 * Routines *must* restore the original mode before returning!!
100 */
101 static int dpm_modeswitch(struct arm_dpm *dpm, enum armv4_5_mode mode)
102 {
103 int retval;
104 uint32_t cpsr;
105
106 /* restore previous mode */
107 if (mode == ARMV4_5_MODE_ANY)
108 cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32);
109
110 /* else force to the specified mode */
111 else
112 cpsr = mode;
113
114 retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, 0), cpsr);
115
116 if (dpm->instr_cpsr_sync)
117 retval = dpm->instr_cpsr_sync(dpm);
118
119 return retval;
120 }
121
122 /* just read the register -- rely on the core mode being right */
123 static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
124 {
125 uint32_t value;
126 int retval;
127
128 switch (regnum) {
129 case 0 ... 14:
130 /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
131 retval = dpm->instr_read_data_dcc(dpm,
132 ARMV4_5_MCR(14, 0, regnum, 0, 5, 0),
133 &value);
134 break;
135 case 15: /* PC */
136 /* "MOV r0, pc"; then return via DCC */
137 retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value);
138
139 /* NOTE: this seems like a slightly awkward place to update
140 * this value ... but if the PC gets written (the only way
141 * to change what we compute), the arch spec says subsequent
142 * reads return values which are "unpredictable". So this
143 * is always right except in those broken-by-intent cases.
144 */
145 switch (dpm->arm->core_state) {
146 case ARMV4_5_STATE_ARM:
147 value -= 8;
148 break;
149 case ARMV4_5_STATE_THUMB:
150 case ARM_STATE_THUMB_EE:
151 value -= 4;
152 break;
153 case ARMV4_5_STATE_JAZELLE:
154 /* core-specific ... ? */
155 LOG_WARNING("Jazelle PC adjustment unknown");
156 break;
157 }
158 break;
159 default:
160 /* 16: "MRS r0, CPSR"; then return via DCC
161 * 17: "MRS r0, SPSR"; then return via DCC
162 */
163 retval = dpm->instr_read_data_r0(dpm,
164 ARMV4_5_MRS(0, regnum & 1),
165 &value);
166 break;
167 }
168
169 if (retval == ERROR_OK) {
170 buf_set_u32(r->value, 0, 32, value);
171 r->valid = true;
172 r->dirty = false;
173 LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value);
174 }
175
176 return retval;
177 }
178
179 /* just write the register -- rely on the core mode being right */
180 static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
181 {
182 int retval;
183 uint32_t value = buf_get_u32(r->value, 0, 32);
184
185 switch (regnum) {
186 case 0 ... 14:
187 /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */
188 retval = dpm->instr_write_data_dcc(dpm,
189 ARMV4_5_MRC(14, 0, regnum, 0, 5, 0),
190 value);
191 break;
192 case 15: /* PC */
193 /* read r0 from DCC; then "MOV pc, r0" */
194 retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
195 break;
196 default:
197 /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
198 * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
199 */
200 retval = dpm->instr_write_data_r0(dpm,
201 ARMV4_5_MSR_GP(0, 0xf, regnum & 1),
202 value);
203
204 if (regnum == 16 && dpm->instr_cpsr_sync)
205 retval = dpm->instr_cpsr_sync(dpm);
206
207 break;
208 }
209
210 if (retval == ERROR_OK) {
211 r->dirty = false;
212 LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value);
213 }
214
215 return retval;
216 }
217
218 /**
219 * Read basic registers of the the current context: R0 to R15, and CPSR;
220 * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
221 * In normal operation this is called on entry to halting debug state,
222 * possibly after some other operations supporting restore of debug state
223 * or making sure the CPU is fully idle (drain write buffer, etc).
224 */
225 int arm_dpm_read_current_registers(struct arm_dpm *dpm)
226 {
227 struct arm *arm = dpm->arm;
228 uint32_t cpsr;
229 int retval;
230 struct reg *r;
231
232 retval = dpm->prepare(dpm);
233 if (retval != ERROR_OK)
234 return retval;
235
236 /* read R0 first (it's used for scratch), then CPSR */
237 r = arm->core_cache->reg_list + 0;
238 if (!r->valid) {
239 retval = dpm_read_reg(dpm, r, 0);
240 if (retval != ERROR_OK)
241 goto fail;
242 }
243 r->dirty = true;
244
245 retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
246 if (retval != ERROR_OK)
247 goto fail;
248
249 /* update core mode and state, plus shadow mapping for R8..R14 */
250 arm_set_cpsr(arm, cpsr);
251
252 /* REVISIT we can probably avoid reading R1..R14, saving time... */
253 for (unsigned i = 1; i < 16; i++) {
254 r = arm_reg_current(arm, i);
255 if (r->valid)
256 continue;
257
258 retval = dpm_read_reg(dpm, r, i);
259 if (retval != ERROR_OK)
260 goto fail;
261 }
262
263 /* NOTE: SPSR ignored (if it's even relevant). */
264
265 /* REVISIT the debugger can trigger various exceptions. See the
266 * ARMv7A architecture spec, section C5.7, for more info about
267 * what defenses are needed; v6 debug has the most issues.
268 */
269
270 fail:
271 /* (void) */ dpm->finish(dpm);
272 return retval;
273 }
274
275 /**
276 * Writes all modified core registers for all processor modes. In normal
277 * operation this is called on exit from halting debug state.
278 *
279 * @param bpwp: true ensures breakpoints and watchpoints are set,
280 * false ensures they are cleared
281 */
282 int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
283 {
284 struct arm *arm = dpm->arm;
285 struct reg_cache *cache = arm->core_cache;
286 int retval;
287 bool did_write;
288
289 retval = dpm->prepare(dpm);
290 if (retval != ERROR_OK)
291 goto done;
292
293 /* enable/disable watchpoints */
294 for (unsigned i = 0; i < dpm->nwp; i++) {
295 struct dpm_wp *dwp = dpm->dwp + i;
296 struct watchpoint *wp = dwp->wp;
297 bool disable;
298
299 /* Avoid needless I/O ... leave watchpoints alone
300 * unless they're removed, or need updating because
301 * of single-stepping or running debugger code.
302 */
303 if (!wp) {
304 if (!dwp->dirty)
305 continue;
306 dwp->dirty = false;
307 /* removed or startup; we must disable it */
308 disable = true;
309 } else if (bpwp) {
310 if (!dwp->dirty)
311 continue;
312 /* disabled, but we must set it */
313 dwp->dirty = disable = false;
314 wp->set = true;
315 } else {
316 if (!wp->set)
317 continue;
318 /* set, but we must temporarily disable it */
319 dwp->dirty = disable = true;
320 wp->set = false;
321 }
322
323 if (disable)
324 retval = dpm->bpwp_disable(dpm, 16 + i);
325 else
326 retval = dpm->bpwp_enable(dpm, 16 + i,
327 wp->address, dwp->control);
328
329 if (retval != ERROR_OK)
330 LOG_ERROR("%s: can't %s HW watchpoint %d",
331 target_name(arm->target),
332 disable ? "disable" : "enable",
333 i);
334 }
335
336 /* NOTE: writes to breakpoint and watchpoint registers might
337 * be queued, and need (efficient/batched) flushing later.
338 */
339
340 /* Scan the registers until we find one that's both dirty and
341 * eligible for flushing. Flush that and everything else that
342 * shares the same core mode setting. Typically this won't
343 * actually find anything to do...
344 */
345 do {
346 enum armv4_5_mode mode = ARMV4_5_MODE_ANY;
347
348 did_write = false;
349
350 /* check everything except our scratch register R0 */
351 for (unsigned i = 1; i < cache->num_regs; i++) {
352 struct arm_reg *r;
353 unsigned regnum;
354
355 /* also skip PC, CPSR, and non-dirty */
356 if (i == 15)
357 continue;
358 if (arm->cpsr == cache->reg_list + i)
359 continue;
360 if (!cache->reg_list[i].dirty)
361 continue;
362
363 r = cache->reg_list[i].arch_info;
364 regnum = r->num;
365
366 /* may need to pick and set a mode */
367 if (!did_write) {
368 enum armv4_5_mode tmode;
369
370 did_write = true;
371 mode = tmode = r->mode;
372
373 /* cope with special cases */
374 switch (regnum) {
375 case 8 ... 12:
376 /* r8..r12 "anything but FIQ" case;
377 * we "know" core mode is accurate
378 * since we haven't changed it yet
379 */
380 if (arm->core_mode == ARMV4_5_MODE_FIQ
381 && ARMV4_5_MODE_ANY
382 != mode)
383 tmode = ARMV4_5_MODE_USR;
384 break;
385 case 16:
386 /* SPSR */
387 regnum++;
388 break;
389 }
390
391 /* REVISIT error checks */
392 if (tmode != ARMV4_5_MODE_ANY)
393 retval = dpm_modeswitch(dpm, tmode);
394 }
395 if (r->mode != mode)
396 continue;
397
398 retval = dpm_write_reg(dpm,
399 &cache->reg_list[i],
400 regnum);
401
402 }
403
404 } while (did_write);
405
406 /* Restore original CPSR ... assuming either that we changed it,
407 * or it's dirty. Must write PC to ensure the return address is
408 * defined, and must not write it before CPSR.
409 */
410 retval = dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
411 arm->cpsr->dirty = false;
412
413 retval = dpm_write_reg(dpm, &cache->reg_list[15], 15);
414 cache->reg_list[15].dirty = false;
415
416 /* flush R0 -- it's *very* dirty by now */
417 retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
418 cache->reg_list[0].dirty = false;
419
420 /* (void) */ dpm->finish(dpm);
421 done:
422 return retval;
423 }
424
425 /* Returns ARMV4_5_MODE_ANY or temporary mode to use while reading the
426 * specified register ... works around flakiness from ARM core calls.
427 * Caller already filtered out SPSR access; mode is never MODE_SYS
428 * or MODE_ANY.
429 */
430 static enum armv4_5_mode dpm_mapmode(struct arm *arm,
431 unsigned num, enum armv4_5_mode mode)
432 {
433 enum armv4_5_mode amode = arm->core_mode;
434
435 /* don't switch if the mode is already correct */
436 if (amode == ARMV4_5_MODE_SYS)
437 amode = ARMV4_5_MODE_USR;
438 if (mode == amode)
439 return ARMV4_5_MODE_ANY;
440
441 switch (num) {
442 /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */
443 case 0 ... 7:
444 case 15:
445 case 16:
446 break;
447 /* r8..r12 aren't shadowed for anything except FIQ */
448 case 8 ... 12:
449 if (mode == ARMV4_5_MODE_FIQ)
450 return mode;
451 break;
452 /* r13/sp, and r14/lr are always shadowed */
453 case 13:
454 case 14:
455 return mode;
456 default:
457 LOG_WARNING("invalid register #%u", num);
458 break;
459 }
460 return ARMV4_5_MODE_ANY;
461 }
462
463
464 /*
465 * Standard ARM register accessors ... there are three methods
466 * in "struct arm", to support individual read/write and bulk read
467 * of registers.
468 */
469
470 static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
471 int regnum, enum armv4_5_mode mode)
472 {
473 struct arm_dpm *dpm = target_to_arm(target)->dpm;
474 int retval;
475
476 if (regnum < 0 || regnum > 16)
477 return ERROR_INVALID_ARGUMENTS;
478
479 if (regnum == 16) {
480 if (mode != ARMV4_5_MODE_ANY)
481 regnum = 17;
482 } else
483 mode = dpm_mapmode(dpm->arm, regnum, mode);
484
485 /* REVISIT what happens if we try to read SPSR in a core mode
486 * which has no such register?
487 */
488
489 retval = dpm->prepare(dpm);
490 if (retval != ERROR_OK)
491 return retval;
492
493 if (mode != ARMV4_5_MODE_ANY) {
494 retval = dpm_modeswitch(dpm, mode);
495 if (retval != ERROR_OK)
496 goto fail;
497 }
498
499 retval = dpm_read_reg(dpm, r, regnum);
500 /* always clean up, regardless of error */
501
502 if (mode != ARMV4_5_MODE_ANY)
503 /* (void) */ dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
504
505 fail:
506 /* (void) */ dpm->finish(dpm);
507 return retval;
508 }
509
510 static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
511 int regnum, enum armv4_5_mode mode, uint32_t value)
512 {
513 struct arm_dpm *dpm = target_to_arm(target)->dpm;
514 int retval;
515
516
517 if (regnum < 0 || regnum > 16)
518 return ERROR_INVALID_ARGUMENTS;
519
520 if (regnum == 16) {
521 if (mode != ARMV4_5_MODE_ANY)
522 regnum = 17;
523 } else
524 mode = dpm_mapmode(dpm->arm, regnum, mode);
525
526 /* REVISIT what happens if we try to write SPSR in a core mode
527 * which has no such register?
528 */
529
530 retval = dpm->prepare(dpm);
531 if (retval != ERROR_OK)
532 return retval;
533
534 if (mode != ARMV4_5_MODE_ANY) {
535 retval = dpm_modeswitch(dpm, mode);
536 if (retval != ERROR_OK)
537 goto fail;
538 }
539
540 retval = dpm_write_reg(dpm, r, regnum);
541 /* always clean up, regardless of error */
542
543 if (mode != ARMV4_5_MODE_ANY)
544 /* (void) */ dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
545
546 fail:
547 /* (void) */ dpm->finish(dpm);
548 return retval;
549 }
550
551 static int arm_dpm_full_context(struct target *target)
552 {
553 struct arm *arm = target_to_arm(target);
554 struct arm_dpm *dpm = arm->dpm;
555 struct reg_cache *cache = arm->core_cache;
556 int retval;
557 bool did_read;
558
559 retval = dpm->prepare(dpm);
560 if (retval != ERROR_OK)
561 goto done;
562
563 do {
564 enum armv4_5_mode mode = ARMV4_5_MODE_ANY;
565
566 did_read = false;
567
568 /* We "know" arm_dpm_read_current_registers() was called so
569 * the unmapped registers (R0..R7, PC, AND CPSR) and some
570 * view of R8..R14 are current. We also "know" oddities of
571 * register mapping: special cases for R8..R12 and SPSR.
572 *
573 * Pick some mode with unread registers and read them all.
574 * Repeat until done.
575 */
576 for (unsigned i = 0; i < cache->num_regs; i++) {
577 struct arm_reg *r;
578
579 if (cache->reg_list[i].valid)
580 continue;
581 r = cache->reg_list[i].arch_info;
582
583 /* may need to pick a mode and set CPSR */
584 if (!did_read) {
585 did_read = true;
586 mode = r->mode;
587
588 /* For R8..R12 when we've entered debug
589 * state in FIQ mode... patch mode.
590 */
591 if (mode == ARMV4_5_MODE_ANY)
592 mode = ARMV4_5_MODE_USR;
593
594 /* REVISIT error checks */
595 retval = dpm_modeswitch(dpm, mode);
596 }
597 if (r->mode != mode)
598 continue;
599
600 /* CPSR was read, so "R16" must mean SPSR */
601 retval = dpm_read_reg(dpm,
602 &cache->reg_list[i],
603 (r->num == 16) ? 17 : r->num);
604
605 }
606
607 } while (did_read);
608
609 retval = dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
610 /* (void) */ dpm->finish(dpm);
611 done:
612 return retval;
613 }
614
615
616 /*----------------------------------------------------------------------*/
617
618 /*
619 * Breakpoint and Watchpoint support.
620 *
621 * Hardware {break,watch}points are usually left active, to minimize
622 * debug entry/exit costs. When they are set or cleared, it's done in
623 * batches. Also, DPM-conformant hardware can update debug registers
624 * regardless of whether the CPU is running or halted ... though that
625 * fact isn't currently leveraged.
626 */
627
628 static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index,
629 struct watchpoint *wp)
630 {
631 uint32_t addr = wp->address;
632 uint32_t control;
633
634 /* this hardware doesn't support data value matching or masking */
635 if (wp->value || wp->mask != ~(uint32_t)0) {
636 LOG_DEBUG("watchpoint values and masking not supported");
637 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
638 }
639
640 control = (1 << 0) /* enable */
641 | (3 << 1); /* both user and privileged access */
642
643 switch (wp->rw) {
644 case WPT_READ:
645 control |= 1 << 3;
646 break;
647 case WPT_WRITE:
648 control |= 2 << 3;
649 break;
650 case WPT_ACCESS:
651 control |= 3 << 3;
652 break;
653 }
654
655 /* Match 1, 2, or all 4 byte addresses in this word.
656 *
657 * FIXME: v7 hardware allows lengths up to 2 GB, and has eight
658 * byte address select bits. Support larger wp->length, if addr
659 * is suitably aligned.
660 */
661 switch (wp->length) {
662 case 1:
663 control |= (1 << (addr & 3)) << 5;
664 addr &= ~3;
665 break;
666 case 2:
667 /* require 2-byte alignment */
668 if (!(addr & 1)) {
669 control |= (3 << (addr & 2)) << 5;
670 break;
671 }
672 /* FALL THROUGH */
673 case 4:
674 /* require 4-byte alignment */
675 if (!(addr & 3)) {
676 control |= 0xf << 5;
677 break;
678 }
679 /* FALL THROUGH */
680 default:
681 LOG_DEBUG("bad watchpoint length or alignment");
682 return ERROR_INVALID_ARGUMENTS;
683 }
684
685 /* other control bits:
686 * bits 9:12 == 0 ... only checking up to four byte addresses (v7 only)
687 * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only)
688 * bit 20 == 0 ... not linked to a context ID
689 * bit 28:24 == 0 ... not ignoring N LSBs (v7 only)
690 */
691
692 dpm->dwp[index].wp = wp;
693 dpm->dwp[index].control = control;
694 dpm->dwp[index].dirty = true;
695
696 /* hardware is updated in write_dirty_registers() */
697 return ERROR_OK;
698 }
699
700
701 static int dpm_add_watchpoint(struct target *target, struct watchpoint *wp)
702 {
703 struct arm *arm = target_to_arm(target);
704 struct arm_dpm *dpm = arm->dpm;
705 int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
706
707 if (dpm->bpwp_enable) {
708 for (unsigned i = 0; i < dpm->nwp; i++) {
709 if (!dpm->dwp[i].wp) {
710 retval = dpm_watchpoint_setup(dpm, i, wp);
711 break;
712 }
713 }
714 }
715
716 return retval;
717 }
718
719 static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp)
720 {
721 struct arm *arm = target_to_arm(target);
722 struct arm_dpm *dpm = arm->dpm;
723 int retval = ERROR_INVALID_ARGUMENTS;
724
725 for (unsigned i = 0; i < dpm->nwp; i++) {
726 if (dpm->dwp[i].wp == wp) {
727 dpm->dwp[i].wp = NULL;
728 dpm->dwp[i].dirty = true;
729
730 /* hardware is updated in write_dirty_registers() */
731 retval = ERROR_OK;
732 break;
733 }
734 }
735
736 return retval;
737 }
738
739 /*----------------------------------------------------------------------*/
740
741 /*
742 * Setup and management support.
743 */
744
745 /**
746 * Hooks up this DPM to its associated target; call only once.
747 * Initially this only covers the register cache.
748 *
749 * Oh, and watchpoints. Yeah.
750 */
751 int arm_dpm_setup(struct arm_dpm *dpm)
752 {
753 struct arm *arm = dpm->arm;
754 struct target *target = arm->target;
755 struct reg_cache *cache;
756
757 arm->dpm = dpm;
758
759 /* register access setup */
760 arm->full_context = arm_dpm_full_context;
761 arm->read_core_reg = arm_dpm_read_core_reg;
762 arm->write_core_reg = arm_dpm_write_core_reg;
763
764 cache = armv4_5_build_reg_cache(target, arm);
765 if (!cache)
766 return ERROR_FAIL;
767
768 *register_get_last_cache_p(&target->reg_cache) = cache;
769
770 /* coprocessor access setup */
771 arm->mrc = dpm_mrc;
772 arm->mcr = dpm_mcr;
773
774 /* breakpoint and watchpoint setup */
775 target->type->add_watchpoint = dpm_add_watchpoint;
776 target->type->remove_watchpoint = dpm_remove_watchpoint;
777
778 /* FIXME add breakpoint support */
779 /* FIXME add vector catch support */
780
781 dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
782 dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
783
784 dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
785 dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
786
787 if (!dpm->dbp || !dpm->dwp) {
788 free(dpm->dbp);
789 free(dpm->dwp);
790 return ERROR_FAIL;
791 }
792
793 /* Disable all breakpoints and watchpoints at startup. */
794 if (dpm->bpwp_disable) {
795 unsigned i;
796
797 for (i = 0; i < dpm->nbp; i++)
798 (void) dpm->bpwp_disable(dpm, i);
799 for (i = 0; i < dpm->nwp; i++)
800 (void) dpm->bpwp_disable(dpm, 16 + i);
801 } else
802 LOG_WARNING("%s: can't disable breakpoints and watchpoints",
803 target_name(target));
804
805 LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
806 target_name(target), dpm->nbp, dpm->nwp);
807
808 /* REVISIT ... and some of those breakpoints could match
809 * execution context IDs...
810 */
811
812 return ERROR_OK;
813 }
814
815 /**
816 * Reinitializes DPM state at the beginning of a new debug session
817 * or after a reset which may have affected the debug module.
818 */
819 int arm_dpm_initialize(struct arm_dpm *dpm)
820 {
821 /* FIXME -- nothing yet */
822 return ERROR_OK;
823 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)