2 * Copyright (C) 2009 by David Brownell
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.
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.
22 #include "armv8_dpm.h"
23 #include <jtag/jtag.h>
25 #include "breakpoints.h"
26 #include "target_type.h"
27 #include "armv8_opcodes.h"
29 #include "helper/time_support.h"
32 #define T32_FMTITR(instr) (((instr & 0x0000FFFF) << 16) | ((instr & 0xFFFF0000) >> 16))
36 * Implements various ARM DPM operations using architectural debug registers.
37 * These routines layer over core-specific communication methods to cope with
38 * implementation differences between cores like ARM1136 and Cortex-A8.
40 * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by
41 * Part C (Debug Architecture) of the ARM Architecture Reference Manual,
42 * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations
43 * are abstracted through internal programming interfaces to share code and
44 * to minimize needless differences in debug behavior between cores.
48 * Get core state from EDSCR, without necessity to retrieve CPSR
50 enum arm_state
armv8_dpm_get_core_state(struct arm_dpm
*dpm
)
52 int el
= (dpm
->dscr
>> 8) & 0x3;
53 int rw
= (dpm
->dscr
>> 10) & 0xF;
57 /* In Debug state, each bit gives the current Execution state of each EL */
59 return ARM_STATE_AARCH64
;
64 /*----------------------------------------------------------------------*/
66 static int dpmv8_write_dcc(struct armv8_common
*armv8
, uint32_t data
)
68 return mem_ap_write_u32(armv8
->debug_ap
,
69 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, data
);
72 static int dpmv8_write_dcc_64(struct armv8_common
*armv8
, uint64_t data
)
75 ret
= mem_ap_write_u32(armv8
->debug_ap
,
76 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, data
);
78 ret
= mem_ap_write_u32(armv8
->debug_ap
,
79 armv8
->debug_base
+ CPUV8_DBG_DTRTX
, data
>> 32);
83 static int dpmv8_read_dcc(struct armv8_common
*armv8
, uint32_t *data
,
86 uint32_t dscr
= DSCR_ITE
;
92 /* Wait for DTRRXfull */
93 long long then
= timeval_ms();
94 while ((dscr
& DSCR_DTR_TX_FULL
) == 0) {
95 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
96 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
98 if (retval
!= ERROR_OK
)
100 if (timeval_ms() > then
+ 1000) {
101 LOG_ERROR("Timeout waiting for read dcc");
106 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
107 armv8
->debug_base
+ CPUV8_DBG_DTRTX
,
109 if (retval
!= ERROR_OK
)
118 static int dpmv8_read_dcc_64(struct armv8_common
*armv8
, uint64_t *data
,
121 uint32_t dscr
= DSCR_ITE
;
128 /* Wait for DTRRXfull */
129 long long then
= timeval_ms();
130 while ((dscr
& DSCR_DTR_TX_FULL
) == 0) {
131 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
132 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
134 if (retval
!= ERROR_OK
)
136 if (timeval_ms() > then
+ 1000) {
137 LOG_ERROR("Timeout waiting for DTR_TX_FULL, dscr = 0x%08" PRIx32
, dscr
);
142 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
143 armv8
->debug_base
+ CPUV8_DBG_DTRTX
,
145 if (retval
!= ERROR_OK
)
148 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
149 armv8
->debug_base
+ CPUV8_DBG_DTRRX
,
151 if (retval
!= ERROR_OK
)
154 *data
= *(uint32_t *)data
| (uint64_t)higher
<< 32;
162 static int dpmv8_dpm_prepare(struct arm_dpm
*dpm
)
164 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
168 /* set up invariant: ITE is set after ever DPM operation */
169 long long then
= timeval_ms();
171 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
172 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
174 if (retval
!= ERROR_OK
)
176 if ((dscr
& DSCR_ITE
) != 0)
178 if (timeval_ms() > then
+ 1000) {
179 LOG_ERROR("Timeout waiting for dpm prepare");
184 /* update the stored copy of dscr */
187 /* this "should never happen" ... */
188 if (dscr
& DSCR_DTR_RX_FULL
) {
189 LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32
, dscr
);
191 retval
= mem_ap_read_u32(armv8
->debug_ap
,
192 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, &dscr
);
193 if (retval
!= ERROR_OK
)
200 static int dpmv8_dpm_finish(struct arm_dpm
*dpm
)
202 /* REVISIT what could be done here? */
206 static int dpmv8_exec_opcode(struct arm_dpm
*dpm
,
207 uint32_t opcode
, uint32_t *p_dscr
)
209 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
210 uint32_t dscr
= dpm
->dscr
;
216 /* Wait for InstrCompl bit to be set */
217 long long then
= timeval_ms();
218 while ((dscr
& DSCR_ITE
) == 0) {
219 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
220 armv8
->debug_base
+ CPUV8_DBG_DSCR
, &dscr
);
221 if (retval
!= ERROR_OK
) {
222 LOG_ERROR("Could not read DSCR register, opcode = 0x%08" PRIx32
, opcode
);
225 if (timeval_ms() > then
+ 1000) {
226 LOG_ERROR("Timeout waiting for aarch64_exec_opcode");
231 if (armv8_dpm_get_core_state(dpm
) != ARM_STATE_AARCH64
)
232 opcode
= T32_FMTITR(opcode
);
234 retval
= mem_ap_write_u32(armv8
->debug_ap
,
235 armv8
->debug_base
+ CPUV8_DBG_ITR
, opcode
);
236 if (retval
!= ERROR_OK
)
241 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
242 armv8
->debug_base
+ CPUV8_DBG_DSCR
, &dscr
);
243 if (retval
!= ERROR_OK
) {
244 LOG_ERROR("Could not read DSCR register");
247 if (timeval_ms() > then
+ 1000) {
248 LOG_ERROR("Timeout waiting for aarch64_exec_opcode");
251 } while ((dscr
& DSCR_ITE
) == 0); /* Wait for InstrCompl bit to be set */
253 /* update dscr and el after each command execution */
255 if (dpm
->last_el
!= ((dscr
>> 8) & 3))
256 LOG_DEBUG("EL %i -> %" PRIu32
, dpm
->last_el
, (dscr
>> 8) & 3);
257 dpm
->last_el
= (dscr
>> 8) & 3;
259 if (dscr
& DSCR_ERR
) {
260 LOG_ERROR("Opcode 0x%08" PRIx32
", DSCR.ERR=1, DSCR.EL=%i", opcode
, dpm
->last_el
);
261 armv8_dpm_handle_exception(dpm
, true);
271 static int dpmv8_instr_execute(struct arm_dpm
*dpm
, uint32_t opcode
)
273 return dpmv8_exec_opcode(dpm
, opcode
, NULL
);
276 static int dpmv8_instr_write_data_dcc(struct arm_dpm
*dpm
,
277 uint32_t opcode
, uint32_t data
)
279 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
282 retval
= dpmv8_write_dcc(armv8
, data
);
283 if (retval
!= ERROR_OK
)
286 return dpmv8_exec_opcode(dpm
, opcode
, 0);
289 static int dpmv8_instr_write_data_dcc_64(struct arm_dpm
*dpm
,
290 uint32_t opcode
, uint64_t data
)
292 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
295 retval
= dpmv8_write_dcc_64(armv8
, data
);
296 if (retval
!= ERROR_OK
)
299 return dpmv8_exec_opcode(dpm
, opcode
, 0);
302 static int dpmv8_instr_write_data_r0(struct arm_dpm
*dpm
,
303 uint32_t opcode
, uint32_t data
)
305 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
306 uint32_t dscr
= DSCR_ITE
;
309 retval
= dpmv8_write_dcc(armv8
, data
);
310 if (retval
!= ERROR_OK
)
313 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, READ_REG_DTRRX
), &dscr
);
314 if (retval
!= ERROR_OK
)
317 /* then the opcode, taking data from R0 */
318 return dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
321 static int dpmv8_instr_write_data_r0_64(struct arm_dpm
*dpm
,
322 uint32_t opcode
, uint64_t data
)
324 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
327 if (dpm
->arm
->core_state
!= ARM_STATE_AARCH64
)
328 return dpmv8_instr_write_data_r0(dpm
, opcode
, data
);
330 /* transfer data from DCC to R0 */
331 retval
= dpmv8_write_dcc_64(armv8
, data
);
332 if (retval
== ERROR_OK
)
333 retval
= dpmv8_exec_opcode(dpm
, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0
, 0), &dpm
->dscr
);
335 /* then the opcode, taking data from R0 */
336 if (retval
== ERROR_OK
)
337 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dpm
->dscr
);
342 static int dpmv8_instr_cpsr_sync(struct arm_dpm
*dpm
)
345 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
347 /* "Prefetch flush" after modifying execution status in CPSR */
348 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DSB_SY
), &dpm
->dscr
);
349 if (retval
== ERROR_OK
)
350 dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, ARMV8_OPC_ISB_SY
), &dpm
->dscr
);
354 static int dpmv8_instr_read_data_dcc(struct arm_dpm
*dpm
,
355 uint32_t opcode
, uint32_t *data
)
357 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
360 /* the opcode, writing data to DCC */
361 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dpm
->dscr
);
362 if (retval
!= ERROR_OK
)
365 return dpmv8_read_dcc(armv8
, data
, &dpm
->dscr
);
368 static int dpmv8_instr_read_data_dcc_64(struct arm_dpm
*dpm
,
369 uint32_t opcode
, uint64_t *data
)
371 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
374 /* the opcode, writing data to DCC */
375 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dpm
->dscr
);
376 if (retval
!= ERROR_OK
)
379 return dpmv8_read_dcc_64(armv8
, data
, &dpm
->dscr
);
382 static int dpmv8_instr_read_data_r0(struct arm_dpm
*dpm
,
383 uint32_t opcode
, uint32_t *data
)
385 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
388 /* the opcode, writing data to R0 */
389 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dpm
->dscr
);
390 if (retval
!= ERROR_OK
)
393 /* write R0 to DCC */
394 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, WRITE_REG_DTRTX
), &dpm
->dscr
);
395 if (retval
!= ERROR_OK
)
398 return dpmv8_read_dcc(armv8
, data
, &dpm
->dscr
);
401 static int dpmv8_instr_read_data_r0_64(struct arm_dpm
*dpm
,
402 uint32_t opcode
, uint64_t *data
)
404 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
407 if (dpm
->arm
->core_state
!= ARM_STATE_AARCH64
) {
409 retval
= dpmv8_instr_read_data_r0(dpm
, opcode
, &tmp
);
410 if (retval
== ERROR_OK
)
415 /* the opcode, writing data to R0 */
416 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dpm
->dscr
);
417 if (retval
!= ERROR_OK
)
420 /* write R0 to DCC */
421 retval
= dpmv8_exec_opcode(dpm
, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0
, 0), &dpm
->dscr
);
422 if (retval
!= ERROR_OK
)
425 return dpmv8_read_dcc_64(armv8
, data
, &dpm
->dscr
);
429 static int dpmv8_bpwp_enable(struct arm_dpm
*dpm
, unsigned index_t
,
430 target_addr_t addr
, uint32_t control
)
432 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
433 uint32_t vr
= armv8
->debug_base
;
434 uint32_t cr
= armv8
->debug_base
;
438 case 0 ... 15: /* breakpoints */
439 vr
+= CPUV8_DBG_BVR_BASE
;
440 cr
+= CPUV8_DBG_BCR_BASE
;
442 case 16 ... 31: /* watchpoints */
443 vr
+= CPUV8_DBG_WVR_BASE
;
444 cr
+= CPUV8_DBG_WCR_BASE
;
453 LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x",
454 (unsigned) vr
, (unsigned) cr
);
456 retval
= mem_ap_write_atomic_u32(armv8
->debug_ap
, vr
, addr
);
457 if (retval
!= ERROR_OK
)
459 return mem_ap_write_atomic_u32(armv8
->debug_ap
, cr
, control
);
463 static int dpmv8_bpwp_disable(struct arm_dpm
*dpm
, unsigned index_t
)
465 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
470 cr
= armv8
->debug_base
+ CPUV8_DBG_BCR_BASE
;
473 cr
= armv8
->debug_base
+ CPUV8_DBG_WCR_BASE
;
481 LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr
);
483 /* clear control register */
484 return mem_ap_write_atomic_u32(armv8
->debug_ap
, cr
, 0);
488 * Coprocessor support
491 /* Read coprocessor */
492 static int dpmv8_mrc(struct target
*target
, int cpnum
,
493 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
496 struct arm
*arm
= target_to_arm(target
);
497 struct arm_dpm
*dpm
= arm
->dpm
;
500 retval
= dpm
->prepare(dpm
);
501 if (retval
!= ERROR_OK
)
504 LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum
,
505 (int) op1
, (int) CRn
,
506 (int) CRm
, (int) op2
);
508 /* read coprocessor register into R0; return via DCC */
509 retval
= dpm
->instr_read_data_r0(dpm
,
510 ARMV4_5_MRC(cpnum
, op1
, 0, CRn
, CRm
, op2
),
513 /* (void) */ dpm
->finish(dpm
);
517 static int dpmv8_mcr(struct target
*target
, int cpnum
,
518 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
521 struct arm
*arm
= target_to_arm(target
);
522 struct arm_dpm
*dpm
= arm
->dpm
;
525 retval
= dpm
->prepare(dpm
);
526 if (retval
!= ERROR_OK
)
529 LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum
,
530 (int) op1
, (int) CRn
,
531 (int) CRm
, (int) op2
);
533 /* read DCC into r0; then write coprocessor register from R0 */
534 retval
= dpm
->instr_write_data_r0(dpm
,
535 ARMV4_5_MCR(cpnum
, op1
, 0, CRn
, CRm
, op2
),
538 /* (void) */ dpm
->finish(dpm
);
542 /*----------------------------------------------------------------------*/
545 * Register access utilities
548 int armv8_dpm_modeswitch(struct arm_dpm
*dpm
, enum arm_mode mode
)
550 struct armv8_common
*armv8
= (struct armv8_common
*)dpm
->arm
->arch_info
;
551 int retval
= ERROR_OK
;
552 unsigned int target_el
;
553 enum arm_state core_state
;
556 /* restore previous mode */
557 if (mode
== ARM_MODE_ANY
) {
558 cpsr
= buf_get_u32(dpm
->arm
->cpsr
->value
, 0, 32);
560 LOG_DEBUG("restoring mode, cpsr = 0x%08"PRIx32
, cpsr
);
563 LOG_DEBUG("setting mode 0x%x", mode
);
567 switch (cpsr
& 0x1f) {
580 * TODO: handle ARM_MODE_HYP
590 target_el
= (cpsr
>> 2) & 3;
593 if (target_el
> SYSTEM_CUREL_EL3
) {
594 LOG_ERROR("%s: Invalid target exception level %i", __func__
, target_el
);
598 LOG_DEBUG("target_el = %i, last_el = %i", target_el
, dpm
->last_el
);
599 if (target_el
> dpm
->last_el
) {
600 retval
= dpm
->instr_execute(dpm
,
601 armv8_opcode(armv8
, ARMV8_OPC_DCPS
) | target_el
);
603 /* DCPS clobbers registers just like an exception taken */
604 armv8_dpm_handle_exception(dpm
, false);
606 core_state
= armv8_dpm_get_core_state(dpm
);
607 if (core_state
!= ARM_STATE_AARCH64
) {
608 /* cannot do DRPS/ERET when already in EL0 */
609 if (dpm
->last_el
!= 0) {
610 /* load SPSR with the desired mode and execute DRPS */
611 LOG_DEBUG("SPSR = 0x%08"PRIx32
, cpsr
);
612 retval
= dpm
->instr_write_data_r0(dpm
,
613 ARMV8_MSR_GP_xPSR_T1(1, 0, 15), cpsr
);
614 if (retval
== ERROR_OK
)
615 retval
= dpm
->instr_execute(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DRPS
));
619 * need to execute multiple DRPS instructions until target_el
622 while (retval
== ERROR_OK
&& dpm
->last_el
!= target_el
) {
623 unsigned int cur_el
= dpm
->last_el
;
624 retval
= dpm
->instr_execute(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DRPS
));
625 if (cur_el
== dpm
->last_el
) {
626 LOG_INFO("Cannot reach EL %i, SPSR corrupted?", target_el
);
632 /* On executing DRPS, DSPSR and DLR become UNKNOWN, mark them as dirty */
633 dpm
->arm
->cpsr
->dirty
= true;
634 dpm
->arm
->pc
->dirty
= true;
637 * re-evaluate the core state, we might be in Aarch32 state now
638 * we rely on dpm->dscr being up-to-date
640 core_state
= armv8_dpm_get_core_state(dpm
);
641 armv8_select_opcodes(armv8
, core_state
== ARM_STATE_AARCH64
);
642 armv8_select_reg_access(armv8
, core_state
== ARM_STATE_AARCH64
);
649 * Common register read, relies on armv8_select_reg_access() having been called.
651 static int dpmv8_read_reg(struct arm_dpm
*dpm
, struct reg
*r
, unsigned regnum
)
653 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
654 int retval
= ERROR_FAIL
;
658 retval
= armv8
->read_reg_u64(armv8
, regnum
, &value_64
);
660 if (retval
== ERROR_OK
) {
663 buf_set_u64(r
->value
, 0, r
->size
, value_64
);
665 LOG_DEBUG("READ: %s, %16.8llx", r
->name
, (unsigned long long) value_64
);
667 LOG_DEBUG("READ: %s, %8.8x", r
->name
, (unsigned int) value_64
);
669 } else if (r
->size
<= 128) {
670 uint64_t lvalue
= 0, hvalue
= 0;
671 retval
= armv8
->read_reg_u128(armv8
, regnum
, &lvalue
, &hvalue
);
673 if (retval
== ERROR_OK
) {
677 buf_set_u64(r
->value
, 0, 64, lvalue
);
678 buf_set_u64(r
->value
+ 8, 0, r
->size
- 64, hvalue
);
680 LOG_DEBUG("READ: %s, lvalue=%16.8llx", r
->name
, (unsigned long long) lvalue
);
681 LOG_DEBUG("READ: %s, hvalue=%16.8llx", r
->name
, (unsigned long long) hvalue
);
685 if (retval
!= ERROR_OK
)
686 LOG_ERROR("Failed to read %s register", r
->name
);
692 * Common register write, relies on armv8_select_reg_access() having been called.
694 static int dpmv8_write_reg(struct arm_dpm
*dpm
, struct reg
*r
, unsigned regnum
)
696 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
697 int retval
= ERROR_FAIL
;
702 value_64
= buf_get_u64(r
->value
, 0, r
->size
);
703 retval
= armv8
->write_reg_u64(armv8
, regnum
, value_64
);
705 if (retval
== ERROR_OK
) {
708 LOG_DEBUG("WRITE: %s, %16.8llx", r
->name
, (unsigned long long)value_64
);
710 LOG_DEBUG("WRITE: %s, %8.8x", r
->name
, (unsigned int)value_64
);
712 } else if (r
->size
<= 128) {
713 uint64_t lvalue
, hvalue
;
715 lvalue
= buf_get_u64(r
->value
, 0, 64);
716 hvalue
= buf_get_u64(r
->value
+ 8, 0, r
->size
- 64);
717 retval
= armv8
->write_reg_u128(armv8
, regnum
, lvalue
, hvalue
);
719 if (retval
== ERROR_OK
) {
722 LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r
->name
, (unsigned long long) lvalue
);
723 LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r
->name
, (unsigned long long) hvalue
);
727 if (retval
!= ERROR_OK
)
728 LOG_ERROR("Failed to write %s register", r
->name
);
734 * Read basic registers of the current context: R0 to R15, and CPSR;
735 * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
736 * In normal operation this is called on entry to halting debug state,
737 * possibly after some other operations supporting restore of debug state
738 * or making sure the CPU is fully idle (drain write buffer, etc).
740 int armv8_dpm_read_current_registers(struct arm_dpm
*dpm
)
742 struct arm
*arm
= dpm
->arm
;
743 struct armv8_common
*armv8
= (struct armv8_common
*)arm
->arch_info
;
744 struct reg_cache
*cache
;
749 retval
= dpm
->prepare(dpm
);
750 if (retval
!= ERROR_OK
)
753 cache
= arm
->core_cache
;
755 /* read R0 first (it's used for scratch), then CPSR */
756 r
= cache
->reg_list
+ ARMV8_R0
;
758 retval
= dpmv8_read_reg(dpm
, r
, ARMV8_R0
);
759 if (retval
!= ERROR_OK
)
764 /* read R1, too, it will be clobbered during memory access */
765 r
= cache
->reg_list
+ ARMV8_R1
;
767 retval
= dpmv8_read_reg(dpm
, r
, ARMV8_R1
);
768 if (retval
!= ERROR_OK
)
772 /* read cpsr to r0 and get it back */
773 retval
= dpm
->instr_read_data_r0(dpm
,
774 armv8_opcode(armv8
, READ_REG_DSPSR
), &cpsr
);
775 if (retval
!= ERROR_OK
)
778 /* update core mode and state */
779 armv8_set_cpsr(arm
, cpsr
);
781 for (unsigned int i
= ARMV8_PC
; i
< cache
->num_regs
; i
++) {
782 struct arm_reg
*arm_reg
;
784 r
= armv8_reg_current(arm
, i
);
785 if (!r
->exist
|| r
->valid
)
788 /* Skip reading FP-SIMD registers */
789 if (r
->number
>= ARMV8_V0
&& r
->number
<= ARMV8_FPCR
)
793 * Only read registers that are available from the
794 * current EL (or core mode).
796 arm_reg
= r
->arch_info
;
797 if (arm_reg
->mode
!= ARM_MODE_ANY
&&
798 dpm
->last_el
!= armv8_curel_from_core_mode(arm_reg
->mode
))
801 /* Special case: ARM_MODE_SYS has no SPSR at EL1 */
802 if (r
->number
== ARMV8_SPSR_EL1
&& arm
->core_mode
== ARM_MODE_SYS
)
805 retval
= dpmv8_read_reg(dpm
, r
, i
);
806 if (retval
!= ERROR_OK
)
816 /* Avoid needless I/O ... leave breakpoints and watchpoints alone
817 * unless they're removed, or need updating because of single-stepping
818 * or running debugger code.
820 static int dpmv8_maybe_update_bpwp(struct arm_dpm
*dpm
, bool bpwp
,
821 struct dpm_bpwp
*xp
, int *set_p
)
823 int retval
= ERROR_OK
;
830 /* removed or startup; we must disable it */
835 /* disabled, but we must set it */
836 xp
->dirty
= disable
= false;
841 /* set, but we must temporarily disable it */
842 xp
->dirty
= disable
= true;
847 retval
= dpm
->bpwp_disable(dpm
, xp
->number
);
849 retval
= dpm
->bpwp_enable(dpm
, xp
->number
,
850 xp
->address
, xp
->control
);
852 if (retval
!= ERROR_OK
)
853 LOG_ERROR("%s: can't %s HW %spoint %d",
854 disable
? "disable" : "enable",
855 target_name(dpm
->arm
->target
),
856 (xp
->number
< 16) ? "break" : "watch",
862 static int dpmv8_add_breakpoint(struct target
*target
, struct breakpoint
*bp
);
865 * Writes all modified core registers for all processor modes. In normal
866 * operation this is called on exit from halting debug state.
868 * @param dpm: represents the processor
869 * @param bpwp: true ensures breakpoints and watchpoints are set,
870 * false ensures they are cleared
872 int armv8_dpm_write_dirty_registers(struct arm_dpm
*dpm
, bool bpwp
)
874 struct arm
*arm
= dpm
->arm
;
875 struct reg_cache
*cache
= arm
->core_cache
;
878 retval
= dpm
->prepare(dpm
);
879 if (retval
!= ERROR_OK
)
882 /* If we're managing hardware breakpoints for this core, enable
883 * or disable them as requested.
885 * REVISIT We don't yet manage them for ANY cores. Eventually
886 * we should be able to assume we handle them; but until then,
887 * cope with the hand-crafted breakpoint code.
889 if (arm
->target
->type
->add_breakpoint
== dpmv8_add_breakpoint
) {
890 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
891 struct dpm_bp
*dbp
= dpm
->dbp
+ i
;
892 struct breakpoint
*bp
= dbp
->bp
;
894 retval
= dpmv8_maybe_update_bpwp(dpm
, bpwp
, &dbp
->bpwp
,
895 bp
? &bp
->set
: NULL
);
896 if (retval
!= ERROR_OK
)
901 /* enable/disable watchpoints */
902 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
903 struct dpm_wp
*dwp
= dpm
->dwp
+ i
;
904 struct watchpoint
*wp
= dwp
->wp
;
906 retval
= dpmv8_maybe_update_bpwp(dpm
, bpwp
, &dwp
->bpwp
,
907 wp
? &wp
->set
: NULL
);
908 if (retval
!= ERROR_OK
)
912 /* NOTE: writes to breakpoint and watchpoint registers might
913 * be queued, and need (efficient/batched) flushing later.
916 /* Restore original core mode and state */
917 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
918 if (retval
!= ERROR_OK
)
921 /* check everything except our scratch register R0 */
922 for (unsigned i
= 1; i
< cache
->num_regs
; i
++) {
925 /* skip non-existent */
926 if (!cache
->reg_list
[i
].exist
)
928 /* skip PC and CPSR */
929 if (i
== ARMV8_PC
|| i
== ARMV8_xPSR
)
932 if (!cache
->reg_list
[i
].valid
)
935 if (!cache
->reg_list
[i
].dirty
)
938 /* skip all registers not on the current EL */
939 r
= cache
->reg_list
[i
].arch_info
;
940 if (r
->mode
!= ARM_MODE_ANY
&&
941 dpm
->last_el
!= armv8_curel_from_core_mode(r
->mode
))
944 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[i
], i
);
945 if (retval
!= ERROR_OK
)
949 /* flush CPSR and PC */
950 if (retval
== ERROR_OK
)
951 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[ARMV8_xPSR
], ARMV8_xPSR
);
952 if (retval
== ERROR_OK
)
953 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[ARMV8_PC
], ARMV8_PC
);
954 /* flush R0 -- it's *very* dirty by now */
955 if (retval
== ERROR_OK
)
956 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[0], 0);
957 if (retval
== ERROR_OK
)
958 dpm
->instr_cpsr_sync(dpm
);
965 * Standard ARM register accessors ... there are three methods
966 * in "struct arm", to support individual read/write and bulk read
970 static int armv8_dpm_read_core_reg(struct target
*target
, struct reg
*r
,
971 int regnum
, enum arm_mode mode
)
973 struct arm
*arm
= target_to_arm(target
);
974 struct arm_dpm
*dpm
= target_to_arm(target
)->dpm
;
976 int max
= arm
->core_cache
->num_regs
;
978 if (regnum
< 0 || regnum
>= max
)
979 return ERROR_COMMAND_SYNTAX_ERROR
;
982 * REVISIT what happens if we try to read SPSR in a core mode
983 * which has no such register?
985 retval
= dpm
->prepare(dpm
);
986 if (retval
!= ERROR_OK
)
989 retval
= dpmv8_read_reg(dpm
, r
, regnum
);
990 if (retval
!= ERROR_OK
)
994 /* (void) */ dpm
->finish(dpm
);
998 static int armv8_dpm_write_core_reg(struct target
*target
, struct reg
*r
,
999 int regnum
, enum arm_mode mode
, uint8_t *value
)
1001 struct arm
*arm
= target_to_arm(target
);
1002 struct arm_dpm
*dpm
= target_to_arm(target
)->dpm
;
1004 int max
= arm
->core_cache
->num_regs
;
1006 if (regnum
< 0 || regnum
> max
)
1007 return ERROR_COMMAND_SYNTAX_ERROR
;
1009 /* REVISIT what happens if we try to write SPSR in a core mode
1010 * which has no such register?
1013 retval
= dpm
->prepare(dpm
);
1014 if (retval
!= ERROR_OK
)
1017 retval
= dpmv8_write_reg(dpm
, r
, regnum
);
1019 /* always clean up, regardless of error */
1025 static int armv8_dpm_full_context(struct target
*target
)
1027 struct arm
*arm
= target_to_arm(target
);
1028 struct arm_dpm
*dpm
= arm
->dpm
;
1029 struct reg_cache
*cache
= arm
->core_cache
;
1033 retval
= dpm
->prepare(dpm
);
1034 if (retval
!= ERROR_OK
)
1038 enum arm_mode mode
= ARM_MODE_ANY
;
1042 /* We "know" arm_dpm_read_current_registers() was called so
1043 * the unmapped registers (R0..R7, PC, AND CPSR) and some
1044 * view of R8..R14 are current. We also "know" oddities of
1045 * register mapping: special cases for R8..R12 and SPSR.
1047 * Pick some mode with unread registers and read them all.
1048 * Repeat until done.
1050 for (unsigned i
= 0; i
< cache
->num_regs
; i
++) {
1053 if (!cache
->reg_list
[i
].exist
|| cache
->reg_list
[i
].valid
)
1055 r
= cache
->reg_list
[i
].arch_info
;
1057 /* may need to pick a mode and set CPSR */
1062 /* For regular (ARM_MODE_ANY) R8..R12
1063 * in case we've entered debug state
1064 * in FIQ mode we need to patch mode.
1066 if (mode
!= ARM_MODE_ANY
)
1067 retval
= armv8_dpm_modeswitch(dpm
, mode
);
1069 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_USR
);
1071 if (retval
!= ERROR_OK
)
1074 if (r
->mode
!= mode
)
1077 /* CPSR was read, so "R16" must mean SPSR */
1078 retval
= dpmv8_read_reg(dpm
,
1079 &cache
->reg_list
[i
],
1080 (r
->num
== 16) ? 17 : r
->num
);
1081 if (retval
!= ERROR_OK
)
1087 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
1088 /* (void) */ dpm
->finish(dpm
);
1094 /*----------------------------------------------------------------------*/
1097 * Breakpoint and Watchpoint support.
1099 * Hardware {break,watch}points are usually left active, to minimize
1100 * debug entry/exit costs. When they are set or cleared, it's done in
1101 * batches. Also, DPM-conformant hardware can update debug registers
1102 * regardless of whether the CPU is running or halted ... though that
1103 * fact isn't currently leveraged.
1106 static int dpmv8_bpwp_setup(struct arm_dpm
*dpm
, struct dpm_bpwp
*xp
,
1107 uint32_t addr
, uint32_t length
)
1111 control
= (1 << 0) /* enable */
1112 | (3 << 1); /* both user and privileged access */
1114 /* Match 1, 2, or all 4 byte addresses in this word.
1116 * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP.
1117 * Support larger length, when addr is suitably aligned. In
1118 * particular, allow watchpoints on 8 byte "double" values.
1120 * REVISIT allow watchpoints on unaligned 2-bit values; and on
1121 * v7 hardware, unaligned 4-byte ones too.
1125 control
|= (1 << (addr
& 3)) << 5;
1128 /* require 2-byte alignment */
1130 control
|= (3 << (addr
& 2)) << 5;
1135 /* require 4-byte alignment */
1137 control
|= 0xf << 5;
1142 LOG_ERROR("unsupported {break,watch}point length/alignment");
1143 return ERROR_COMMAND_SYNTAX_ERROR
;
1146 /* other shared control bits:
1147 * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only)
1148 * bit 20 == 0 ... not linked to a context ID
1149 * bit 28:24 == 0 ... not ignoring N LSBs (v7 only)
1152 xp
->address
= addr
& ~3;
1153 xp
->control
= control
;
1156 LOG_DEBUG("BPWP: addr %8.8" PRIx32
", control %" PRIx32
", number %d",
1157 xp
->address
, control
, xp
->number
);
1159 /* hardware is updated in write_dirty_registers() */
1163 static int dpmv8_add_breakpoint(struct target
*target
, struct breakpoint
*bp
)
1165 struct arm
*arm
= target_to_arm(target
);
1166 struct arm_dpm
*dpm
= arm
->dpm
;
1167 int retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1170 return ERROR_COMMAND_SYNTAX_ERROR
;
1171 if (!dpm
->bpwp_enable
)
1174 /* FIXME we need a generic solution for software breakpoints. */
1175 if (bp
->type
== BKPT_SOFT
)
1176 LOG_DEBUG("using HW bkpt, not SW...");
1178 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
1179 if (!dpm
->dbp
[i
].bp
) {
1180 retval
= dpmv8_bpwp_setup(dpm
, &dpm
->dbp
[i
].bpwp
,
1181 bp
->address
, bp
->length
);
1182 if (retval
== ERROR_OK
)
1183 dpm
->dbp
[i
].bp
= bp
;
1191 static int dpmv8_remove_breakpoint(struct target
*target
, struct breakpoint
*bp
)
1193 struct arm
*arm
= target_to_arm(target
);
1194 struct arm_dpm
*dpm
= arm
->dpm
;
1195 int retval
= ERROR_COMMAND_SYNTAX_ERROR
;
1197 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
1198 if (dpm
->dbp
[i
].bp
== bp
) {
1199 dpm
->dbp
[i
].bp
= NULL
;
1200 dpm
->dbp
[i
].bpwp
.dirty
= true;
1202 /* hardware is updated in write_dirty_registers() */
1211 static int dpmv8_watchpoint_setup(struct arm_dpm
*dpm
, unsigned index_t
,
1212 struct watchpoint
*wp
)
1215 struct dpm_wp
*dwp
= dpm
->dwp
+ index_t
;
1218 /* this hardware doesn't support data value matching or masking */
1219 if (wp
->value
|| wp
->mask
!= ~(uint32_t)0) {
1220 LOG_DEBUG("watchpoint values and masking not supported");
1221 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1224 retval
= dpmv8_bpwp_setup(dpm
, &dwp
->bpwp
, wp
->address
, wp
->length
);
1225 if (retval
!= ERROR_OK
)
1228 control
= dwp
->bpwp
.control
;
1240 dwp
->bpwp
.control
= control
;
1242 dpm
->dwp
[index_t
].wp
= wp
;
1247 static int dpmv8_add_watchpoint(struct target
*target
, struct watchpoint
*wp
)
1249 struct arm
*arm
= target_to_arm(target
);
1250 struct arm_dpm
*dpm
= arm
->dpm
;
1251 int retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1253 if (dpm
->bpwp_enable
) {
1254 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
1255 if (!dpm
->dwp
[i
].wp
) {
1256 retval
= dpmv8_watchpoint_setup(dpm
, i
, wp
);
1265 static int dpmv8_remove_watchpoint(struct target
*target
, struct watchpoint
*wp
)
1267 struct arm
*arm
= target_to_arm(target
);
1268 struct arm_dpm
*dpm
= arm
->dpm
;
1269 int retval
= ERROR_COMMAND_SYNTAX_ERROR
;
1271 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
1272 if (dpm
->dwp
[i
].wp
== wp
) {
1273 dpm
->dwp
[i
].wp
= NULL
;
1274 dpm
->dwp
[i
].bpwp
.dirty
= true;
1276 /* hardware is updated in write_dirty_registers() */
1286 * Handle exceptions taken in debug state. This happens mostly for memory
1287 * accesses that violated a MMU policy. Taking an exception while in debug
1288 * state clobbers certain state registers on the target exception level.
1289 * Just mark those registers dirty so that they get restored on resume.
1290 * This works both for Aarch32 and Aarch64 states.
1292 * This function must not perform any actions that trigger another exception
1293 * or a recursion will happen.
1295 void armv8_dpm_handle_exception(struct arm_dpm
*dpm
, bool do_restore
)
1297 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
1298 struct reg_cache
*cache
= dpm
->arm
->core_cache
;
1299 enum arm_state core_state
;
1304 static const int clobbered_regs_by_el
[3][5] = {
1305 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL1
, ARMV8_ESR_EL1
, ARMV8_SPSR_EL1
},
1306 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL2
, ARMV8_ESR_EL2
, ARMV8_SPSR_EL2
},
1307 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL3
, ARMV8_ESR_EL3
, ARMV8_SPSR_EL3
},
1310 el
= (dpm
->dscr
>> 8) & 3;
1312 /* safety check, must not happen since EL0 cannot be a target for an exception */
1313 if (el
< SYSTEM_CUREL_EL1
|| el
> SYSTEM_CUREL_EL3
) {
1314 LOG_ERROR("%s: EL %i is invalid, DSCR corrupted?", __func__
, el
);
1318 /* Clear sticky error */
1319 mem_ap_write_u32(armv8
->debug_ap
,
1320 armv8
->debug_base
+ CPUV8_DBG_DRCR
, DRCR_CSE
);
1322 armv8
->read_reg_u64(armv8
, ARMV8_xPSR
, &dlr
);
1324 armv8
->read_reg_u64(armv8
, ARMV8_PC
, &dlr
);
1326 LOG_DEBUG("Exception taken to EL %i, DLR=0x%016"PRIx64
" DSPSR=0x%08"PRIx32
,
1329 /* mark all clobbered registers as dirty */
1330 for (int i
= 0; i
< 5; i
++)
1331 cache
->reg_list
[clobbered_regs_by_el
[el
-1][i
]].dirty
= true;
1334 * re-evaluate the core state, we might be in Aarch64 state now
1335 * we rely on dpm->dscr being up-to-date
1337 core_state
= armv8_dpm_get_core_state(dpm
);
1338 armv8_select_opcodes(armv8
, core_state
== ARM_STATE_AARCH64
);
1339 armv8_select_reg_access(armv8
, core_state
== ARM_STATE_AARCH64
);
1342 armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
1345 /*----------------------------------------------------------------------*/
1348 * Other debug and support utilities
1351 void armv8_dpm_report_dscr(struct arm_dpm
*dpm
, uint32_t dscr
)
1353 struct target
*target
= dpm
->arm
->target
;
1356 dpm
->last_el
= (dscr
>> 8) & 3;
1358 /* Examine debug reason */
1359 switch (DSCR_ENTRY(dscr
)) {
1360 /* FALL THROUGH -- assume a v6 core in abort mode */
1361 case DSCRV8_ENTRY_EXT_DEBUG
: /* EDBGRQ */
1362 target
->debug_reason
= DBG_REASON_DBGRQ
;
1364 case DSCRV8_ENTRY_HALT_STEP_EXECLU
: /* HALT step */
1365 case DSCRV8_ENTRY_HALT_STEP_NORMAL
: /* Halt step*/
1366 case DSCRV8_ENTRY_HALT_STEP
:
1367 target
->debug_reason
= DBG_REASON_SINGLESTEP
;
1369 case DSCRV8_ENTRY_HLT
: /* HLT instruction (software breakpoint) */
1370 case DSCRV8_ENTRY_BKPT
: /* SW BKPT (?) */
1371 case DSCRV8_ENTRY_RESET_CATCH
: /* Reset catch */
1372 case DSCRV8_ENTRY_OS_UNLOCK
: /*OS unlock catch*/
1373 case DSCRV8_ENTRY_SW_ACCESS_DBG
: /*SW access dbg register*/
1374 target
->debug_reason
= DBG_REASON_BREAKPOINT
;
1376 case DSCRV8_ENTRY_WATCHPOINT
: /* asynch watchpoint */
1377 target
->debug_reason
= DBG_REASON_WATCHPOINT
;
1379 case DSCRV8_ENTRY_EXCEPTION_CATCH
: /*exception catch*/
1380 target
->debug_reason
= DBG_REASON_EXC_CATCH
;
1383 target
->debug_reason
= DBG_REASON_UNDEFINED
;
1389 /*----------------------------------------------------------------------*/
1392 * Setup and management support.
1396 * Hooks up this DPM to its associated target; call only once.
1397 * Initially this only covers the register cache.
1399 * Oh, and watchpoints. Yeah.
1401 int armv8_dpm_setup(struct arm_dpm
*dpm
)
1403 struct arm
*arm
= dpm
->arm
;
1404 struct target
*target
= arm
->target
;
1405 struct reg_cache
*cache
;
1408 /* register access setup */
1409 arm
->full_context
= armv8_dpm_full_context
;
1410 arm
->read_core_reg
= armv8_dpm_read_core_reg
;
1411 arm
->write_core_reg
= armv8_dpm_write_core_reg
;
1413 if (arm
->core_cache
== NULL
) {
1414 cache
= armv8_build_reg_cache(target
);
1419 /* coprocessor access setup */
1420 arm
->mrc
= dpmv8_mrc
;
1421 arm
->mcr
= dpmv8_mcr
;
1423 dpm
->prepare
= dpmv8_dpm_prepare
;
1424 dpm
->finish
= dpmv8_dpm_finish
;
1426 dpm
->instr_execute
= dpmv8_instr_execute
;
1427 dpm
->instr_write_data_dcc
= dpmv8_instr_write_data_dcc
;
1428 dpm
->instr_write_data_dcc_64
= dpmv8_instr_write_data_dcc_64
;
1429 dpm
->instr_write_data_r0
= dpmv8_instr_write_data_r0
;
1430 dpm
->instr_write_data_r0_64
= dpmv8_instr_write_data_r0_64
;
1431 dpm
->instr_cpsr_sync
= dpmv8_instr_cpsr_sync
;
1433 dpm
->instr_read_data_dcc
= dpmv8_instr_read_data_dcc
;
1434 dpm
->instr_read_data_dcc_64
= dpmv8_instr_read_data_dcc_64
;
1435 dpm
->instr_read_data_r0
= dpmv8_instr_read_data_r0
;
1436 dpm
->instr_read_data_r0_64
= dpmv8_instr_read_data_r0_64
;
1438 dpm
->arm_reg_current
= armv8_reg_current
;
1440 /* dpm->bpwp_enable = dpmv8_bpwp_enable; */
1441 dpm
->bpwp_disable
= dpmv8_bpwp_disable
;
1443 /* breakpoint setup -- optional until it works everywhere */
1444 if (!target
->type
->add_breakpoint
) {
1445 target
->type
->add_breakpoint
= dpmv8_add_breakpoint
;
1446 target
->type
->remove_breakpoint
= dpmv8_remove_breakpoint
;
1449 /* watchpoint setup */
1450 if (!target
->type
->add_watchpoint
) {
1451 target
->type
->add_watchpoint
= dpmv8_add_watchpoint
;
1452 target
->type
->remove_watchpoint
= dpmv8_remove_watchpoint
;
1455 /* FIXME add vector catch support */
1457 dpm
->nbp
= 1 + ((dpm
->didr
>> 12) & 0xf);
1458 dpm
->dbp
= calloc(dpm
->nbp
, sizeof(*dpm
->dbp
));
1460 dpm
->nwp
= 1 + ((dpm
->didr
>> 20) & 0xf);
1461 dpm
->dwp
= calloc(dpm
->nwp
, sizeof(*dpm
->dwp
));
1463 if (!dpm
->dbp
|| !dpm
->dwp
) {
1469 LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
1470 target_name(target
), dpm
->nbp
, dpm
->nwp
);
1472 /* REVISIT ... and some of those breakpoints could match
1473 * execution context IDs...
1480 * Reinitializes DPM state at the beginning of a new debug session
1481 * or after a reset which may have affected the debug module.
1483 int armv8_dpm_initialize(struct arm_dpm
*dpm
)
1485 /* Disable all breakpoints and watchpoints at startup. */
1486 if (dpm
->bpwp_disable
) {
1489 for (i
= 0; i
< dpm
->nbp
; i
++) {
1490 dpm
->dbp
[i
].bpwp
.number
= i
;
1491 (void) dpm
->bpwp_disable(dpm
, i
);
1493 for (i
= 0; i
< dpm
->nwp
; i
++) {
1494 dpm
->dwp
[i
].bpwp
.number
= 16 + i
;
1495 (void) dpm
->bpwp_disable(dpm
, 16 + i
);
1498 LOG_WARNING("%s: can't disable breakpoints and watchpoints",
1499 target_name(dpm
->arm
->target
));
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)