1 /***************************************************************************
2 * Copyright (C) 2015 by David Ung *
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. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 ***************************************************************************/
23 #include <helper/replacements.h>
26 #include "arm_disassembler.h"
29 #include <helper/binarybuffer.h>
30 #include <helper/command.h>
36 #include "armv8_opcodes.h"
38 #include "target_type.h"
40 #define __unused __attribute__((unused))
42 static const char * const armv8_state_strings
[] = {
43 "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
49 } armv8_mode_data
[] = {
50 /* These special modes are currently only supported
51 * by ARMv6M and ARMv7M profiles */
102 .psr
= ARMV8_64_EL3H
,
106 /** Map PSR mode bits to the name of an ARM processor operating mode. */
107 const char *armv8_mode_name(unsigned psr_mode
)
109 for (unsigned i
= 0; i
< ARRAY_SIZE(armv8_mode_data
); i
++) {
110 if (armv8_mode_data
[i
].psr
== psr_mode
)
111 return armv8_mode_data
[i
].name
;
113 LOG_ERROR("unrecognized psr mode: %#02x", psr_mode
);
114 return "UNRECOGNIZED";
117 int armv8_mode_to_number(enum arm_mode mode
)
121 /* map MODE_ANY to user mode */
154 LOG_ERROR("invalid mode value encountered %d", mode
);
159 static int armv8_read_reg(struct armv8_common
*armv8
, int regnum
, uint64_t *regval
)
161 struct arm_dpm
*dpm
= &armv8
->dpm
;
168 retval
= dpm
->instr_read_data_dcc_64(dpm
,
169 ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0
, regnum
), &value_64
);
172 retval
= dpm
->instr_read_data_r0_64(dpm
,
173 ARMV8_MOVFSP_64(0), &value_64
);
176 retval
= dpm
->instr_read_data_r0_64(dpm
,
177 ARMV8_MRS_DLR(0), &value_64
);
180 retval
= dpm
->instr_read_data_r0(dpm
,
181 ARMV8_MRS_DSPSR(0), &value
);
185 retval
= dpm
->instr_read_data_r0_64(dpm
,
186 ARMV8_MRS(SYSTEM_ELR_EL1
, 0), &value_64
);
189 retval
= dpm
->instr_read_data_r0_64(dpm
,
190 ARMV8_MRS(SYSTEM_ELR_EL2
, 0), &value_64
);
193 retval
= dpm
->instr_read_data_r0_64(dpm
,
194 ARMV8_MRS(SYSTEM_ELR_EL3
, 0), &value_64
);
197 retval
= dpm
->instr_read_data_r0(dpm
,
198 ARMV8_MRS(SYSTEM_ESR_EL1
, 0), &value
);
202 retval
= dpm
->instr_read_data_r0(dpm
,
203 ARMV8_MRS(SYSTEM_ESR_EL2
, 0), &value
);
207 retval
= dpm
->instr_read_data_r0(dpm
,
208 ARMV8_MRS(SYSTEM_ESR_EL3
, 0), &value
);
212 retval
= dpm
->instr_read_data_r0(dpm
,
213 ARMV8_MRS(SYSTEM_SPSR_EL1
, 0), &value
);
217 retval
= dpm
->instr_read_data_r0(dpm
,
218 ARMV8_MRS(SYSTEM_SPSR_EL2
, 0), &value
);
222 retval
= dpm
->instr_read_data_r0(dpm
,
223 ARMV8_MRS(SYSTEM_SPSR_EL3
, 0), &value
);
231 if (retval
== ERROR_OK
&& regval
!= NULL
)
237 static int armv8_write_reg(struct armv8_common
*armv8
, int regnum
, uint64_t value_64
)
239 struct arm_dpm
*dpm
= &armv8
->dpm
;
245 retval
= dpm
->instr_write_data_dcc_64(dpm
,
246 ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0
, regnum
),
250 retval
= dpm
->instr_write_data_r0_64(dpm
,
255 retval
= dpm
->instr_write_data_r0_64(dpm
,
261 retval
= dpm
->instr_write_data_r0(dpm
,
265 /* registers clobbered by taking exception in debug state */
267 retval
= dpm
->instr_write_data_r0_64(dpm
,
268 ARMV8_MSR_GP(SYSTEM_ELR_EL1
, 0), value_64
);
271 retval
= dpm
->instr_write_data_r0_64(dpm
,
272 ARMV8_MSR_GP(SYSTEM_ELR_EL2
, 0), value_64
);
275 retval
= dpm
->instr_write_data_r0_64(dpm
,
276 ARMV8_MSR_GP(SYSTEM_ELR_EL3
, 0), value_64
);
280 retval
= dpm
->instr_write_data_r0(dpm
,
281 ARMV8_MSR_GP(SYSTEM_ESR_EL1
, 0), value
);
285 retval
= dpm
->instr_write_data_r0(dpm
,
286 ARMV8_MSR_GP(SYSTEM_ESR_EL2
, 0), value
);
290 retval
= dpm
->instr_write_data_r0(dpm
,
291 ARMV8_MSR_GP(SYSTEM_ESR_EL3
, 0), value
);
295 retval
= dpm
->instr_write_data_r0(dpm
,
296 ARMV8_MSR_GP(SYSTEM_SPSR_EL1
, 0), value
);
300 retval
= dpm
->instr_write_data_r0(dpm
,
301 ARMV8_MSR_GP(SYSTEM_SPSR_EL2
, 0), value
);
305 retval
= dpm
->instr_write_data_r0(dpm
,
306 ARMV8_MSR_GP(SYSTEM_SPSR_EL3
, 0), value
);
316 static int armv8_read_reg32(struct armv8_common
*armv8
, int regnum
, uint64_t *regval
)
318 struct arm_dpm
*dpm
= &armv8
->dpm
;
323 case ARMV8_R0
... ARMV8_R14
:
324 /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
325 retval
= dpm
->instr_read_data_dcc(dpm
,
326 ARMV4_5_MCR(14, 0, regnum
, 0, 5, 0),
330 retval
= dpm
->instr_read_data_dcc(dpm
,
331 ARMV4_5_MCR(14, 0, 13, 0, 5, 0),
335 retval
= dpm
->instr_read_data_r0(dpm
,
340 retval
= dpm
->instr_read_data_r0(dpm
,
344 case ARMV8_ELR_EL1
: /* mapped to LR_svc */
345 retval
= dpm
->instr_read_data_dcc(dpm
,
346 ARMV4_5_MCR(14, 0, 14, 0, 5, 0),
349 case ARMV8_ELR_EL2
: /* mapped to ELR_hyp */
350 retval
= dpm
->instr_read_data_r0(dpm
,
351 ARMV8_MRS_T1(0, 14, 0, 1),
354 case ARMV8_ELR_EL3
: /* mapped to LR_mon */
355 retval
= dpm
->instr_read_data_dcc(dpm
,
356 ARMV4_5_MCR(14, 0, 14, 0, 5, 0),
359 case ARMV8_ESR_EL1
: /* mapped to DFSR */
360 retval
= dpm
->instr_read_data_r0(dpm
,
361 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
364 case ARMV8_ESR_EL2
: /* mapped to HSR */
365 retval
= dpm
->instr_read_data_r0(dpm
,
366 ARMV4_5_MRC(15, 4, 0, 5, 2, 0),
369 case ARMV8_ESR_EL3
: /* FIXME: no equivalent in aarch32? */
372 case ARMV8_SPSR_EL1
: /* mapped to SPSR_svc */
373 retval
= dpm
->instr_read_data_r0(dpm
,
374 ARMV8_MRS_xPSR_T1(1, 0),
377 case ARMV8_SPSR_EL2
: /* mapped to SPSR_hyp */
378 retval
= dpm
->instr_read_data_r0(dpm
,
379 ARMV8_MRS_xPSR_T1(1, 0),
382 case ARMV8_SPSR_EL3
: /* mapped to SPSR_mon */
383 retval
= dpm
->instr_read_data_r0(dpm
,
384 ARMV8_MRS_xPSR_T1(1, 0),
392 if (retval
== ERROR_OK
&& regval
!= NULL
)
398 static int armv8_write_reg32(struct armv8_common
*armv8
, int regnum
, uint64_t value
)
400 struct arm_dpm
*dpm
= &armv8
->dpm
;
404 case ARMV8_R0
... ARMV8_R14
:
405 /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */
406 retval
= dpm
->instr_write_data_dcc(dpm
,
407 ARMV4_5_MRC(14, 0, regnum
, 0, 5, 0), value
);
410 retval
= dpm
->instr_write_data_dcc(dpm
,
411 ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value
);
414 * read r0 from DCC; then "MOV pc, r0" */
415 retval
= dpm
->instr_write_data_r0(dpm
,
416 ARMV8_MCR_DLR(0), value
);
418 case ARMV8_xPSR
: /* CPSR */
419 /* read r0 from DCC, then "MCR r0, DSPSR" */
420 retval
= dpm
->instr_write_data_r0(dpm
,
421 ARMV8_MCR_DSPSR(0), value
);
423 case ARMV8_ELR_EL1
: /* mapped to LR_svc */
424 retval
= dpm
->instr_write_data_dcc(dpm
,
425 ARMV4_5_MRC(14, 0, 14, 0, 5, 0),
428 case ARMV8_ELR_EL2
: /* mapped to ELR_hyp */
429 retval
= dpm
->instr_write_data_r0(dpm
,
430 ARMV8_MSR_GP_T1(0, 14, 0, 1),
433 case ARMV8_ELR_EL3
: /* mapped to LR_mon */
434 retval
= dpm
->instr_write_data_dcc(dpm
,
435 ARMV4_5_MRC(14, 0, 14, 0, 5, 0),
438 case ARMV8_ESR_EL1
: /* mapped to DFSR */
439 retval
= dpm
->instr_write_data_r0(dpm
,
440 ARMV4_5_MCR(15, 0, 0, 5, 0, 0),
443 case ARMV8_ESR_EL2
: /* mapped to HSR */
444 retval
= dpm
->instr_write_data_r0(dpm
,
445 ARMV4_5_MCR(15, 4, 0, 5, 2, 0),
448 case ARMV8_ESR_EL3
: /* FIXME: no equivalent in aarch32? */
451 case ARMV8_SPSR_EL1
: /* mapped to SPSR_svc */
452 retval
= dpm
->instr_write_data_r0(dpm
,
453 ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
456 case ARMV8_SPSR_EL2
: /* mapped to SPSR_hyp */
457 retval
= dpm
->instr_write_data_r0(dpm
,
458 ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
461 case ARMV8_SPSR_EL3
: /* mapped to SPSR_mon */
462 retval
= dpm
->instr_write_data_r0(dpm
,
463 ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
475 void armv8_select_reg_access(struct armv8_common
*armv8
, bool is_aarch64
)
478 armv8
->read_reg_u64
= armv8_read_reg
;
479 armv8
->write_reg_u64
= armv8_write_reg
;
481 armv8
->read_reg_u64
= armv8_read_reg32
;
482 armv8
->write_reg_u64
= armv8_write_reg32
;
486 /* retrieve core id cluster id */
487 int armv8_read_mpidr(struct armv8_common
*armv8
)
489 int retval
= ERROR_FAIL
;
490 struct arm_dpm
*dpm
= armv8
->arm
.dpm
;
493 retval
= dpm
->prepare(dpm
);
494 if (retval
!= ERROR_OK
)
497 retval
= dpm
->instr_read_data_r0(dpm
, armv8_opcode(armv8
, READ_REG_MPIDR
), &mpidr
);
498 if (retval
!= ERROR_OK
)
501 armv8
->multi_processor_system
= (mpidr
>> 30) & 1;
502 armv8
->cluster_id
= (mpidr
>> 8) & 0xf;
503 armv8
->cpu_id
= mpidr
& 0x3;
504 LOG_INFO("%s cluster %x core %x %s", target_name(armv8
->arm
.target
),
507 armv8
->multi_processor_system
== 0 ? "multi core" : "single core");
509 LOG_ERROR("mpidr not in multiprocessor format");
517 * Configures host-side ARM records to reflect the specified CPSR.
518 * Later, code can use arm_reg_current() to map register numbers
519 * according to how they are exposed by this mode.
521 void armv8_set_cpsr(struct arm
*arm
, uint32_t cpsr
)
523 uint32_t mode
= cpsr
& 0x1F;
525 /* NOTE: this may be called very early, before the register
526 * cache is set up. We can't defend against many errors, in
527 * particular against CPSRs that aren't valid *here* ...
530 buf_set_u32(arm
->cpsr
->value
, 0, 32, cpsr
);
531 arm
->cpsr
->valid
= 1;
532 arm
->cpsr
->dirty
= 0;
535 /* Older ARMs won't have the J bit */
536 enum arm_state state
= 0xFF;
538 if (((cpsr
& 0x10) >> 4) == 0) {
539 state
= ARM_STATE_AARCH64
;
541 if (cpsr
& (1 << 5)) { /* T */
542 if (cpsr
& (1 << 24)) { /* J */
543 LOG_WARNING("ThumbEE -- incomplete support");
544 state
= ARM_STATE_THUMB_EE
;
546 state
= ARM_STATE_THUMB
;
548 if (cpsr
& (1 << 24)) { /* J */
549 LOG_ERROR("Jazelle state handling is BROKEN!");
550 state
= ARM_STATE_JAZELLE
;
552 state
= ARM_STATE_ARM
;
555 arm
->core_state
= state
;
556 if (arm
->core_state
== ARM_STATE_AARCH64
)
557 arm
->core_mode
= (mode
<< 4) | 0xf;
559 arm
->core_mode
= mode
;
561 LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr
,
562 armv8_mode_name(arm
->core_mode
),
563 armv8_state_strings
[arm
->core_state
]);
566 static void armv8_show_fault_registers32(struct armv8_common
*armv8
)
568 uint32_t dfsr
, ifsr
, dfar
, ifar
;
569 struct arm_dpm
*dpm
= armv8
->arm
.dpm
;
572 retval
= dpm
->prepare(dpm
);
573 if (retval
!= ERROR_OK
)
576 /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */
578 /* c5/c0 - {data, instruction} fault status registers */
579 retval
= dpm
->instr_read_data_r0(dpm
,
580 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
582 if (retval
!= ERROR_OK
)
585 retval
= dpm
->instr_read_data_r0(dpm
,
586 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
588 if (retval
!= ERROR_OK
)
591 /* c6/c0 - {data, instruction} fault address registers */
592 retval
= dpm
->instr_read_data_r0(dpm
,
593 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
595 if (retval
!= ERROR_OK
)
598 retval
= dpm
->instr_read_data_r0(dpm
,
599 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
601 if (retval
!= ERROR_OK
)
604 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
605 ", DFAR: %8.8" PRIx32
, dfsr
, dfar
);
606 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
607 ", IFAR: %8.8" PRIx32
, ifsr
, ifar
);
610 /* (void) */ dpm
->finish(dpm
);
613 static __unused
void armv8_show_fault_registers(struct target
*target
)
615 struct armv8_common
*armv8
= target_to_armv8(target
);
617 if (armv8
->arm
.core_state
!= ARM_STATE_AARCH64
)
618 armv8_show_fault_registers32(armv8
);
621 static uint8_t armv8_pa_size(uint32_t ps
)
644 LOG_INFO("Unknow physicall address size");
650 static __unused
int armv8_read_ttbcr32(struct target
*target
)
652 struct armv8_common
*armv8
= target_to_armv8(target
);
653 struct arm_dpm
*dpm
= armv8
->arm
.dpm
;
654 uint32_t ttbcr
, ttbcr_n
;
655 int retval
= dpm
->prepare(dpm
);
656 if (retval
!= ERROR_OK
)
658 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
659 retval
= dpm
->instr_read_data_r0(dpm
,
660 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
662 if (retval
!= ERROR_OK
)
665 LOG_DEBUG("ttbcr %" PRIx32
, ttbcr
);
667 ttbcr_n
= ttbcr
& 0x7;
668 armv8
->armv8_mmu
.ttbcr
= ttbcr
;
671 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
672 * document # ARM DDI 0406C
674 armv8
->armv8_mmu
.ttbr_range
[0] = 0xffffffff >> ttbcr_n
;
675 armv8
->armv8_mmu
.ttbr_range
[1] = 0xffffffff;
676 armv8
->armv8_mmu
.ttbr_mask
[0] = 0xffffffff << (14 - ttbcr_n
);
677 armv8
->armv8_mmu
.ttbr_mask
[1] = 0xffffffff << 14;
679 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32
" ttbr1_mask %" PRIx32
,
680 (ttbcr_n
!= 0) ? "used" : "not used",
681 armv8
->armv8_mmu
.ttbr_mask
[0],
682 armv8
->armv8_mmu
.ttbr_mask
[1]);
689 static __unused
int armv8_read_ttbcr(struct target
*target
)
691 struct armv8_common
*armv8
= target_to_armv8(target
);
692 struct arm_dpm
*dpm
= armv8
->arm
.dpm
;
693 struct arm
*arm
= &armv8
->arm
;
697 int retval
= dpm
->prepare(dpm
);
698 if (retval
!= ERROR_OK
)
701 /* claaer ttrr1_used and ttbr0_mask */
702 memset(&armv8
->armv8_mmu
.ttbr1_used
, 0, sizeof(armv8
->armv8_mmu
.ttbr1_used
));
703 memset(&armv8
->armv8_mmu
.ttbr0_mask
, 0, sizeof(armv8
->armv8_mmu
.ttbr0_mask
));
705 switch (armv8_curel_from_core_mode(arm
->core_mode
)) {
706 case SYSTEM_CUREL_EL3
:
707 retval
= dpm
->instr_read_data_r0(dpm
,
708 ARMV8_MRS(SYSTEM_TCR_EL3
, 0),
710 retval
+= dpm
->instr_read_data_r0_64(dpm
,
711 ARMV8_MRS(SYSTEM_TTBR0_EL3
, 0),
713 if (retval
!= ERROR_OK
)
715 armv8
->va_size
= 64 - (ttbcr
& 0x3F);
716 armv8
->pa_size
= armv8_pa_size((ttbcr
>> 16) & 7);
717 armv8
->page_size
= (ttbcr
>> 14) & 3;
719 case SYSTEM_CUREL_EL2
:
720 retval
= dpm
->instr_read_data_r0(dpm
,
721 ARMV8_MRS(SYSTEM_TCR_EL2
, 0),
723 retval
+= dpm
->instr_read_data_r0_64(dpm
,
724 ARMV8_MRS(SYSTEM_TTBR0_EL2
, 0),
726 if (retval
!= ERROR_OK
)
728 armv8
->va_size
= 64 - (ttbcr
& 0x3F);
729 armv8
->pa_size
= armv8_pa_size((ttbcr
>> 16) & 7);
730 armv8
->page_size
= (ttbcr
>> 14) & 3;
732 case SYSTEM_CUREL_EL0
:
733 armv8_dpm_modeswitch(dpm
, ARMV8_64_EL1H
);
735 case SYSTEM_CUREL_EL1
:
736 retval
= dpm
->instr_read_data_r0_64(dpm
,
737 ARMV8_MRS(SYSTEM_TCR_EL1
, 0),
739 armv8
->va_size
= 64 - (ttbcr_64
& 0x3F);
740 armv8
->pa_size
= armv8_pa_size((ttbcr_64
>> 32) & 7);
741 armv8
->page_size
= (ttbcr_64
>> 14) & 3;
742 armv8
->armv8_mmu
.ttbr1_used
= (((ttbcr_64
>> 16) & 0x3F) != 0) ? 1 : 0;
743 armv8
->armv8_mmu
.ttbr0_mask
= 0x0000FFFFFFFFFFFF;
744 retval
+= dpm
->instr_read_data_r0_64(dpm
,
745 ARMV8_MRS(SYSTEM_TTBR0_EL1
| (armv8
->armv8_mmu
.ttbr1_used
), 0),
747 if (retval
!= ERROR_OK
)
751 LOG_ERROR("unknow core state");
755 if (retval
!= ERROR_OK
)
758 if (armv8
->armv8_mmu
.ttbr1_used
== 1)
759 LOG_INFO("TTBR0 access above %" PRIx64
, (uint64_t)(armv8
->armv8_mmu
.ttbr0_mask
));
762 armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
767 /* method adapted to cortex A : reused arm v4 v5 method*/
768 int armv8_mmu_translate_va(struct target
*target
, target_addr_t va
, target_addr_t
*val
)
773 /* V8 method VA TO PA */
774 int armv8_mmu_translate_va_pa(struct target
*target
, target_addr_t va
,
775 target_addr_t
*val
, int meminfo
)
777 struct armv8_common
*armv8
= target_to_armv8(target
);
778 struct arm
*arm
= target_to_arm(target
);
779 struct arm_dpm
*dpm
= &armv8
->dpm
;
780 enum arm_mode target_mode
= ARM_MODE_ANY
;
785 static const char * const shared_name
[] = {
786 "Non-", "UNDEFINED ", "Outer ", "Inner "
789 static const char * const secure_name
[] = {
790 "Secure", "Not Secure"
793 retval
= dpm
->prepare(dpm
);
794 if (retval
!= ERROR_OK
)
797 switch (armv8_curel_from_core_mode(arm
->core_mode
)) {
798 case SYSTEM_CUREL_EL0
:
799 instr
= ARMV8_SYS(SYSTEM_ATS12E0R
, 0);
800 /* can only execute instruction at EL2 */
801 target_mode
= ARMV8_64_EL2H
;
803 case SYSTEM_CUREL_EL1
:
804 instr
= ARMV8_SYS(SYSTEM_ATS12E1R
, 0);
805 /* can only execute instruction at EL2 */
806 target_mode
= ARMV8_64_EL2H
;
808 case SYSTEM_CUREL_EL2
:
809 instr
= ARMV8_SYS(SYSTEM_ATS1E2R
, 0);
811 case SYSTEM_CUREL_EL3
:
812 instr
= ARMV8_SYS(SYSTEM_ATS1E3R
, 0);
819 if (target_mode
!= ARM_MODE_ANY
)
820 armv8_dpm_modeswitch(dpm
, target_mode
);
822 /* write VA to R0 and execute translation instruction */
823 retval
= dpm
->instr_write_data_r0_64(dpm
, instr
, (uint64_t)va
);
824 /* read result from PAR_EL1 */
825 if (retval
== ERROR_OK
)
826 retval
= dpm
->instr_read_data_r0_64(dpm
, ARMV8_MRS(SYSTEM_PAR_EL1
, 0), &par
);
828 /* switch back to saved PE mode */
829 if (target_mode
!= ARM_MODE_ANY
)
830 armv8_dpm_modeswitch(dpm
, ARM_MODE_ANY
);
834 if (retval
!= ERROR_OK
)
838 LOG_ERROR("Address translation failed at stage %i, FST=%x, PTW=%i",
839 ((int)(par
>> 9) & 1)+1, (int)(par
>> 1) & 0x3f, (int)(par
>> 8) & 1);
844 *val
= (par
& 0xFFFFFFFFF000UL
) | (va
& 0xFFF);
846 int SH
= (par
>> 7) & 3;
847 int NS
= (par
>> 9) & 1;
848 int ATTR
= (par
>> 56) & 0xFF;
850 char *memtype
= (ATTR
& 0xF0) == 0 ? "Device Memory" : "Normal Memory";
852 LOG_USER("%sshareable, %s",
853 shared_name
[SH
], secure_name
[NS
]);
854 LOG_USER("%s", memtype
);
861 int armv8_handle_cache_info_command(struct command_context
*cmd_ctx
,
862 struct armv8_cache_common
*armv8_cache
)
864 if (armv8_cache
->info
== -1) {
865 command_print(cmd_ctx
, "cache not yet identified");
869 if (armv8_cache
->display_cache_info
)
870 armv8_cache
->display_cache_info(cmd_ctx
, armv8_cache
);
874 int armv8_init_arch_info(struct target
*target
, struct armv8_common
*armv8
)
876 struct arm
*arm
= &armv8
->arm
;
877 arm
->arch_info
= armv8
;
878 target
->arch_info
= &armv8
->arm
;
879 /* target is useful in all function arm v4 5 compatible */
880 armv8
->arm
.target
= target
;
881 armv8
->arm
.common_magic
= ARM_COMMON_MAGIC
;
882 armv8
->common_magic
= ARMV8_COMMON_MAGIC
;
884 armv8
->armv8_mmu
.armv8_cache
.l2_cache
= NULL
;
885 armv8
->armv8_mmu
.armv8_cache
.info
= -1;
886 armv8
->armv8_mmu
.armv8_cache
.flush_all_data_cache
= NULL
;
887 armv8
->armv8_mmu
.armv8_cache
.display_cache_info
= NULL
;
891 int armv8_aarch64_state(struct target
*target
)
893 struct arm
*arm
= target_to_arm(target
);
895 if (arm
->common_magic
!= ARM_COMMON_MAGIC
) {
896 LOG_ERROR("BUG: called for a non-ARM target");
900 LOG_USER("target halted in %s state due to %s, current mode: %s\n"
901 "cpsr: 0x%8.8" PRIx32
" pc: 0x%" PRIx64
"%s",
902 armv8_state_strings
[arm
->core_state
],
903 debug_reason_name(target
),
904 armv8_mode_name(arm
->core_mode
),
905 buf_get_u32(arm
->cpsr
->value
, 0, 32),
906 buf_get_u64(arm
->pc
->value
, 0, 64),
907 arm
->is_semihosting
? ", semihosting" : "");
912 int armv8_arch_state(struct target
*target
)
914 static const char * const state
[] = {
915 "disabled", "enabled"
918 struct armv8_common
*armv8
= target_to_armv8(target
);
919 struct arm
*arm
= &armv8
->arm
;
921 if (armv8
->common_magic
!= ARMV8_COMMON_MAGIC
) {
922 LOG_ERROR("BUG: called for a non-Armv8 target");
923 return ERROR_COMMAND_SYNTAX_ERROR
;
926 if (arm
->core_state
== ARM_STATE_AARCH64
)
927 armv8_aarch64_state(target
);
929 arm_arch_state(target
);
931 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
932 state
[armv8
->armv8_mmu
.mmu_enabled
],
933 state
[armv8
->armv8_mmu
.armv8_cache
.d_u_cache_enabled
],
934 state
[armv8
->armv8_mmu
.armv8_cache
.i_cache_enabled
]);
936 if (arm
->core_mode
== ARM_MODE_ABT
)
937 armv8_show_fault_registers(target
);
939 if (target
->debug_reason
== DBG_REASON_WATCHPOINT
)
940 LOG_USER("Watchpoint triggered at PC %#08x",
941 (unsigned) armv8
->dpm
.wp_pc
);
946 static const struct {
955 { ARMV8_R0
, "x0", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
956 { ARMV8_R1
, "x1", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
957 { ARMV8_R2
, "x2", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
958 { ARMV8_R3
, "x3", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
959 { ARMV8_R4
, "x4", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
960 { ARMV8_R5
, "x5", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
961 { ARMV8_R6
, "x6", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
962 { ARMV8_R7
, "x7", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
963 { ARMV8_R8
, "x8", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
964 { ARMV8_R9
, "x9", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
965 { ARMV8_R10
, "x10", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
966 { ARMV8_R11
, "x11", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
967 { ARMV8_R12
, "x12", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
968 { ARMV8_R13
, "x13", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
969 { ARMV8_R14
, "x14", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
970 { ARMV8_R15
, "x15", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
971 { ARMV8_R16
, "x16", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
972 { ARMV8_R17
, "x17", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
973 { ARMV8_R18
, "x18", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
974 { ARMV8_R19
, "x19", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
975 { ARMV8_R20
, "x20", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
976 { ARMV8_R21
, "x21", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
977 { ARMV8_R22
, "x22", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
978 { ARMV8_R23
, "x23", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
979 { ARMV8_R24
, "x24", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
980 { ARMV8_R25
, "x25", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
981 { ARMV8_R26
, "x26", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
982 { ARMV8_R27
, "x27", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
983 { ARMV8_R28
, "x28", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
984 { ARMV8_R29
, "x29", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
985 { ARMV8_R30
, "x30", 64, ARM_MODE_ANY
, REG_TYPE_UINT64
, "general", "org.gnu.gdb.aarch64.core" },
987 { ARMV8_SP
, "sp", 64, ARM_MODE_ANY
, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.aarch64.core" },
988 { ARMV8_PC
, "pc", 64, ARM_MODE_ANY
, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.aarch64.core" },
990 { ARMV8_xPSR
, "CPSR", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.aarch64.core" },
992 { ARMV8_ELR_EL1
, "ELR_EL1", 64, ARMV8_64_EL1H
, REG_TYPE_CODE_PTR
, "banked", "net.sourceforge.openocd.banked" },
993 { ARMV8_ESR_EL1
, "ESR_EL1", 32, ARMV8_64_EL1H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
994 { ARMV8_SPSR_EL1
, "SPSR_EL1", 32, ARMV8_64_EL1H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
996 { ARMV8_ELR_EL2
, "ELR_EL2", 64, ARMV8_64_EL2H
, REG_TYPE_CODE_PTR
, "banked", "net.sourceforge.openocd.banked" },
997 { ARMV8_ESR_EL2
, "ESR_EL2", 32, ARMV8_64_EL2H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
998 { ARMV8_SPSR_EL2
, "SPSR_EL2", 32, ARMV8_64_EL2H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
1000 { ARMV8_ELR_EL3
, "ELR_EL3", 64, ARMV8_64_EL3H
, REG_TYPE_CODE_PTR
, "banked", "net.sourceforge.openocd.banked" },
1001 { ARMV8_ESR_EL3
, "ESR_EL3", 32, ARMV8_64_EL3H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
1002 { ARMV8_SPSR_EL3
, "SPSR_EL3", 32, ARMV8_64_EL3H
, REG_TYPE_UINT32
, "banked", "net.sourceforge.openocd.banked" },
1005 static const struct {
1012 const char *feature
;
1013 } armv8_regs32
[] = {
1014 { ARMV8_R0
, "r0", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1015 { ARMV8_R1
, "r1", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1016 { ARMV8_R2
, "r2", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1017 { ARMV8_R3
, "r3", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1018 { ARMV8_R4
, "r4", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1019 { ARMV8_R5
, "r5", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1020 { ARMV8_R6
, "r6", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1021 { ARMV8_R7
, "r7", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1022 { ARMV8_R8
, "r8", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1023 { ARMV8_R9
, "r9", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1024 { ARMV8_R10
, "r10", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1025 { ARMV8_R11
, "r11", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1026 { ARMV8_R12
, "r12", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1027 { ARMV8_R13
, "sp", 32, ARM_MODE_ANY
, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.arm.core" },
1028 { ARMV8_R14
, "lr", 32, ARM_MODE_ANY
, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.core" },
1029 { ARMV8_PC
, "pc", 32, ARM_MODE_ANY
, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.core" },
1030 { ARMV8_xPSR
, "cpsr", 32, ARM_MODE_ANY
, REG_TYPE_UINT32
, "general", "org.gnu.gdb.arm.core" },
1033 #define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs)
1034 #define ARMV8_NUM_REGS32 ARRAY_SIZE(armv8_regs32)
1036 static int armv8_get_core_reg(struct reg
*reg
)
1038 struct arm_reg
*armv8_reg
= reg
->arch_info
;
1039 struct target
*target
= armv8_reg
->target
;
1040 struct arm
*arm
= target_to_arm(target
);
1042 if (target
->state
!= TARGET_HALTED
)
1043 return ERROR_TARGET_NOT_HALTED
;
1045 return arm
->read_core_reg(target
, reg
, armv8_reg
->num
, arm
->core_mode
);
1048 static int armv8_set_core_reg(struct reg
*reg
, uint8_t *buf
)
1050 struct arm_reg
*armv8_reg
= reg
->arch_info
;
1051 struct target
*target
= armv8_reg
->target
;
1052 struct arm
*arm
= target_to_arm(target
);
1053 uint64_t value
= buf_get_u64(buf
, 0, 64);
1055 if (target
->state
!= TARGET_HALTED
)
1056 return ERROR_TARGET_NOT_HALTED
;
1058 if (reg
== arm
->cpsr
) {
1059 armv8_set_cpsr(arm
, (uint32_t)value
);
1061 buf_set_u64(reg
->value
, 0, 64, value
);
1070 static const struct reg_arch_type armv8_reg_type
= {
1071 .get
= armv8_get_core_reg
,
1072 .set
= armv8_set_core_reg
,
1075 static int armv8_get_core_reg32(struct reg
*reg
)
1077 struct arm_reg
*armv8_reg
= reg
->arch_info
;
1078 struct target
*target
= armv8_reg
->target
;
1079 struct arm
*arm
= target_to_arm(target
);
1080 struct reg_cache
*cache
= arm
->core_cache
;
1084 /* get the corresponding Aarch64 register */
1085 reg64
= cache
->reg_list
+ armv8_reg
->num
;
1091 retval
= arm
->read_core_reg(target
, reg64
, armv8_reg
->num
, arm
->core_mode
);
1092 if (retval
== ERROR_OK
)
1093 reg
->valid
= reg64
->valid
;
1098 static int armv8_set_core_reg32(struct reg
*reg
, uint8_t *buf
)
1100 struct arm_reg
*armv8_reg
= reg
->arch_info
;
1101 struct target
*target
= armv8_reg
->target
;
1102 struct arm
*arm
= target_to_arm(target
);
1103 struct reg_cache
*cache
= arm
->core_cache
;
1104 struct reg
*reg64
= cache
->reg_list
+ armv8_reg
->num
;
1105 uint32_t value
= buf_get_u32(buf
, 0, 32);
1107 if (reg64
== arm
->cpsr
) {
1108 armv8_set_cpsr(arm
, value
);
1110 buf_set_u32(reg
->value
, 0, 32, value
);
1120 static const struct reg_arch_type armv8_reg32_type
= {
1121 .get
= armv8_get_core_reg32
,
1122 .set
= armv8_set_core_reg32
,
1125 /** Builds cache of architecturally defined registers. */
1126 struct reg_cache
*armv8_build_reg_cache(struct target
*target
)
1128 struct armv8_common
*armv8
= target_to_armv8(target
);
1129 struct arm
*arm
= &armv8
->arm
;
1130 int num_regs
= ARMV8_NUM_REGS
;
1131 int num_regs32
= ARMV8_NUM_REGS32
;
1132 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
1133 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
1134 struct reg_cache
*cache32
= malloc(sizeof(struct reg_cache
));
1135 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
1136 struct reg
*reg_list32
= calloc(num_regs32
, sizeof(struct reg
));
1137 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
1138 struct reg_feature
*feature
;
1141 /* Build the process context cache */
1142 cache
->name
= "Aarch64 registers";
1143 cache
->next
= cache32
;
1144 cache
->reg_list
= reg_list
;
1145 cache
->num_regs
= num_regs
;
1147 for (i
= 0; i
< num_regs
; i
++) {
1148 arch_info
[i
].num
= armv8_regs
[i
].id
;
1149 arch_info
[i
].mode
= armv8_regs
[i
].mode
;
1150 arch_info
[i
].target
= target
;
1151 arch_info
[i
].arm
= arm
;
1153 reg_list
[i
].name
= armv8_regs
[i
].name
;
1154 reg_list
[i
].size
= armv8_regs
[i
].bits
;
1155 reg_list
[i
].value
= &arch_info
[i
].value
[0];
1156 reg_list
[i
].type
= &armv8_reg_type
;
1157 reg_list
[i
].arch_info
= &arch_info
[i
];
1159 reg_list
[i
].group
= armv8_regs
[i
].group
;
1160 reg_list
[i
].number
= i
;
1161 reg_list
[i
].exist
= true;
1162 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
1164 feature
= calloc(1, sizeof(struct reg_feature
));
1166 feature
->name
= armv8_regs
[i
].feature
;
1167 reg_list
[i
].feature
= feature
;
1169 LOG_ERROR("unable to allocate feature list");
1171 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
1172 if (reg_list
[i
].reg_data_type
)
1173 reg_list
[i
].reg_data_type
->type
= armv8_regs
[i
].type
;
1175 LOG_ERROR("unable to allocate reg type list");
1178 arm
->cpsr
= reg_list
+ ARMV8_xPSR
;
1179 arm
->pc
= reg_list
+ ARMV8_PC
;
1180 arm
->core_cache
= cache
;
1182 /* shadow cache for ARM mode registers */
1183 cache32
->name
= "Aarch32 registers";
1184 cache32
->next
= NULL
;
1185 cache32
->reg_list
= reg_list32
;
1186 cache32
->num_regs
= num_regs32
;
1188 for (i
= 0; i
< num_regs32
; i
++) {
1189 reg_list32
[i
].name
= armv8_regs32
[i
].name
;
1190 reg_list32
[i
].size
= armv8_regs32
[i
].bits
;
1191 reg_list32
[i
].value
= &arch_info
[armv8_regs32
[i
].id
].value
[0];
1192 reg_list32
[i
].type
= &armv8_reg32_type
;
1193 reg_list32
[i
].arch_info
= &arch_info
[armv8_regs32
[i
].id
];
1194 reg_list32
[i
].group
= armv8_regs32
[i
].group
;
1195 reg_list32
[i
].number
= i
;
1196 reg_list32
[i
].exist
= true;
1197 reg_list32
[i
].caller_save
= true;
1199 feature
= calloc(1, sizeof(struct reg_feature
));
1201 feature
->name
= armv8_regs32
[i
].feature
;
1202 reg_list32
[i
].feature
= feature
;
1204 LOG_ERROR("unable to allocate feature list");
1206 reg_list32
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
1207 if (reg_list32
[i
].reg_data_type
)
1208 reg_list32
[i
].reg_data_type
->type
= armv8_regs32
[i
].type
;
1210 LOG_ERROR("unable to allocate reg type list");
1217 struct reg
*armv8_reg_current(struct arm
*arm
, unsigned regnum
)
1221 if (regnum
> (ARMV8_LAST_REG
- 1))
1224 r
= arm
->core_cache
->reg_list
+ regnum
;
1228 const struct command_registration armv8_command_handlers
[] = {
1230 .chain
= dap_command_handlers
,
1232 COMMAND_REGISTRATION_DONE
1236 int armv8_get_gdb_reg_list(struct target
*target
,
1237 struct reg
**reg_list
[], int *reg_list_size
,
1238 enum target_register_class reg_class
)
1240 struct arm
*arm
= target_to_arm(target
);
1243 if (arm
->core_state
== ARM_STATE_AARCH64
) {
1245 LOG_DEBUG("Creating Aarch64 register list for target %s", target_name(target
));
1247 switch (reg_class
) {
1248 case REG_CLASS_GENERAL
:
1249 *reg_list_size
= ARMV8_ELR_EL1
;
1250 *reg_list
= malloc(sizeof(struct reg
*) * (*reg_list_size
));
1252 for (i
= 0; i
< *reg_list_size
; i
++)
1253 (*reg_list
)[i
] = armv8_reg_current(arm
, i
);
1257 *reg_list_size
= ARMV8_LAST_REG
;
1258 *reg_list
= malloc(sizeof(struct reg
*) * (*reg_list_size
));
1260 for (i
= 0; i
< *reg_list_size
; i
++)
1261 (*reg_list
)[i
] = armv8_reg_current(arm
, i
);
1266 LOG_ERROR("not a valid register class type in query.");
1270 struct reg_cache
*cache32
= arm
->core_cache
->next
;
1272 LOG_DEBUG("Creating Aarch32 register list for target %s", target_name(target
));
1274 switch (reg_class
) {
1275 case REG_CLASS_GENERAL
:
1277 *reg_list_size
= cache32
->num_regs
;
1278 *reg_list
= malloc(sizeof(struct reg
*) * (*reg_list_size
));
1280 for (i
= 0; i
< *reg_list_size
; i
++)
1281 (*reg_list
)[i
] = cache32
->reg_list
+ i
;
1285 LOG_ERROR("not a valid register class type in query.");
1291 int armv8_set_dbgreg_bits(struct armv8_common
*armv8
, unsigned int reg
, unsigned long mask
, unsigned long value
)
1296 int retval
= mem_ap_read_atomic_u32(armv8
->debug_ap
,
1297 armv8
->debug_base
+ reg
, &tmp
);
1298 if (ERROR_OK
!= retval
)
1301 /* clear bitfield */
1304 tmp
|= value
& mask
;
1306 /* write new value */
1307 retval
= mem_ap_write_atomic_u32(armv8
->debug_ap
,
1308 armv8
->debug_base
+ reg
, tmp
);
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)