aarch64: add basic Aarch32 support
[openocd.git] / src / target / armv8_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 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include "arm.h"
21 #include "armv8.h"
22 #include "armv8_dpm.h"
23 #include <jtag/jtag.h>
24 #include "register.h"
25 #include "breakpoints.h"
26 #include "target_type.h"
27 #include "armv8_opcodes.h"
28
29
30 /**
31 * @file
32 * Implements various ARM DPM operations using architectural debug registers.
33 * These routines layer over core-specific communication methods to cope with
34 * implementation differences between cores like ARM1136 and Cortex-A8.
35 *
36 * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by
37 * Part C (Debug Architecture) of the ARM Architecture Reference Manual,
38 * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations
39 * are abstracted through internal programming interfaces to share code and
40 * to minimize needless differences in debug behavior between cores.
41 */
42
43 /*----------------------------------------------------------------------*/
44
45 /*
46 * Coprocessor support
47 */
48
49 /* Read coprocessor */
50 static int dpmv8_mrc(struct target *target, int cpnum,
51 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
52 uint32_t *value)
53 {
54 struct arm *arm = target_to_arm(target);
55 struct arm_dpm *dpm = arm->dpm;
56 int retval;
57
58 retval = dpm->prepare(dpm);
59 if (retval != ERROR_OK)
60 return retval;
61
62 LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum,
63 (int) op1, (int) CRn,
64 (int) CRm, (int) op2);
65
66 /* read coprocessor register into R0; return via DCC */
67 retval = dpm->instr_read_data_r0(dpm,
68 T32_FMTITR(ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2)),
69 value);
70
71 /* (void) */ dpm->finish(dpm);
72 return retval;
73 }
74
75 static int dpmv8_mcr(struct target *target, int cpnum,
76 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
77 uint32_t value)
78 {
79 struct arm *arm = target_to_arm(target);
80 struct arm_dpm *dpm = arm->dpm;
81 int retval;
82
83 retval = dpm->prepare(dpm);
84 if (retval != ERROR_OK)
85 return retval;
86
87 LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum,
88 (int) op1, (int) CRn,
89 (int) CRm, (int) op2);
90
91 /* read DCC into r0; then write coprocessor register from R0 */
92 retval = dpm->instr_write_data_r0(dpm,
93 T32_FMTITR(ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2)),
94 value);
95
96 /* (void) */ dpm->finish(dpm);
97 return retval;
98 }
99
100 static int dpmv8_mrs(struct target *target, uint32_t op0,
101 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
102 uint32_t *value)
103 {
104 struct arm *arm = target_to_arm(target);
105 struct arm_dpm *dpm = arm->dpm;
106 int retval;
107 uint32_t op_code;
108
109 retval = dpm->prepare(dpm);
110 if (retval != ERROR_OK)
111 return retval;
112 op_code = ((op0 & 0x3) << 19 | (op1 & 0x7) << 16 | (CRn & 0xF) << 12 |\
113 (CRm & 0xF) << 8 | (op2 & 0x7) << 5);
114 op_code >>= 5;
115 LOG_DEBUG("MRS p%d, %d, r0, c%d, c%d, %d", (int)op0,
116 (int) op1, (int) CRn,
117 (int) CRm, (int) op2);
118 /* read coprocessor register into R0; return via DCC */
119 retval = dpm->instr_read_data_r0(dpm,
120 ARMV8_MRS(op_code, 0),
121 value);
122
123 /* (void) */ dpm->finish(dpm);
124 return retval;
125 }
126
127 static int dpmv8_msr(struct target *target, uint32_t op0,
128 uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
129 uint32_t value)
130 {
131 struct arm *arm = target_to_arm(target);
132 struct arm_dpm *dpm = arm->dpm;
133 int retval;
134 uint32_t op_code;
135
136 retval = dpm->prepare(dpm);
137 if (retval != ERROR_OK)
138 return retval;
139
140 op_code = ((op0 & 0x3) << 19 | (op1 & 0x7) << 16 | (CRn & 0xF) << 12 |\
141 (CRm & 0xF) << 8 | (op2 & 0x7) << 5);
142 op_code >>= 5;
143 LOG_DEBUG("MSR p%d, %d, r0, c%d, c%d, %d", (int)op0,
144 (int) op1, (int) CRn,
145 (int) CRm, (int) op2);
146
147 /* read DCC into r0; then write coprocessor register from R0 */
148 retval = dpm->instr_write_data_r0(dpm,
149 ARMV8_MSR_GP(op_code, 0),
150 value);
151
152 /* (void) */ dpm->finish(dpm);
153 return retval;
154 }
155
156 /*----------------------------------------------------------------------*/
157
158 /*
159 * Register access utilities
160 */
161
162 /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
163 * Routines *must* restore the original mode before returning!!
164 */
165 int dpmv8_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
166 {
167 struct armv8_common *armv8 = (struct armv8_common *)dpm->arm->arch_info;
168 int retval;
169 uint32_t cpsr;
170
171 /* restore previous mode */
172 if (mode == ARM_MODE_ANY)
173 cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32);
174
175 /* else force to the specified mode */
176 else
177 cpsr = mode >> 4;
178
179 switch ((cpsr & 0xC) >> 2) {
180 case SYSTEM_CUREL_EL1:
181 retval = dpm->instr_execute(dpm, ARMV8_DCPS1(11));
182 if (retval != ERROR_OK)
183 return retval;
184 break;
185 case SYSTEM_CUREL_EL2:
186 retval = dpm->instr_execute(dpm, ARMV8_DCPS2(11));
187 if (retval != ERROR_OK)
188 return retval;
189 break;
190 break;
191 case SYSTEM_CUREL_EL3:
192 retval = dpm->instr_execute(dpm, ARMV8_DCPS3(11));
193 if (retval != ERROR_OK)
194 return retval;
195 break;
196 break;
197 default:
198 LOG_DEBUG("unknow mode 0x%x", (unsigned) ((cpsr & 0xC) >> 2));
199 break;
200 }
201
202
203 retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_DSPSR), cpsr);
204 if (retval != ERROR_OK)
205 return retval;
206
207 if (dpm->instr_cpsr_sync)
208 retval = dpm->instr_cpsr_sync(dpm);
209
210 return retval;
211 }
212
213 static int dpmv8_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
214 {
215 uint32_t value;
216 int retval = ERROR_FAIL;
217 bool valid = true;
218
219 switch (regnum) {
220 case 0 ... 14:
221 /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
222 retval = dpm->instr_read_data_dcc(dpm,
223 T32_FMTITR(ARMV4_5_MCR(14, 0, regnum, 0, 5, 0)),
224 &value);
225 break;
226 case ARMV8_R31:
227 retval = dpm->instr_read_data_dcc(dpm,
228 T32_FMTITR(ARMV4_5_MCR(14, 0, 13, 0, 5, 0)),
229 &value);
230 break;
231 case ARMV8_PC:
232 retval = dpm->instr_read_data_r0(dpm,
233 T32_FMTITR(ARMV8_MRC_DLR(0)),
234 &value);
235 break;
236 case ARMV8_xPSR:
237 retval = dpm->instr_read_data_r0(dpm,
238 T32_FMTITR(ARMV8_MRC_DSPSR(0)),
239 &value);
240 break;
241 default:
242 LOG_DEBUG("READ: %s ignored", r->name);
243 retval = ERROR_OK;
244 value = 0xFFFFFFFF;
245 valid = false;
246 break;
247 }
248
249 if (retval == ERROR_OK) {
250 r->valid = valid;
251 r->dirty = false;
252 buf_set_u64(r->value, 0, 32, value);
253 LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value);
254 }
255 return retval;
256 }
257
258 static int dpmv8_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
259 {
260 int retval;
261 uint64_t value = buf_get_u64(r->value, 0, 32);
262
263 switch (regnum) {
264 case 0 ... 14:
265 /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */
266 retval = dpm->instr_write_data_dcc(dpm,
267 T32_FMTITR(ARMV4_5_MRC(14, 0, regnum, 0, 5, 0)), value);
268 break;
269 case ARMV8_PC:/* PC
270 * read r0 from DCC; then "MOV pc, r0" */
271 retval = dpm->instr_write_data_r0(dpm,
272 T32_FMTITR(ARMV8_MCR_DLR(0)), value);
273 break;
274 case ARMV8_xPSR: /* CPSR */
275 /* read r0 from DCC, then "MCR r0, DSPSR" */
276 retval = dpm->instr_write_data_r0(dpm,
277 T32_FMTITR(ARMV8_MCR_DSPSR(0)), value);
278 break;
279 default:
280 retval = ERROR_OK;
281 LOG_DEBUG("WRITE: %s ignored", r->name);
282 break;
283 }
284
285 if (retval == ERROR_OK) {
286 r->dirty = false;
287 LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value);
288 }
289
290 return retval;
291 }
292
293 /* just read the register -- rely on the core mode being right */
294 static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
295 {
296 uint32_t value;
297 uint64_t value_64;
298 int retval = ERROR_FAIL;
299
300 switch (regnum) {
301 case 0 ... 30:
302 retval = dpm->instr_read_data_dcc_64(dpm,
303 ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, regnum),
304 &value_64);
305 break;
306 case ARMV8_R31:
307 retval = dpm->instr_read_data_r0_64(dpm,
308 ARMV8_MOVFSP_64(0),
309 &value_64);
310 break;
311 case ARMV8_PC:
312 retval = dpm->instr_read_data_r0_64(dpm,
313 ARMV8_MRS_DLR(0),
314 &value_64);
315 break;
316 case ARMV8_xPSR:
317 retval = dpm->instr_read_data_r0(dpm,
318 ARMV8_MRS_DSPSR(0),
319 &value);
320 break;
321 default:
322 LOG_DEBUG("READ: %s fail", r->name);
323 break;
324 }
325
326 if (retval == ERROR_OK) {
327 r->valid = true;
328 r->dirty = false;
329 if (r->size == 64) {
330 buf_set_u64(r->value, 0, 64, value_64);
331 LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64);
332 } else {
333 buf_set_u32(r->value, 0, 32, value);
334 LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value);
335 }
336 }
337 return retval;
338 }
339
340 /* just write the register -- rely on the core mode being right */
341 static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
342 {
343 int retval = ERROR_FAIL;
344 uint32_t value = 0xFFFFFFFF;
345 uint64_t value_64 = 0xFFFFFFFFFFFFFFFF;
346
347 switch (regnum) {
348 case 0 ... 30:
349 value_64 = buf_get_u64(r->value, 0, 64);
350 retval = dpm->instr_write_data_dcc_64(dpm,
351 ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, regnum),
352 value_64);
353 break;
354 case ARMV8_R31:
355 value_64 = buf_get_u64(r->value, 0, 64);
356 retval = dpm->instr_write_data_r0_64(dpm,
357 ARMV8_MOVTSP_64(0),
358 value_64);
359 break;
360 case ARMV8_PC:
361 value_64 = buf_get_u64(r->value, 0, 64);
362 retval = dpm->instr_write_data_r0_64(dpm,
363 ARMV8_MSR_DLR(0),
364 value_64);
365 break;
366 case ARMV8_xPSR:
367 value = buf_get_u32(r->value, 0, 32);
368 retval = dpm->instr_write_data_r0(dpm,
369 ARMV8_MSR_DSPSR(0),
370 value);
371 break;
372 default:
373 LOG_DEBUG("write: %s fail", r->name);
374 break;
375 }
376
377
378 if (retval == ERROR_OK) {
379 r->dirty = false;
380 if (r->size == 64)
381 LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long) value_64);
382 else
383 LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value);
384 }
385
386 return retval;
387 }
388
389 static inline enum arm_state dpm_get_core_state(uint32_t dscr)
390 {
391 int el = (dscr >> 8) & 0x3;
392 int rw = (dscr >> 10) & 0xF;
393
394 LOG_DEBUG("EL:%i, RW:0x%x", el, rw);
395
396 /* DSCR.RW = 0b1111 - all EL are using AArch64 state */
397 if (rw == 0xF)
398 return ARM_STATE_AARCH64;
399
400 /* DSCR.RW = 0b1110 - all EL > 0 are using AArch64 state */
401 if (rw == 0xE && el > 0)
402 return ARM_STATE_AARCH64;
403
404 /* DSCR.RW = 0b110x - all EL > 1 are using Aarch64 state */
405 if ((rw & 0xE) == 0xC && el > 1)
406 return ARM_STATE_AARCH64;
407
408 /* DSCR.RW = 0b10xx - all EL > 2 are using Aarch64 state */
409 if ((rw & 0xC) == 0x8 && el > 2)
410 return ARM_STATE_AARCH64;
411
412 /* DSCR.RW = 0b0xxx - all EL are using AArch32 state */
413 if ((rw & 0x8) == 0)
414 return ARM_STATE_ARM;
415
416 return ARM_STATE_ARM;
417 }
418
419 /**
420 * Read basic registers of the the current context: R0 to R15, and CPSR;
421 * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
422 * In normal operation this is called on entry to halting debug state,
423 * possibly after some other operations supporting restore of debug state
424 * or making sure the CPU is fully idle (drain write buffer, etc).
425 */
426 int armv8_dpm_read_current_registers(struct arm_dpm *dpm)
427 {
428 struct arm *arm = dpm->arm;
429 struct armv8_common *armv8 = (struct armv8_common *)arm->arch_info;
430 enum arm_state core_state;
431 uint32_t cpsr;
432
433 int retval;
434 struct reg *r;
435
436 retval = dpm->prepare(dpm);
437 if (retval != ERROR_OK)
438 return retval;
439
440 core_state = dpm_get_core_state(dpm->dscr);
441
442 armv8_select_opcodes(armv8, core_state);
443
444 /* read R0 first (it's used for scratch), then CPSR */
445 r = arm->core_cache->reg_list + 0;
446 if (!r->valid) {
447 retval = core_state == ARM_STATE_AARCH64 ?
448 dpmv8_read_reg(dpm, r, 0) : dpmv8_read_reg32(dpm, r, 0);
449 if (retval != ERROR_OK)
450 goto fail;
451 }
452 r->dirty = true;
453
454 /* read cpsr to r0 and get it back */
455 retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_DSPSR), &cpsr);
456 if (retval != ERROR_OK)
457 goto fail;
458
459 /* update core mode and state, plus shadow mapping for R8..R14 */
460 armv8_set_cpsr(arm, cpsr);
461
462 /* REVISIT we can probably avoid reading R1..R14, saving time... */
463 for (unsigned i = 1; i < arm->core_cache->num_regs ; i++) {
464 r = armv8_reg_current(arm, i);
465 if (r->valid)
466 continue;
467
468 retval = core_state == ARM_STATE_AARCH64 ?
469 dpmv8_read_reg(dpm, r, i) : dpmv8_read_reg32(dpm, r, i);
470
471 if (retval != ERROR_OK)
472 goto fail;
473 }
474
475 /* NOTE: SPSR ignored (if it's even relevant). */
476
477 /* REVISIT the debugger can trigger various exceptions. See the
478 * ARMv7A architecture spec, section C5.7, for more info about
479 * what defenses are needed; v6 debug has the most issues.
480 */
481
482 fail:
483 /* (void) */ dpm->finish(dpm);
484 return retval;
485 }
486
487 /* Avoid needless I/O ... leave breakpoints and watchpoints alone
488 * unless they're removed, or need updating because of single-stepping
489 * or running debugger code.
490 */
491 static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp,
492 struct dpm_bpwp *xp, int *set_p)
493 {
494 int retval = ERROR_OK;
495 bool disable;
496
497 if (!set_p) {
498 if (!xp->dirty)
499 goto done;
500 xp->dirty = false;
501 /* removed or startup; we must disable it */
502 disable = true;
503 } else if (bpwp) {
504 if (!xp->dirty)
505 goto done;
506 /* disabled, but we must set it */
507 xp->dirty = disable = false;
508 *set_p = true;
509 } else {
510 if (!*set_p)
511 goto done;
512 /* set, but we must temporarily disable it */
513 xp->dirty = disable = true;
514 *set_p = false;
515 }
516
517 if (disable)
518 retval = dpm->bpwp_disable(dpm, xp->number);
519 else
520 retval = dpm->bpwp_enable(dpm, xp->number,
521 xp->address, xp->control);
522
523 if (retval != ERROR_OK)
524 LOG_ERROR("%s: can't %s HW %spoint %d",
525 disable ? "disable" : "enable",
526 target_name(dpm->arm->target),
527 (xp->number < 16) ? "break" : "watch",
528 xp->number & 0xf);
529 done:
530 return retval;
531 }
532
533 static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp);
534
535 /**
536 * Writes all modified core registers for all processor modes. In normal
537 * operation this is called on exit from halting debug state.
538 *
539 * @param dpm: represents the processor
540 * @param bpwp: true ensures breakpoints and watchpoints are set,
541 * false ensures they are cleared
542 */
543 int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
544 {
545 struct arm *arm = dpm->arm;
546 struct reg_cache *cache = arm->core_cache;
547 int retval;
548 bool is_aarch64 = arm->core_state == ARM_STATE_AARCH64;
549
550 retval = dpm->prepare(dpm);
551 if (retval != ERROR_OK)
552 goto done;
553
554 /* If we're managing hardware breakpoints for this core, enable
555 * or disable them as requested.
556 *
557 * REVISIT We don't yet manage them for ANY cores. Eventually
558 * we should be able to assume we handle them; but until then,
559 * cope with the hand-crafted breakpoint code.
560 */
561 if (arm->target->type->add_breakpoint == dpmv8_add_breakpoint) {
562 for (unsigned i = 0; i < dpm->nbp; i++) {
563 struct dpm_bp *dbp = dpm->dbp + i;
564 struct breakpoint *bp = dbp->bp;
565
566 retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
567 bp ? &bp->set : NULL);
568 if (retval != ERROR_OK)
569 goto done;
570 }
571 }
572
573 /* enable/disable watchpoints */
574 for (unsigned i = 0; i < dpm->nwp; i++) {
575 struct dpm_wp *dwp = dpm->dwp + i;
576 struct watchpoint *wp = dwp->wp;
577
578 retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
579 wp ? &wp->set : NULL);
580 if (retval != ERROR_OK)
581 goto done;
582 }
583
584 /* NOTE: writes to breakpoint and watchpoint registers might
585 * be queued, and need (efficient/batched) flushing later.
586 */
587
588 /* Scan the registers until we find one that's both dirty and
589 * eligible for flushing. Flush that and everything else that
590 * shares the same core mode setting. Typically this won't
591 * actually find anything to do...
592 */
593
594 /* check everything except our scratch register R0 */
595 for (unsigned i = 1; i < cache->num_regs; i++) {
596 struct arm_reg *r;
597 unsigned regnum;
598
599 /* also skip PC, CPSR, and non-dirty */
600 if (i == (arm->core_cache->num_regs - 2))
601 continue;
602 if (arm->cpsr == cache->reg_list + i)
603 continue;
604 if (!cache->reg_list[i].dirty)
605 continue;
606
607 r = cache->reg_list[i].arch_info;
608 regnum = r->num;
609
610 retval = is_aarch64 ? dpmv8_write_reg(dpm, &cache->reg_list[i], regnum)
611 : dpmv8_write_reg32(dpm, &cache->reg_list[i], regnum);
612 if (retval != ERROR_OK)
613 goto done;
614 }
615
616
617 /* Restore original CPSR ... assuming either that we changed it,
618 * or it's dirty. Must write PC to ensure the return address is
619 * defined, and must not write it before CPSR.
620 */
621 retval = dpmv8_modeswitch(dpm, ARM_MODE_ANY);
622 if (retval != ERROR_OK)
623 goto done;
624 arm->cpsr->dirty = false;
625
626 retval = is_aarch64 ? dpmv8_write_reg(dpm, arm->pc, (arm->core_cache->num_regs - 2))
627 : dpmv8_write_reg32(dpm, arm->pc, (arm->core_cache->num_regs - 2));
628 if (retval != ERROR_OK)
629 goto done;
630 arm->pc->dirty = false;
631
632 /* flush R0 -- it's *very* dirty by now */
633 retval = is_aarch64 ? dpmv8_write_reg(dpm, &cache->reg_list[0], 0)
634 : dpmv8_write_reg32(dpm, &cache->reg_list[0], 0);
635 if (retval != ERROR_OK)
636 goto done;
637 cache->reg_list[0].dirty = false;
638
639 /* (void) */ dpm->finish(dpm);
640 done:
641 return retval;
642 }
643
644 /*
645 * Standard ARM register accessors ... there are three methods
646 * in "struct arm", to support individual read/write and bulk read
647 * of registers.
648 */
649
650 static int armv8_dpm_read_core_reg(struct target *target, struct reg *r,
651 int regnum, enum arm_mode mode)
652 {
653 struct arm *arm = target_to_arm(target);
654 struct arm_dpm *dpm = target_to_arm(target)->dpm;
655 int retval;
656 int max = arm->core_cache->num_regs;
657
658 if (regnum < 0 || regnum > max)
659 return ERROR_COMMAND_SYNTAX_ERROR;
660
661 /* REVISIT what happens if we try to read SPSR in a core mode
662 * which has no such register?
663 */
664
665 retval = dpm->prepare(dpm);
666 if (retval != ERROR_OK)
667 return retval;
668
669 retval = arm->core_state == ARM_STATE_AARCH64 ?
670 dpmv8_read_reg(dpm, r, regnum) : dpmv8_read_reg32(dpm, r, regnum);
671 if (retval != ERROR_OK)
672 goto fail;
673
674 fail:
675 /* (void) */ dpm->finish(dpm);
676 return retval;
677 }
678
679 static int armv8_dpm_write_core_reg(struct target *target, struct reg *r,
680 int regnum, enum arm_mode mode, uint8_t *value)
681 {
682 struct arm *arm = target_to_arm(target);
683 struct arm_dpm *dpm = target_to_arm(target)->dpm;
684 int retval;
685 int max = arm->core_cache->num_regs;
686
687 if (regnum < 0 || regnum > max)
688 return ERROR_COMMAND_SYNTAX_ERROR;
689
690 /* REVISIT what happens if we try to write SPSR in a core mode
691 * which has no such register?
692 */
693
694 retval = dpm->prepare(dpm);
695 if (retval != ERROR_OK)
696 return retval;
697
698 retval = arm->core_state == ARM_STATE_AARCH64 ?
699 dpmv8_write_reg(dpm, r, regnum) : dpmv8_write_reg32(dpm, r, regnum);
700
701 /* always clean up, regardless of error */
702
703 /* (void) */ dpm->finish(dpm);
704 return retval;
705 }
706
707 static int armv8_dpm_full_context(struct target *target)
708 {
709 struct arm *arm = target_to_arm(target);
710 struct arm_dpm *dpm = arm->dpm;
711 struct reg_cache *cache = arm->core_cache;
712 int retval;
713 bool did_read;
714
715 retval = dpm->prepare(dpm);
716 if (retval != ERROR_OK)
717 goto done;
718
719 do {
720 enum arm_mode mode = ARM_MODE_ANY;
721
722 did_read = false;
723
724 /* We "know" arm_dpm_read_current_registers() was called so
725 * the unmapped registers (R0..R7, PC, AND CPSR) and some
726 * view of R8..R14 are current. We also "know" oddities of
727 * register mapping: special cases for R8..R12 and SPSR.
728 *
729 * Pick some mode with unread registers and read them all.
730 * Repeat until done.
731 */
732 for (unsigned i = 0; i < cache->num_regs; i++) {
733 struct arm_reg *r;
734
735 if (cache->reg_list[i].valid)
736 continue;
737 r = cache->reg_list[i].arch_info;
738
739 /* may need to pick a mode and set CPSR */
740 if (!did_read) {
741 did_read = true;
742 mode = r->mode;
743
744 /* For regular (ARM_MODE_ANY) R8..R12
745 * in case we've entered debug state
746 * in FIQ mode we need to patch mode.
747 */
748 if (mode != ARM_MODE_ANY)
749 retval = dpmv8_modeswitch(dpm, mode);
750 else
751 retval = dpmv8_modeswitch(dpm, ARM_MODE_USR);
752
753 if (retval != ERROR_OK)
754 goto done;
755 }
756 if (r->mode != mode)
757 continue;
758
759 /* CPSR was read, so "R16" must mean SPSR */
760 retval = dpmv8_read_reg(dpm,
761 &cache->reg_list[i],
762 (r->num == 16) ? 17 : r->num);
763 if (retval != ERROR_OK)
764 goto done;
765 }
766
767 } while (did_read);
768
769 retval = dpmv8_modeswitch(dpm, ARM_MODE_ANY);
770 /* (void) */ dpm->finish(dpm);
771 done:
772 return retval;
773 }
774
775
776 /*----------------------------------------------------------------------*/
777
778 /*
779 * Breakpoint and Watchpoint support.
780 *
781 * Hardware {break,watch}points are usually left active, to minimize
782 * debug entry/exit costs. When they are set or cleared, it's done in
783 * batches. Also, DPM-conformant hardware can update debug registers
784 * regardless of whether the CPU is running or halted ... though that
785 * fact isn't currently leveraged.
786 */
787
788 static int dpmv8_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp,
789 uint32_t addr, uint32_t length)
790 {
791 uint32_t control;
792
793 control = (1 << 0) /* enable */
794 | (3 << 1); /* both user and privileged access */
795
796 /* Match 1, 2, or all 4 byte addresses in this word.
797 *
798 * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP.
799 * Support larger length, when addr is suitably aligned. In
800 * particular, allow watchpoints on 8 byte "double" values.
801 *
802 * REVISIT allow watchpoints on unaligned 2-bit values; and on
803 * v7 hardware, unaligned 4-byte ones too.
804 */
805 switch (length) {
806 case 1:
807 control |= (1 << (addr & 3)) << 5;
808 break;
809 case 2:
810 /* require 2-byte alignment */
811 if (!(addr & 1)) {
812 control |= (3 << (addr & 2)) << 5;
813 break;
814 }
815 /* FALL THROUGH */
816 case 4:
817 /* require 4-byte alignment */
818 if (!(addr & 3)) {
819 control |= 0xf << 5;
820 break;
821 }
822 /* FALL THROUGH */
823 default:
824 LOG_ERROR("unsupported {break,watch}point length/alignment");
825 return ERROR_COMMAND_SYNTAX_ERROR;
826 }
827
828 /* other shared control bits:
829 * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only)
830 * bit 20 == 0 ... not linked to a context ID
831 * bit 28:24 == 0 ... not ignoring N LSBs (v7 only)
832 */
833
834 xp->address = addr & ~3;
835 xp->control = control;
836 xp->dirty = true;
837
838 LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d",
839 xp->address, control, xp->number);
840
841 /* hardware is updated in write_dirty_registers() */
842 return ERROR_OK;
843 }
844
845 static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp)
846 {
847 struct arm *arm = target_to_arm(target);
848 struct arm_dpm *dpm = arm->dpm;
849 int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
850
851 if (bp->length < 2)
852 return ERROR_COMMAND_SYNTAX_ERROR;
853 if (!dpm->bpwp_enable)
854 return retval;
855
856 /* FIXME we need a generic solution for software breakpoints. */
857 if (bp->type == BKPT_SOFT)
858 LOG_DEBUG("using HW bkpt, not SW...");
859
860 for (unsigned i = 0; i < dpm->nbp; i++) {
861 if (!dpm->dbp[i].bp) {
862 retval = dpmv8_bpwp_setup(dpm, &dpm->dbp[i].bpwp,
863 bp->address, bp->length);
864 if (retval == ERROR_OK)
865 dpm->dbp[i].bp = bp;
866 break;
867 }
868 }
869
870 return retval;
871 }
872
873 static int dpmv8_remove_breakpoint(struct target *target, struct breakpoint *bp)
874 {
875 struct arm *arm = target_to_arm(target);
876 struct arm_dpm *dpm = arm->dpm;
877 int retval = ERROR_COMMAND_SYNTAX_ERROR;
878
879 for (unsigned i = 0; i < dpm->nbp; i++) {
880 if (dpm->dbp[i].bp == bp) {
881 dpm->dbp[i].bp = NULL;
882 dpm->dbp[i].bpwp.dirty = true;
883
884 /* hardware is updated in write_dirty_registers() */
885 retval = ERROR_OK;
886 break;
887 }
888 }
889
890 return retval;
891 }
892
893 static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t,
894 struct watchpoint *wp)
895 {
896 int retval;
897 struct dpm_wp *dwp = dpm->dwp + index_t;
898 uint32_t control;
899
900 /* this hardware doesn't support data value matching or masking */
901 if (wp->value || wp->mask != ~(uint32_t)0) {
902 LOG_DEBUG("watchpoint values and masking not supported");
903 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
904 }
905
906 retval = dpmv8_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length);
907 if (retval != ERROR_OK)
908 return retval;
909
910 control = dwp->bpwp.control;
911 switch (wp->rw) {
912 case WPT_READ:
913 control |= 1 << 3;
914 break;
915 case WPT_WRITE:
916 control |= 2 << 3;
917 break;
918 case WPT_ACCESS:
919 control |= 3 << 3;
920 break;
921 }
922 dwp->bpwp.control = control;
923
924 dpm->dwp[index_t].wp = wp;
925
926 return retval;
927 }
928
929 static int dpmv8_add_watchpoint(struct target *target, struct watchpoint *wp)
930 {
931 struct arm *arm = target_to_arm(target);
932 struct arm_dpm *dpm = arm->dpm;
933 int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
934
935 if (dpm->bpwp_enable) {
936 for (unsigned i = 0; i < dpm->nwp; i++) {
937 if (!dpm->dwp[i].wp) {
938 retval = dpmv8_watchpoint_setup(dpm, i, wp);
939 break;
940 }
941 }
942 }
943
944 return retval;
945 }
946
947 static int dpmv8_remove_watchpoint(struct target *target, struct watchpoint *wp)
948 {
949 struct arm *arm = target_to_arm(target);
950 struct arm_dpm *dpm = arm->dpm;
951 int retval = ERROR_COMMAND_SYNTAX_ERROR;
952
953 for (unsigned i = 0; i < dpm->nwp; i++) {
954 if (dpm->dwp[i].wp == wp) {
955 dpm->dwp[i].wp = NULL;
956 dpm->dwp[i].bpwp.dirty = true;
957
958 /* hardware is updated in write_dirty_registers() */
959 retval = ERROR_OK;
960 break;
961 }
962 }
963
964 return retval;
965 }
966
967 void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr)
968 {
969 switch (dpm->arm->core_state) {
970 case ARM_STATE_ARM:
971 case ARM_STATE_AARCH64:
972 addr -= 8;
973 break;
974 case ARM_STATE_THUMB:
975 case ARM_STATE_THUMB_EE:
976 addr -= 4;
977 break;
978 case ARM_STATE_JAZELLE:
979 /* ?? */
980 break;
981 default:
982 LOG_DEBUG("Unknow core_state");
983 break;
984 }
985 dpm->wp_pc = addr;
986 }
987
988 /*----------------------------------------------------------------------*/
989
990 /*
991 * Other debug and support utilities
992 */
993
994 void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr)
995 {
996 struct target *target = dpm->arm->target;
997
998 dpm->dscr = dscr;
999
1000 /* Examine debug reason */
1001 switch (DSCR_ENTRY(dscr)) {
1002 /* FALL THROUGH -- assume a v6 core in abort mode */
1003 case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */
1004 target->debug_reason = DBG_REASON_DBGRQ;
1005 break;
1006 case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */
1007 case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/
1008 case DSCRV8_ENTRY_HALT_STEP:
1009 target->debug_reason = DBG_REASON_SINGLESTEP;
1010 break;
1011 case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */
1012 case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */
1013 case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */
1014 case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/
1015 case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/
1016 case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/
1017 target->debug_reason = DBG_REASON_BREAKPOINT;
1018 break;
1019 case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */
1020 target->debug_reason = DBG_REASON_WATCHPOINT;
1021 break;
1022 default:
1023 target->debug_reason = DBG_REASON_UNDEFINED;
1024 break;
1025 }
1026
1027 }
1028
1029 /*----------------------------------------------------------------------*/
1030
1031 /*
1032 * Setup and management support.
1033 */
1034
1035 /**
1036 * Hooks up this DPM to its associated target; call only once.
1037 * Initially this only covers the register cache.
1038 *
1039 * Oh, and watchpoints. Yeah.
1040 */
1041 int armv8_dpm_setup(struct arm_dpm *dpm)
1042 {
1043 struct arm *arm = dpm->arm;
1044 struct target *target = arm->target;
1045 struct reg_cache *cache;
1046 arm->dpm = dpm;
1047
1048 /* register access setup */
1049 arm->full_context = armv8_dpm_full_context;
1050 arm->read_core_reg = armv8_dpm_read_core_reg;
1051 arm->write_core_reg = armv8_dpm_write_core_reg;
1052
1053 if (arm->core_cache == NULL) {
1054 cache = armv8_build_reg_cache(target);
1055 if (!cache)
1056 return ERROR_FAIL;
1057 }
1058
1059 /* coprocessor access setup */
1060 arm->mrc = dpmv8_mrc;
1061 arm->mcr = dpmv8_mcr;
1062 arm->mrs = dpmv8_mrs;
1063 arm->msr = dpmv8_msr;
1064 /* breakpoint setup -- optional until it works everywhere */
1065 if (!target->type->add_breakpoint) {
1066 target->type->add_breakpoint = dpmv8_add_breakpoint;
1067 target->type->remove_breakpoint = dpmv8_remove_breakpoint;
1068 }
1069
1070 /* watchpoint setup */
1071 target->type->add_watchpoint = dpmv8_add_watchpoint;
1072 target->type->remove_watchpoint = dpmv8_remove_watchpoint;
1073
1074 /* FIXME add vector catch support */
1075
1076 dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
1077 dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
1078
1079 dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
1080 dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
1081
1082 if (!dpm->dbp || !dpm->dwp) {
1083 free(dpm->dbp);
1084 free(dpm->dwp);
1085 return ERROR_FAIL;
1086 }
1087
1088 LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
1089 target_name(target), dpm->nbp, dpm->nwp);
1090
1091 /* REVISIT ... and some of those breakpoints could match
1092 * execution context IDs...
1093 */
1094
1095 return ERROR_OK;
1096 }
1097
1098 /**
1099 * Reinitializes DPM state at the beginning of a new debug session
1100 * or after a reset which may have affected the debug module.
1101 */
1102 int armv8_dpm_initialize(struct arm_dpm *dpm)
1103 {
1104 /* Disable all breakpoints and watchpoints at startup. */
1105 if (dpm->bpwp_disable) {
1106 unsigned i;
1107
1108 for (i = 0; i < dpm->nbp; i++) {
1109 dpm->dbp[i].bpwp.number = i;
1110 (void) dpm->bpwp_disable(dpm, i);
1111 }
1112 for (i = 0; i < dpm->nwp; i++) {
1113 dpm->dwp[i].bpwp.number = 16 + i;
1114 (void) dpm->bpwp_disable(dpm, 16 + i);
1115 }
1116 } else
1117 LOG_WARNING("%s: can't disable breakpoints and watchpoints",
1118 target_name(dpm->arm->target));
1119
1120 return ERROR_OK;
1121 }

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)