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;
58 /* find the first '0' in DSCR.RW */
59 for (pos
= 3; pos
>= 0; pos
--) {
60 if ((rw
& (1 << pos
)) == 0)
65 return ARM_STATE_AARCH64
;
70 /*----------------------------------------------------------------------*/
72 static int dpmv8_write_dcc(struct armv8_common
*armv8
, uint32_t data
)
74 LOG_DEBUG("write DCC 0x%08" PRIx32
, data
);
75 return mem_ap_write_u32(armv8
->debug_ap
,
76 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, data
);
79 static int dpmv8_write_dcc_64(struct armv8_common
*armv8
, uint64_t data
)
82 LOG_DEBUG("write DCC Low word 0x%08" PRIx32
, (unsigned)data
);
83 LOG_DEBUG("write DCC High word 0x%08" PRIx32
, (unsigned)(data
>> 32));
84 ret
= mem_ap_write_u32(armv8
->debug_ap
,
85 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, data
);
86 ret
+= mem_ap_write_u32(armv8
->debug_ap
,
87 armv8
->debug_base
+ CPUV8_DBG_DTRTX
, data
>> 32);
91 static int dpmv8_read_dcc(struct armv8_common
*armv8
, uint32_t *data
,
94 uint32_t dscr
= DSCR_ITE
;
100 /* Wait for DTRRXfull */
101 long long then
= timeval_ms();
102 while ((dscr
& DSCR_DTR_TX_FULL
) == 0) {
103 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
104 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
106 if (retval
!= ERROR_OK
)
108 if (timeval_ms() > then
+ 1000) {
109 LOG_ERROR("Timeout waiting for read dcc");
114 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
115 armv8
->debug_base
+ CPUV8_DBG_DTRTX
,
117 if (retval
!= ERROR_OK
)
119 LOG_DEBUG("read DCC 0x%08" PRIx32
, *data
);
127 static int dpmv8_read_dcc_64(struct armv8_common
*armv8
, uint64_t *data
,
130 uint32_t dscr
= DSCR_ITE
;
137 /* Wait for DTRRXfull */
138 long long then
= timeval_ms();
139 while ((dscr
& DSCR_DTR_TX_FULL
) == 0) {
140 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
141 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
143 if (retval
!= ERROR_OK
)
145 if (timeval_ms() > then
+ 1000) {
146 LOG_ERROR("Timeout waiting for read dcc");
151 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
152 armv8
->debug_base
+ CPUV8_DBG_DTRTX
,
154 if (retval
!= ERROR_OK
)
157 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
158 armv8
->debug_base
+ CPUV8_DBG_DTRRX
,
160 if (retval
!= ERROR_OK
)
163 *data
= *(uint32_t *)data
| (uint64_t)higher
<< 32;
164 LOG_DEBUG("read DCC 0x%16.16" PRIx64
, *data
);
172 static int dpmv8_dpm_prepare(struct arm_dpm
*dpm
)
174 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
178 /* set up invariant: INSTR_COMP is set after ever DPM operation */
179 long long then
= timeval_ms();
181 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
182 armv8
->debug_base
+ CPUV8_DBG_DSCR
,
184 if (retval
!= ERROR_OK
)
186 if ((dscr
& DSCR_ITE
) != 0)
188 if (timeval_ms() > then
+ 1000) {
189 LOG_ERROR("Timeout waiting for dpm prepare");
194 /* update the stored copy of dscr */
197 /* this "should never happen" ... */
198 if (dscr
& DSCR_DTR_RX_FULL
) {
199 LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32
, dscr
);
201 retval
= mem_ap_read_u32(armv8
->debug_ap
,
202 armv8
->debug_base
+ CPUV8_DBG_DTRRX
, &dscr
);
203 if (retval
!= ERROR_OK
)
210 static int dpmv8_dpm_finish(struct arm_dpm
*dpm
)
212 /* REVISIT what could be done here? */
216 static int dpmv8_exec_opcode(struct arm_dpm
*dpm
,
217 uint32_t opcode
, uint32_t *p_dscr
)
219 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
220 uint32_t dscr
= DSCR_ITE
;
223 LOG_DEBUG("exec opcode 0x%08" PRIx32
, opcode
);
228 /* Wait for InstrCompl bit to be set */
229 long long then
= timeval_ms();
230 while ((dscr
& DSCR_ITE
) == 0) {
231 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
232 armv8
->debug_base
+ CPUV8_DBG_DSCR
, &dscr
);
233 if (retval
!= ERROR_OK
) {
234 LOG_ERROR("Could not read DSCR register, opcode = 0x%08" PRIx32
, opcode
);
237 if (timeval_ms() > then
+ 1000) {
238 LOG_ERROR("Timeout waiting for aarch64_exec_opcode");
243 if (armv8_dpm_get_core_state(dpm
) != ARM_STATE_AARCH64
)
244 opcode
= T32_FMTITR(opcode
);
246 retval
= mem_ap_write_u32(armv8
->debug_ap
,
247 armv8
->debug_base
+ CPUV8_DBG_ITR
, opcode
);
248 if (retval
!= ERROR_OK
)
253 retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
254 armv8
->debug_base
+ CPUV8_DBG_DSCR
, &dscr
);
255 if (retval
!= ERROR_OK
) {
256 LOG_ERROR("Could not read DSCR register");
259 if (timeval_ms() > then
+ 1000) {
260 LOG_ERROR("Timeout waiting for aarch64_exec_opcode");
263 } while ((dscr
& DSCR_ITE
) == 0); /* Wait for InstrCompl bit to be set */
265 /* update dscr and el after each command execution */
267 if (dpm
->last_el
!= ((dscr
>> 8) & 3))
268 LOG_DEBUG("EL %i -> %i", dpm
->last_el
, (dscr
>> 8) & 3);
269 dpm
->last_el
= (dscr
>> 8) & 3;
271 if (dscr
& DSCR_ERR
) {
272 LOG_ERROR("Opcode 0x%08"PRIx32
", DSCR.ERR=1, DSCR.EL=%i", opcode
, dpm
->last_el
);
273 armv8_dpm_handle_exception(dpm
);
283 static int dpmv8_instr_execute(struct arm_dpm
*dpm
, uint32_t opcode
)
285 return dpmv8_exec_opcode(dpm
, opcode
, NULL
);
288 static int dpmv8_instr_write_data_dcc(struct arm_dpm
*dpm
,
289 uint32_t opcode
, uint32_t data
)
291 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
294 retval
= dpmv8_write_dcc(armv8
, data
);
295 if (retval
!= ERROR_OK
)
298 return dpmv8_exec_opcode(dpm
, opcode
, 0);
301 static int dpmv8_instr_write_data_dcc_64(struct arm_dpm
*dpm
,
302 uint32_t opcode
, uint64_t data
)
304 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
307 retval
= dpmv8_write_dcc_64(armv8
, data
);
308 if (retval
!= ERROR_OK
)
311 return dpmv8_exec_opcode(dpm
, opcode
, 0);
314 static int dpmv8_instr_write_data_r0(struct arm_dpm
*dpm
,
315 uint32_t opcode
, uint32_t data
)
317 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
318 uint32_t dscr
= DSCR_ITE
;
321 retval
= dpmv8_write_dcc(armv8
, data
);
322 if (retval
!= ERROR_OK
)
325 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, READ_REG_DTRRX
), &dscr
);
326 if (retval
!= ERROR_OK
)
329 /* then the opcode, taking data from R0 */
330 return dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
333 static int dpmv8_instr_write_data_r0_64(struct arm_dpm
*dpm
,
334 uint32_t opcode
, uint64_t data
)
336 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
337 uint32_t dscr
= DSCR_ITE
;
340 retval
= dpmv8_write_dcc_64(armv8
, data
);
341 if (retval
!= ERROR_OK
)
344 retval
= dpmv8_exec_opcode(dpm
, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0
, 0), &dscr
);
345 if (retval
!= ERROR_OK
)
348 /* then the opcode, taking data from R0 */
349 return dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
352 static int dpmv8_instr_cpsr_sync(struct arm_dpm
*dpm
)
355 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
357 /* "Prefetch flush" after modifying execution status in CPSR */
358 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DSB_SY
), &dpm
->dscr
);
359 if (retval
== ERROR_OK
)
360 dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, ARMV8_OPC_ISB_SY
), &dpm
->dscr
);
364 static int dpmv8_instr_read_data_dcc(struct arm_dpm
*dpm
,
365 uint32_t opcode
, uint32_t *data
)
367 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
368 uint32_t dscr
= DSCR_ITE
;
371 /* the opcode, writing data to DCC */
372 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
373 if (retval
!= ERROR_OK
)
376 return dpmv8_read_dcc(armv8
, data
, &dscr
);
379 static int dpmv8_instr_read_data_dcc_64(struct arm_dpm
*dpm
,
380 uint32_t opcode
, uint64_t *data
)
382 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
383 uint32_t dscr
= DSCR_ITE
;
386 /* the opcode, writing data to DCC */
387 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
388 if (retval
!= ERROR_OK
)
391 return dpmv8_read_dcc_64(armv8
, data
, &dscr
);
394 static int dpmv8_instr_read_data_r0(struct arm_dpm
*dpm
,
395 uint32_t opcode
, uint32_t *data
)
397 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
398 uint32_t dscr
= DSCR_ITE
;
401 /* the opcode, writing data to R0 */
402 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
403 if (retval
!= ERROR_OK
)
406 /* write R0 to DCC */
407 retval
= dpmv8_exec_opcode(dpm
, armv8_opcode(armv8
, WRITE_REG_DTRTX
), &dscr
);
408 if (retval
!= ERROR_OK
)
411 return dpmv8_read_dcc(armv8
, data
, &dscr
);
414 static int dpmv8_instr_read_data_r0_64(struct arm_dpm
*dpm
,
415 uint32_t opcode
, uint64_t *data
)
417 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
418 uint32_t dscr
= DSCR_ITE
;
421 /* the opcode, writing data to R0 */
422 retval
= dpmv8_exec_opcode(dpm
, opcode
, &dscr
);
423 if (retval
!= ERROR_OK
)
426 /* write R0 to DCC */
427 retval
= dpmv8_exec_opcode(dpm
, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0
, 0), &dscr
);
428 if (retval
!= ERROR_OK
)
431 return dpmv8_read_dcc_64(armv8
, data
, &dscr
);
435 static int dpmv8_bpwp_enable(struct arm_dpm
*dpm
, unsigned index_t
,
436 target_addr_t addr
, uint32_t control
)
438 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
439 uint32_t vr
= armv8
->debug_base
;
440 uint32_t cr
= armv8
->debug_base
;
444 case 0 ... 15: /* breakpoints */
445 vr
+= CPUV8_DBG_BVR_BASE
;
446 cr
+= CPUV8_DBG_BCR_BASE
;
448 case 16 ... 31: /* watchpoints */
449 vr
+= CPUV8_DBG_WVR_BASE
;
450 cr
+= CPUV8_DBG_WCR_BASE
;
459 LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x",
460 (unsigned) vr
, (unsigned) cr
);
462 retval
= mem_ap_write_atomic_u32(armv8
->debug_ap
, vr
, addr
);
463 if (retval
!= ERROR_OK
)
465 return mem_ap_write_atomic_u32(armv8
->debug_ap
, cr
, control
);
469 static int dpmv8_bpwp_disable(struct arm_dpm
*dpm
, unsigned index_t
)
471 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
476 cr
= armv8
->debug_base
+ CPUV8_DBG_BCR_BASE
;
479 cr
= armv8
->debug_base
+ CPUV8_DBG_WCR_BASE
;
487 LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr
);
489 /* clear control register */
490 return mem_ap_write_atomic_u32(armv8
->debug_ap
, cr
, 0);
494 * Coprocessor support
497 /* Read coprocessor */
498 static int dpmv8_mrc(struct target
*target
, int cpnum
,
499 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
502 struct arm
*arm
= target_to_arm(target
);
503 struct arm_dpm
*dpm
= arm
->dpm
;
506 retval
= dpm
->prepare(dpm
);
507 if (retval
!= ERROR_OK
)
510 LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum
,
511 (int) op1
, (int) CRn
,
512 (int) CRm
, (int) op2
);
514 /* read coprocessor register into R0; return via DCC */
515 retval
= dpm
->instr_read_data_r0(dpm
,
516 ARMV4_5_MRC(cpnum
, op1
, 0, CRn
, CRm
, op2
),
519 /* (void) */ dpm
->finish(dpm
);
523 static int dpmv8_mcr(struct target
*target
, int cpnum
,
524 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
527 struct arm
*arm
= target_to_arm(target
);
528 struct arm_dpm
*dpm
= arm
->dpm
;
531 retval
= dpm
->prepare(dpm
);
532 if (retval
!= ERROR_OK
)
535 LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum
,
536 (int) op1
, (int) CRn
,
537 (int) CRm
, (int) op2
);
539 /* read DCC into r0; then write coprocessor register from R0 */
540 retval
= dpm
->instr_write_data_r0(dpm
,
541 ARMV4_5_MCR(cpnum
, op1
, 0, CRn
, CRm
, op2
),
544 /* (void) */ dpm
->finish(dpm
);
548 static int dpmv8_mrs(struct target
*target
, uint32_t op0
,
549 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
552 struct arm
*arm
= target_to_arm(target
);
553 struct arm_dpm
*dpm
= arm
->dpm
;
557 retval
= dpm
->prepare(dpm
);
558 if (retval
!= ERROR_OK
)
560 op_code
= ((op0
& 0x3) << 19 | (op1
& 0x7) << 16 | (CRn
& 0xF) << 12 |\
561 (CRm
& 0xF) << 8 | (op2
& 0x7) << 5);
563 LOG_DEBUG("MRS p%d, %d, r0, c%d, c%d, %d", (int)op0
,
564 (int) op1
, (int) CRn
,
565 (int) CRm
, (int) op2
);
566 /* read coprocessor register into R0; return via DCC */
567 retval
= dpm
->instr_read_data_r0(dpm
,
568 ARMV8_MRS(op_code
, 0),
571 /* (void) */ dpm
->finish(dpm
);
575 static int dpmv8_msr(struct target
*target
, uint32_t op0
,
576 uint32_t op1
, uint32_t op2
, uint32_t CRn
, uint32_t CRm
,
579 struct arm
*arm
= target_to_arm(target
);
580 struct arm_dpm
*dpm
= arm
->dpm
;
584 retval
= dpm
->prepare(dpm
);
585 if (retval
!= ERROR_OK
)
588 op_code
= ((op0
& 0x3) << 19 | (op1
& 0x7) << 16 | (CRn
& 0xF) << 12 |\
589 (CRm
& 0xF) << 8 | (op2
& 0x7) << 5);
591 LOG_DEBUG("MSR p%d, %d, r0, c%d, c%d, %d", (int)op0
,
592 (int) op1
, (int) CRn
,
593 (int) CRm
, (int) op2
);
595 /* read DCC into r0; then write coprocessor register from R0 */
596 retval
= dpm
->instr_write_data_r0(dpm
,
597 ARMV8_MSR_GP(op_code
, 0),
600 /* (void) */ dpm
->finish(dpm
);
604 /*----------------------------------------------------------------------*/
607 * Register access utilities
610 int armv8_dpm_modeswitch(struct arm_dpm
*dpm
, enum arm_mode mode
)
612 struct armv8_common
*armv8
= (struct armv8_common
*)dpm
->arm
->arch_info
;
613 int retval
= ERROR_OK
;
614 unsigned int target_el
;
615 enum arm_state core_state
;
618 /* restore previous mode */
619 if (mode
== ARM_MODE_ANY
) {
620 cpsr
= buf_get_u32(dpm
->arm
->cpsr
->value
, 0, 32);
622 LOG_DEBUG("restoring mode, cpsr = 0x%08"PRIx32
, cpsr
);
625 LOG_DEBUG("setting mode 0x%"PRIx32
, mode
);
627 /* else force to the specified mode */
628 if (is_arm_mode(mode
))
634 switch (cpsr
& 0x1f) {
646 * TODO: handle ARM_MODE_HYP
656 target_el
= (cpsr
>> 2) & 3;
659 if (target_el
> SYSTEM_CUREL_EL3
) {
660 LOG_ERROR("%s: Invalid target exception level %i", __func__
, target_el
);
664 LOG_DEBUG("target_el = %i, last_el = %i", target_el
, dpm
->last_el
);
665 if (target_el
> dpm
->last_el
) {
666 retval
= dpm
->instr_execute(dpm
,
667 armv8_opcode(armv8
, ARMV8_OPC_DCPS
) | target_el
);
669 /* DCPS clobbers registers just like an exception taken */
670 armv8_dpm_handle_exception(dpm
);
672 core_state
= armv8_dpm_get_core_state(dpm
);
673 if (core_state
!= ARM_STATE_AARCH64
) {
674 /* cannot do DRPS/ERET when already in EL0 */
675 if (dpm
->last_el
!= 0) {
676 /* load SPSR with the desired mode and execute DRPS */
677 LOG_DEBUG("SPSR = 0x%08"PRIx32
, cpsr
);
678 retval
= dpm
->instr_write_data_r0(dpm
,
679 ARMV8_MSR_GP_xPSR_T1(1, 0, 15), cpsr
);
680 if (retval
== ERROR_OK
)
681 retval
= dpm
->instr_execute(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DRPS
));
685 * need to execute multiple DRPS instructions until target_el
688 while (retval
== ERROR_OK
&& dpm
->last_el
!= target_el
) {
689 unsigned int cur_el
= dpm
->last_el
;
690 retval
= dpm
->instr_execute(dpm
, armv8_opcode(armv8
, ARMV8_OPC_DRPS
));
691 if (cur_el
== dpm
->last_el
) {
692 LOG_INFO("Cannot reach EL %i, SPSR corrupted?", target_el
);
698 /* On executing DRPS, DSPSR and DLR become UNKNOWN, mark them as dirty */
699 dpm
->arm
->cpsr
->dirty
= true;
700 dpm
->arm
->pc
->dirty
= true;
703 * re-evaluate the core state, we might be in Aarch32 state now
704 * we rely on dpm->dscr being up-to-date
706 core_state
= armv8_dpm_get_core_state(dpm
);
707 armv8_select_opcodes(armv8
, core_state
== ARM_STATE_AARCH64
);
708 armv8_select_reg_access(armv8
, core_state
== ARM_STATE_AARCH64
);
715 * Common register read, relies on armv8_select_reg_access() having been called.
717 static int dpmv8_read_reg(struct arm_dpm
*dpm
, struct reg
*r
, unsigned regnum
)
719 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
723 retval
= armv8
->read_reg_u64(armv8
, regnum
, &value_64
);
725 if (retval
== ERROR_OK
) {
728 buf_set_u64(r
->value
, 0, r
->size
, value_64
);
730 LOG_DEBUG("READ: %s, %16.8llx", r
->name
, (unsigned long long) value_64
);
732 LOG_DEBUG("READ: %s, %8.8x", r
->name
, (unsigned int) value_64
);
738 * Common register write, relies on armv8_select_reg_access() having been called.
740 static int dpmv8_write_reg(struct arm_dpm
*dpm
, struct reg
*r
, unsigned regnum
)
742 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
743 int retval
= ERROR_FAIL
;
746 value_64
= buf_get_u64(r
->value
, 0, r
->size
);
748 retval
= armv8
->write_reg_u64(armv8
, regnum
, value_64
);
749 if (retval
== ERROR_OK
) {
752 LOG_DEBUG("WRITE: %s, %16.8llx", r
->name
, (unsigned long long)value_64
);
754 LOG_DEBUG("WRITE: %s, %8.8x", r
->name
, (unsigned int)value_64
);
761 * Read basic registers of the the current context: R0 to R15, and CPSR;
762 * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
763 * In normal operation this is called on entry to halting debug state,
764 * possibly after some other operations supporting restore of debug state
765 * or making sure the CPU is fully idle (drain write buffer, etc).
767 int armv8_dpm_read_current_registers(struct arm_dpm
*dpm
)
769 struct arm
*arm
= dpm
->arm
;
770 struct armv8_common
*armv8
= (struct armv8_common
*)arm
->arch_info
;
771 struct reg_cache
*cache
;
776 retval
= dpm
->prepare(dpm
);
777 if (retval
!= ERROR_OK
)
780 cache
= arm
->core_cache
;
782 /* read R0 first (it's used for scratch), then CPSR */
783 r
= cache
->reg_list
+ 0;
785 retval
= dpmv8_read_reg(dpm
, r
, 0);
786 if (retval
!= ERROR_OK
)
791 /* read cpsr to r0 and get it back */
792 retval
= dpm
->instr_read_data_r0(dpm
,
793 armv8_opcode(armv8
, READ_REG_DSPSR
), &cpsr
);
794 if (retval
!= ERROR_OK
)
797 /* update core mode and state */
798 armv8_set_cpsr(arm
, cpsr
);
800 for (unsigned int i
= 1; i
< cache
->num_regs
; i
++) {
801 struct arm_reg
*arm_reg
;
803 r
= armv8_reg_current(arm
, i
);
808 * Only read registers that are available from the
809 * current EL (or core mode).
811 arm_reg
= r
->arch_info
;
812 if (arm_reg
->mode
!= ARM_MODE_ANY
&&
813 dpm
->last_el
!= armv8_curel_from_core_mode(arm_reg
->mode
))
816 retval
= dpmv8_read_reg(dpm
, r
, i
);
817 if (retval
!= ERROR_OK
)
827 /* Avoid needless I/O ... leave breakpoints and watchpoints alone
828 * unless they're removed, or need updating because of single-stepping
829 * or running debugger code.
831 static int dpmv8_maybe_update_bpwp(struct arm_dpm
*dpm
, bool bpwp
,
832 struct dpm_bpwp
*xp
, int *set_p
)
834 int retval
= ERROR_OK
;
841 /* removed or startup; we must disable it */
846 /* disabled, but we must set it */
847 xp
->dirty
= disable
= false;
852 /* set, but we must temporarily disable it */
853 xp
->dirty
= disable
= true;
858 retval
= dpm
->bpwp_disable(dpm
, xp
->number
);
860 retval
= dpm
->bpwp_enable(dpm
, xp
->number
,
861 xp
->address
, xp
->control
);
863 if (retval
!= ERROR_OK
)
864 LOG_ERROR("%s: can't %s HW %spoint %d",
865 disable
? "disable" : "enable",
866 target_name(dpm
->arm
->target
),
867 (xp
->number
< 16) ? "break" : "watch",
873 static int dpmv8_add_breakpoint(struct target
*target
, struct breakpoint
*bp
);
876 * Writes all modified core registers for all processor modes. In normal
877 * operation this is called on exit from halting debug state.
879 * @param dpm: represents the processor
880 * @param bpwp: true ensures breakpoints and watchpoints are set,
881 * false ensures they are cleared
883 int armv8_dpm_write_dirty_registers(struct arm_dpm
*dpm
, bool bpwp
)
885 struct arm
*arm
= dpm
->arm
;
886 struct reg_cache
*cache
= arm
->core_cache
;
889 retval
= dpm
->prepare(dpm
);
890 if (retval
!= ERROR_OK
)
893 /* If we're managing hardware breakpoints for this core, enable
894 * or disable them as requested.
896 * REVISIT We don't yet manage them for ANY cores. Eventually
897 * we should be able to assume we handle them; but until then,
898 * cope with the hand-crafted breakpoint code.
900 if (arm
->target
->type
->add_breakpoint
== dpmv8_add_breakpoint
) {
901 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
902 struct dpm_bp
*dbp
= dpm
->dbp
+ i
;
903 struct breakpoint
*bp
= dbp
->bp
;
905 retval
= dpmv8_maybe_update_bpwp(dpm
, bpwp
, &dbp
->bpwp
,
906 bp
? &bp
->set
: NULL
);
907 if (retval
!= ERROR_OK
)
912 /* enable/disable watchpoints */
913 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
914 struct dpm_wp
*dwp
= dpm
->dwp
+ i
;
915 struct watchpoint
*wp
= dwp
->wp
;
917 retval
= dpmv8_maybe_update_bpwp(dpm
, bpwp
, &dwp
->bpwp
,
918 wp
? &wp
->set
: NULL
);
919 if (retval
!= ERROR_OK
)
923 /* NOTE: writes to breakpoint and watchpoint registers might
924 * be queued, and need (efficient/batched) flushing later.
927 /* Restore original core mode and state */
928 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
929 if (retval
!= ERROR_OK
)
932 /* check everything except our scratch register R0 */
933 for (unsigned i
= 1; i
< cache
->num_regs
; i
++) {
936 /* skip PC and CPSR */
937 if (i
== ARMV8_PC
|| i
== ARMV8_xPSR
)
940 if (!cache
->reg_list
[i
].valid
)
943 if (!cache
->reg_list
[i
].dirty
)
946 /* skip all registers not on the current EL */
947 r
= cache
->reg_list
[i
].arch_info
;
948 if (r
->mode
!= ARM_MODE_ANY
&&
949 dpm
->last_el
!= armv8_curel_from_core_mode(r
->mode
))
952 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[i
], i
);
953 if (retval
!= ERROR_OK
)
957 /* flush CPSR and PC */
958 if (retval
== ERROR_OK
)
959 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[ARMV8_xPSR
], ARMV8_xPSR
);
960 if (retval
== ERROR_OK
)
961 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[ARMV8_PC
], ARMV8_PC
);
962 /* flush R0 -- it's *very* dirty by now */
963 if (retval
== ERROR_OK
)
964 retval
= dpmv8_write_reg(dpm
, &cache
->reg_list
[0], 0);
965 if (retval
== ERROR_OK
)
966 dpm
->instr_cpsr_sync(dpm
);
973 * Standard ARM register accessors ... there are three methods
974 * in "struct arm", to support individual read/write and bulk read
978 static int armv8_dpm_read_core_reg(struct target
*target
, struct reg
*r
,
979 int regnum
, enum arm_mode mode
)
981 struct arm
*arm
= target_to_arm(target
);
982 struct arm_dpm
*dpm
= target_to_arm(target
)->dpm
;
984 int max
= arm
->core_cache
->num_regs
;
986 if (regnum
< 0 || regnum
>= max
)
987 return ERROR_COMMAND_SYNTAX_ERROR
;
990 * REVISIT what happens if we try to read SPSR in a core mode
991 * which has no such register?
993 retval
= dpm
->prepare(dpm
);
994 if (retval
!= ERROR_OK
)
997 retval
= dpmv8_read_reg(dpm
, r
, regnum
);
998 if (retval
!= ERROR_OK
)
1002 /* (void) */ dpm
->finish(dpm
);
1006 static int armv8_dpm_write_core_reg(struct target
*target
, struct reg
*r
,
1007 int regnum
, enum arm_mode mode
, uint8_t *value
)
1009 struct arm
*arm
= target_to_arm(target
);
1010 struct arm_dpm
*dpm
= target_to_arm(target
)->dpm
;
1012 int max
= arm
->core_cache
->num_regs
;
1014 if (regnum
< 0 || regnum
> max
)
1015 return ERROR_COMMAND_SYNTAX_ERROR
;
1017 /* REVISIT what happens if we try to write SPSR in a core mode
1018 * which has no such register?
1021 retval
= dpm
->prepare(dpm
);
1022 if (retval
!= ERROR_OK
)
1025 retval
= dpmv8_write_reg(dpm
, r
, regnum
);
1027 /* always clean up, regardless of error */
1033 static int armv8_dpm_full_context(struct target
*target
)
1035 struct arm
*arm
= target_to_arm(target
);
1036 struct arm_dpm
*dpm
= arm
->dpm
;
1037 struct reg_cache
*cache
= arm
->core_cache
;
1041 retval
= dpm
->prepare(dpm
);
1042 if (retval
!= ERROR_OK
)
1046 enum arm_mode mode
= ARM_MODE_ANY
;
1050 /* We "know" arm_dpm_read_current_registers() was called so
1051 * the unmapped registers (R0..R7, PC, AND CPSR) and some
1052 * view of R8..R14 are current. We also "know" oddities of
1053 * register mapping: special cases for R8..R12 and SPSR.
1055 * Pick some mode with unread registers and read them all.
1056 * Repeat until done.
1058 for (unsigned i
= 0; i
< cache
->num_regs
; i
++) {
1061 if (cache
->reg_list
[i
].valid
)
1063 r
= cache
->reg_list
[i
].arch_info
;
1065 /* may need to pick a mode and set CPSR */
1070 /* For regular (ARM_MODE_ANY) R8..R12
1071 * in case we've entered debug state
1072 * in FIQ mode we need to patch mode.
1074 if (mode
!= ARM_MODE_ANY
)
1075 retval
= armv8_dpm_modeswitch(dpm
, mode
);
1077 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_USR
);
1079 if (retval
!= ERROR_OK
)
1082 if (r
->mode
!= mode
)
1085 /* CPSR was read, so "R16" must mean SPSR */
1086 retval
= dpmv8_read_reg(dpm
,
1087 &cache
->reg_list
[i
],
1088 (r
->num
== 16) ? 17 : r
->num
);
1089 if (retval
!= ERROR_OK
)
1095 retval
= armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
1096 /* (void) */ dpm
->finish(dpm
);
1102 /*----------------------------------------------------------------------*/
1105 * Breakpoint and Watchpoint support.
1107 * Hardware {break,watch}points are usually left active, to minimize
1108 * debug entry/exit costs. When they are set or cleared, it's done in
1109 * batches. Also, DPM-conformant hardware can update debug registers
1110 * regardless of whether the CPU is running or halted ... though that
1111 * fact isn't currently leveraged.
1114 static int dpmv8_bpwp_setup(struct arm_dpm
*dpm
, struct dpm_bpwp
*xp
,
1115 uint32_t addr
, uint32_t length
)
1119 control
= (1 << 0) /* enable */
1120 | (3 << 1); /* both user and privileged access */
1122 /* Match 1, 2, or all 4 byte addresses in this word.
1124 * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP.
1125 * Support larger length, when addr is suitably aligned. In
1126 * particular, allow watchpoints on 8 byte "double" values.
1128 * REVISIT allow watchpoints on unaligned 2-bit values; and on
1129 * v7 hardware, unaligned 4-byte ones too.
1133 control
|= (1 << (addr
& 3)) << 5;
1136 /* require 2-byte alignment */
1138 control
|= (3 << (addr
& 2)) << 5;
1143 /* require 4-byte alignment */
1145 control
|= 0xf << 5;
1150 LOG_ERROR("unsupported {break,watch}point length/alignment");
1151 return ERROR_COMMAND_SYNTAX_ERROR
;
1154 /* other shared control bits:
1155 * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only)
1156 * bit 20 == 0 ... not linked to a context ID
1157 * bit 28:24 == 0 ... not ignoring N LSBs (v7 only)
1160 xp
->address
= addr
& ~3;
1161 xp
->control
= control
;
1164 LOG_DEBUG("BPWP: addr %8.8" PRIx32
", control %" PRIx32
", number %d",
1165 xp
->address
, control
, xp
->number
);
1167 /* hardware is updated in write_dirty_registers() */
1171 static int dpmv8_add_breakpoint(struct target
*target
, struct breakpoint
*bp
)
1173 struct arm
*arm
= target_to_arm(target
);
1174 struct arm_dpm
*dpm
= arm
->dpm
;
1175 int retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1178 return ERROR_COMMAND_SYNTAX_ERROR
;
1179 if (!dpm
->bpwp_enable
)
1182 /* FIXME we need a generic solution for software breakpoints. */
1183 if (bp
->type
== BKPT_SOFT
)
1184 LOG_DEBUG("using HW bkpt, not SW...");
1186 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
1187 if (!dpm
->dbp
[i
].bp
) {
1188 retval
= dpmv8_bpwp_setup(dpm
, &dpm
->dbp
[i
].bpwp
,
1189 bp
->address
, bp
->length
);
1190 if (retval
== ERROR_OK
)
1191 dpm
->dbp
[i
].bp
= bp
;
1199 static int dpmv8_remove_breakpoint(struct target
*target
, struct breakpoint
*bp
)
1201 struct arm
*arm
= target_to_arm(target
);
1202 struct arm_dpm
*dpm
= arm
->dpm
;
1203 int retval
= ERROR_COMMAND_SYNTAX_ERROR
;
1205 for (unsigned i
= 0; i
< dpm
->nbp
; i
++) {
1206 if (dpm
->dbp
[i
].bp
== bp
) {
1207 dpm
->dbp
[i
].bp
= NULL
;
1208 dpm
->dbp
[i
].bpwp
.dirty
= true;
1210 /* hardware is updated in write_dirty_registers() */
1219 static int dpmv8_watchpoint_setup(struct arm_dpm
*dpm
, unsigned index_t
,
1220 struct watchpoint
*wp
)
1223 struct dpm_wp
*dwp
= dpm
->dwp
+ index_t
;
1226 /* this hardware doesn't support data value matching or masking */
1227 if (wp
->value
|| wp
->mask
!= ~(uint32_t)0) {
1228 LOG_DEBUG("watchpoint values and masking not supported");
1229 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1232 retval
= dpmv8_bpwp_setup(dpm
, &dwp
->bpwp
, wp
->address
, wp
->length
);
1233 if (retval
!= ERROR_OK
)
1236 control
= dwp
->bpwp
.control
;
1248 dwp
->bpwp
.control
= control
;
1250 dpm
->dwp
[index_t
].wp
= wp
;
1255 static int dpmv8_add_watchpoint(struct target
*target
, struct watchpoint
*wp
)
1257 struct arm
*arm
= target_to_arm(target
);
1258 struct arm_dpm
*dpm
= arm
->dpm
;
1259 int retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1261 if (dpm
->bpwp_enable
) {
1262 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
1263 if (!dpm
->dwp
[i
].wp
) {
1264 retval
= dpmv8_watchpoint_setup(dpm
, i
, wp
);
1273 static int dpmv8_remove_watchpoint(struct target
*target
, struct watchpoint
*wp
)
1275 struct arm
*arm
= target_to_arm(target
);
1276 struct arm_dpm
*dpm
= arm
->dpm
;
1277 int retval
= ERROR_COMMAND_SYNTAX_ERROR
;
1279 for (unsigned i
= 0; i
< dpm
->nwp
; i
++) {
1280 if (dpm
->dwp
[i
].wp
== wp
) {
1281 dpm
->dwp
[i
].wp
= NULL
;
1282 dpm
->dwp
[i
].bpwp
.dirty
= true;
1284 /* hardware is updated in write_dirty_registers() */
1293 void armv8_dpm_report_wfar(struct arm_dpm
*dpm
, uint64_t addr
)
1295 switch (dpm
->arm
->core_state
) {
1297 case ARM_STATE_AARCH64
:
1300 case ARM_STATE_THUMB
:
1301 case ARM_STATE_THUMB_EE
:
1304 case ARM_STATE_JAZELLE
:
1308 LOG_DEBUG("Unknow core_state");
1315 * Handle exceptions taken in debug state. This happens mostly for memory
1316 * accesses that violated a MMU policy. Taking an exception while in debug
1317 * state clobbers certain state registers on the target exception level.
1318 * Just mark those registers dirty so that they get restored on resume.
1319 * This works both for Aarch32 and Aarch64 states.
1321 * This function must not perform any actions that trigger another exception
1322 * or a recursion will happen.
1324 void armv8_dpm_handle_exception(struct arm_dpm
*dpm
)
1326 struct armv8_common
*armv8
= dpm
->arm
->arch_info
;
1327 struct reg_cache
*cache
= dpm
->arm
->core_cache
;
1328 enum arm_state core_state
;
1333 static const int clobbered_regs_by_el
[3][5] = {
1334 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL1
, ARMV8_ESR_EL1
, ARMV8_SPSR_EL1
},
1335 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL2
, ARMV8_ESR_EL2
, ARMV8_SPSR_EL2
},
1336 { ARMV8_PC
, ARMV8_xPSR
, ARMV8_ELR_EL3
, ARMV8_ESR_EL3
, ARMV8_SPSR_EL3
},
1339 el
= (dpm
->dscr
>> 8) & 3;
1341 /* safety check, must not happen since EL0 cannot be a target for an exception */
1342 if (el
< SYSTEM_CUREL_EL1
|| el
> SYSTEM_CUREL_EL3
) {
1343 LOG_ERROR("%s: EL %i is invalid, DSCR corrupted?", __func__
, el
);
1347 /* Clear sticky error */
1348 mem_ap_write_u32(armv8
->debug_ap
,
1349 armv8
->debug_base
+ CPUV8_DBG_DRCR
, DRCR_CSE
);
1351 armv8
->read_reg_u64(armv8
, ARMV8_xPSR
, &dlr
);
1353 armv8
->read_reg_u64(armv8
, ARMV8_PC
, &dlr
);
1355 LOG_DEBUG("Exception taken to EL %i, DLR=0x%016"PRIx64
" DSPSR=0x%08"PRIx32
,
1358 /* mark all clobbered registers as dirty */
1359 for (int i
= 0; i
< 5; i
++)
1360 cache
->reg_list
[clobbered_regs_by_el
[el
-1][i
]].dirty
= true;
1363 * re-evaluate the core state, we might be in Aarch64 state now
1364 * we rely on dpm->dscr being up-to-date
1366 core_state
= armv8_dpm_get_core_state(dpm
);
1367 armv8_select_opcodes(armv8
, core_state
== ARM_STATE_AARCH64
);
1368 armv8_select_reg_access(armv8
, core_state
== ARM_STATE_AARCH64
);
1371 /*----------------------------------------------------------------------*/
1374 * Other debug and support utilities
1377 void armv8_dpm_report_dscr(struct arm_dpm
*dpm
, uint32_t dscr
)
1379 struct target
*target
= dpm
->arm
->target
;
1382 dpm
->last_el
= (dscr
>> 8) & 3;
1384 /* Examine debug reason */
1385 switch (DSCR_ENTRY(dscr
)) {
1386 /* FALL THROUGH -- assume a v6 core in abort mode */
1387 case DSCRV8_ENTRY_EXT_DEBUG
: /* EDBGRQ */
1388 target
->debug_reason
= DBG_REASON_DBGRQ
;
1390 case DSCRV8_ENTRY_HALT_STEP_EXECLU
: /* HALT step */
1391 case DSCRV8_ENTRY_HALT_STEP_NORMAL
: /* Halt step*/
1392 case DSCRV8_ENTRY_HALT_STEP
:
1393 target
->debug_reason
= DBG_REASON_SINGLESTEP
;
1395 case DSCRV8_ENTRY_HLT
: /* HLT instruction (software breakpoint) */
1396 case DSCRV8_ENTRY_BKPT
: /* SW BKPT (?) */
1397 case DSCRV8_ENTRY_RESET_CATCH
: /* Reset catch */
1398 case DSCRV8_ENTRY_OS_UNLOCK
: /*OS unlock catch*/
1399 case DSCRV8_ENTRY_EXCEPTION_CATCH
: /*exception catch*/
1400 case DSCRV8_ENTRY_SW_ACCESS_DBG
: /*SW access dbg register*/
1401 target
->debug_reason
= DBG_REASON_BREAKPOINT
;
1403 case DSCRV8_ENTRY_WATCHPOINT
: /* asynch watchpoint */
1404 target
->debug_reason
= DBG_REASON_WATCHPOINT
;
1407 target
->debug_reason
= DBG_REASON_UNDEFINED
;
1413 /*----------------------------------------------------------------------*/
1416 * Setup and management support.
1420 * Hooks up this DPM to its associated target; call only once.
1421 * Initially this only covers the register cache.
1423 * Oh, and watchpoints. Yeah.
1425 int armv8_dpm_setup(struct arm_dpm
*dpm
)
1427 struct arm
*arm
= dpm
->arm
;
1428 struct target
*target
= arm
->target
;
1429 struct reg_cache
*cache
;
1432 /* register access setup */
1433 arm
->full_context
= armv8_dpm_full_context
;
1434 arm
->read_core_reg
= armv8_dpm_read_core_reg
;
1435 arm
->write_core_reg
= armv8_dpm_write_core_reg
;
1437 if (arm
->core_cache
== NULL
) {
1438 cache
= armv8_build_reg_cache(target
);
1443 /* coprocessor access setup */
1444 arm
->mrc
= dpmv8_mrc
;
1445 arm
->mcr
= dpmv8_mcr
;
1446 arm
->mrs
= dpmv8_mrs
;
1447 arm
->msr
= dpmv8_msr
;
1449 dpm
->prepare
= dpmv8_dpm_prepare
;
1450 dpm
->finish
= dpmv8_dpm_finish
;
1452 dpm
->instr_execute
= dpmv8_instr_execute
;
1453 dpm
->instr_write_data_dcc
= dpmv8_instr_write_data_dcc
;
1454 dpm
->instr_write_data_dcc_64
= dpmv8_instr_write_data_dcc_64
;
1455 dpm
->instr_write_data_r0
= dpmv8_instr_write_data_r0
;
1456 dpm
->instr_write_data_r0_64
= dpmv8_instr_write_data_r0_64
;
1457 dpm
->instr_cpsr_sync
= dpmv8_instr_cpsr_sync
;
1459 dpm
->instr_read_data_dcc
= dpmv8_instr_read_data_dcc
;
1460 dpm
->instr_read_data_dcc_64
= dpmv8_instr_read_data_dcc_64
;
1461 dpm
->instr_read_data_r0
= dpmv8_instr_read_data_r0
;
1462 dpm
->instr_read_data_r0_64
= dpmv8_instr_read_data_r0_64
;
1464 dpm
->arm_reg_current
= armv8_reg_current
;
1466 /* dpm->bpwp_enable = dpmv8_bpwp_enable; */
1467 dpm
->bpwp_disable
= dpmv8_bpwp_disable
;
1469 /* breakpoint setup -- optional until it works everywhere */
1470 if (!target
->type
->add_breakpoint
) {
1471 target
->type
->add_breakpoint
= dpmv8_add_breakpoint
;
1472 target
->type
->remove_breakpoint
= dpmv8_remove_breakpoint
;
1475 /* watchpoint setup */
1476 target
->type
->add_watchpoint
= dpmv8_add_watchpoint
;
1477 target
->type
->remove_watchpoint
= dpmv8_remove_watchpoint
;
1479 /* FIXME add vector catch support */
1481 dpm
->nbp
= 1 + ((dpm
->didr
>> 12) & 0xf);
1482 dpm
->dbp
= calloc(dpm
->nbp
, sizeof *dpm
->dbp
);
1484 dpm
->nwp
= 1 + ((dpm
->didr
>> 20) & 0xf);
1485 dpm
->dwp
= calloc(dpm
->nwp
, sizeof *dpm
->dwp
);
1487 if (!dpm
->dbp
|| !dpm
->dwp
) {
1493 LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
1494 target_name(target
), dpm
->nbp
, dpm
->nwp
);
1496 /* REVISIT ... and some of those breakpoints could match
1497 * execution context IDs...
1504 * Reinitializes DPM state at the beginning of a new debug session
1505 * or after a reset which may have affected the debug module.
1507 int armv8_dpm_initialize(struct arm_dpm
*dpm
)
1509 /* Disable all breakpoints and watchpoints at startup. */
1510 if (dpm
->bpwp_disable
) {
1513 for (i
= 0; i
< dpm
->nbp
; i
++) {
1514 dpm
->dbp
[i
].bpwp
.number
= i
;
1515 (void) dpm
->bpwp_disable(dpm
, i
);
1517 for (i
= 0; i
< dpm
->nwp
; i
++) {
1518 dpm
->dwp
[i
].bpwp
.number
= 16 + i
;
1519 (void) dpm
->bpwp_disable(dpm
, 16 + i
);
1522 LOG_WARNING("%s: can't disable breakpoints and watchpoints",
1523 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)