1 /***************************************************************************
2 * Copyright (C) 2011 by Mathias Kuester *
3 * Mathias Kuester <kesmtp@freenet.de> *
5 * Copyright (C) 2011 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
28 #include "jtag/jtag.h"
29 #include "jtag/hla/hla_transport.h"
30 #include "jtag/hla/hla_interface.h"
31 #include "jtag/hla/hla_layout.h"
33 #include "algorithm.h"
35 #include "breakpoints.h"
36 #include "target_type.h"
39 #include "arm_semihosting.h"
41 #define ARMV7M_SCS_DCRSR 0xe000edf4
42 #define ARMV7M_SCS_DCRDR 0xe000edf8
44 static inline struct hl_interface_s
*target_to_adapter(struct target
*target
)
46 return target
->tap
->priv
;
49 static int adapter_load_core_reg_u32(struct target
*target
,
50 uint32_t num
, uint32_t *value
)
53 struct hl_interface_s
*adapter
= target_to_adapter(target
);
55 LOG_DEBUG("%s", __func__
);
57 /* NOTE: we "know" here that the register identifiers used
58 * in the v7m header match the Cortex-M3 Debug Core Register
59 * Selector values for R0..R15, xPSR, MSP, and PSP.
63 /* read a normal core register */
64 retval
= adapter
->layout
->api
->read_reg(adapter
->fd
, num
, value
);
66 if (retval
!= ERROR_OK
) {
67 LOG_ERROR("JTAG failure %i", retval
);
68 return ERROR_JTAG_DEVICE_ERROR
;
70 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
79 /* Floating-point Status and Registers */
80 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, 33);
81 if (retval
!= ERROR_OK
)
83 retval
= target_read_u32(target
, ARMV7M_SCS_DCRDR
, value
);
84 if (retval
!= ERROR_OK
)
86 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
89 case ARMV7M_S0
... ARMV7M_S31
:
90 /* Floating-point Status and Registers */
91 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, num
-ARMV7M_S0
+64);
92 if (retval
!= ERROR_OK
)
94 retval
= target_read_u32(target
, ARMV7M_SCS_DCRDR
, value
);
95 if (retval
!= ERROR_OK
)
97 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
100 case ARMV7M_D0
... ARMV7M_D15
:
106 case ARMV7M_FAULTMASK
:
108 /* Cortex-M3 packages these four registers as bitfields
109 * in one Debug Core register. So say r0 and r2 docs;
110 * it was removed from r1 docs, but still works.
112 retval
= adapter
->layout
->api
->read_reg(adapter
->fd
, 20, value
);
113 if (retval
!= ERROR_OK
)
118 *value
= buf_get_u32((uint8_t *) value
, 0, 1);
122 *value
= buf_get_u32((uint8_t *) value
, 8, 8);
125 case ARMV7M_FAULTMASK
:
126 *value
= buf_get_u32((uint8_t *) value
, 16, 1);
130 *value
= buf_get_u32((uint8_t *) value
, 24, 2);
134 LOG_DEBUG("load from special reg %i value 0x%" PRIx32
"",
139 return ERROR_COMMAND_SYNTAX_ERROR
;
145 static int adapter_store_core_reg_u32(struct target
*target
,
146 uint32_t num
, uint32_t value
)
150 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
151 struct hl_interface_s
*adapter
= target_to_adapter(target
);
153 LOG_DEBUG("%s", __func__
);
155 #ifdef ARMV7_GDB_HACKS
156 /* If the LR register is being modified, make sure it will put us
157 * in "thumb" mode, or an INVSTATE exception will occur. This is a
158 * hack to deal with the fact that gdb will sometimes "forge"
159 * return addresses, and doesn't set the LSB correctly (i.e., when
160 * printing expressions containing function calls, it sets LR = 0.)
161 * Valid exception return codes have bit 0 set too.
163 if (num
== ARMV7M_R14
)
167 /* NOTE: we "know" here that the register identifiers used
168 * in the v7m header match the Cortex-M3 Debug Core Register
169 * Selector values for R0..R15, xPSR, MSP, and PSP.
173 retval
= adapter
->layout
->api
->write_reg(adapter
->fd
, num
, value
);
175 if (retval
!= ERROR_OK
) {
178 LOG_ERROR("JTAG failure");
179 r
= armv7m
->arm
.core_cache
->reg_list
+ num
;
181 return ERROR_JTAG_DEVICE_ERROR
;
183 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
191 /* Floating-point Status and Registers */
192 retval
= target_write_u32(target
, ARMV7M_SCS_DCRDR
, value
);
193 if (retval
!= ERROR_OK
)
195 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, 33 | (1<<16));
196 if (retval
!= ERROR_OK
)
198 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
201 case ARMV7M_S0
... ARMV7M_S31
:
202 /* Floating-point Status and Registers */
203 retval
= target_write_u32(target
, ARMV7M_SCS_DCRDR
, value
);
204 if (retval
!= ERROR_OK
)
206 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, (num
-ARMV7M_S0
+64) | (1<<16));
207 if (retval
!= ERROR_OK
)
209 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
212 case ARMV7M_D0
... ARMV7M_D15
:
217 case ARMV7M_FAULTMASK
:
219 /* Cortex-M3 packages these four registers as bitfields
220 * in one Debug Core register. So say r0 and r2 docs;
221 * it was removed from r1 docs, but still works.
224 adapter
->layout
->api
->read_reg(adapter
->fd
, 20, ®
);
228 buf_set_u32((uint8_t *) ®
, 0, 1, value
);
232 buf_set_u32((uint8_t *) ®
, 8, 8, value
);
235 case ARMV7M_FAULTMASK
:
236 buf_set_u32((uint8_t *) ®
, 16, 1, value
);
240 buf_set_u32((uint8_t *) ®
, 24, 2, value
);
244 adapter
->layout
->api
->write_reg(adapter
->fd
, 20, reg
);
246 LOG_DEBUG("write special reg %i value 0x%" PRIx32
" ", (int)num
, value
);
250 return ERROR_COMMAND_SYNTAX_ERROR
;
256 static int adapter_examine_debug_reason(struct target
*target
)
258 if ((target
->debug_reason
!= DBG_REASON_DBGRQ
)
259 && (target
->debug_reason
!= DBG_REASON_SINGLESTEP
)) {
260 target
->debug_reason
= DBG_REASON_BREAKPOINT
;
266 static int adapter_init_arch_info(struct target
*target
,
267 struct cortex_m3_common
*cortex_m3
,
268 struct jtag_tap
*tap
)
270 struct armv7m_common
*armv7m
;
272 LOG_DEBUG("%s", __func__
);
274 armv7m
= &cortex_m3
->armv7m
;
275 armv7m_init_arch_info(target
, armv7m
);
277 armv7m
->load_core_reg_u32
= adapter_load_core_reg_u32
;
278 armv7m
->store_core_reg_u32
= adapter_store_core_reg_u32
;
280 armv7m
->examine_debug_reason
= adapter_examine_debug_reason
;
281 armv7m
->stlink
= true;
286 static int adapter_init_target(struct command_context
*cmd_ctx
,
287 struct target
*target
)
289 LOG_DEBUG("%s", __func__
);
291 armv7m_build_reg_cache(target
);
296 static int adapter_target_create(struct target
*target
,
299 LOG_DEBUG("%s", __func__
);
301 struct cortex_m3_common
*cortex_m3
= calloc(1, sizeof(struct cortex_m3_common
));
304 return ERROR_COMMAND_SYNTAX_ERROR
;
306 adapter_init_arch_info(target
, cortex_m3
, target
->tap
);
311 static int adapter_load_context(struct target
*target
)
313 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
314 int num_regs
= armv7m
->arm
.core_cache
->num_regs
;
316 for (int i
= 0; i
< num_regs
; i
++) {
318 struct reg
*r
= &armv7m
->arm
.core_cache
->reg_list
[i
];
320 armv7m
->arm
.read_core_reg(target
, r
, i
, ARM_MODE_ANY
);
326 static int adapter_debug_entry(struct target
*target
)
328 struct hl_interface_s
*adapter
= target_to_adapter(target
);
329 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
330 struct arm
*arm
= &armv7m
->arm
;
335 retval
= armv7m
->examine_debug_reason(target
);
336 if (retval
!= ERROR_OK
)
339 adapter_load_context(target
);
341 /* make sure we clear the vector catch bit */
342 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DEMCR
, TRCENA
);
344 r
= arm
->core_cache
->reg_list
+ ARMV7M_xPSR
;
345 xPSR
= buf_get_u32(r
->value
, 0, 32);
347 /* Are we in an exception handler */
349 armv7m
->exception_number
= (xPSR
& 0x1FF);
351 arm
->core_mode
= ARM_MODE_HANDLER
;
352 arm
->map
= armv7m_msp_reg_map
;
354 unsigned control
= buf_get_u32(arm
->core_cache
355 ->reg_list
[ARMV7M_CONTROL
].value
, 0, 2);
357 /* is this thread privileged? */
358 arm
->core_mode
= control
& 1
359 ? ARM_MODE_USER_THREAD
362 /* which stack is it using? */
364 arm
->map
= armv7m_psp_reg_map
;
366 arm
->map
= armv7m_msp_reg_map
;
368 armv7m
->exception_number
= 0;
371 LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32
", target->state: %s",
372 arm_mode_name(arm
->core_mode
),
373 *(uint32_t *)(arm
->pc
->value
),
374 target_state_name(target
));
379 static int adapter_poll(struct target
*target
)
381 enum target_state state
;
382 struct hl_interface_s
*adapter
= target_to_adapter(target
);
383 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
384 enum target_state prev_target_state
= target
->state
;
386 state
= adapter
->layout
->api
->state(adapter
->fd
);
388 if (state
== TARGET_UNKNOWN
) {
389 LOG_ERROR("jtag status contains invalid mode value - communication failure");
390 return ERROR_TARGET_FAILURE
;
393 if (target
->state
== state
)
396 if (state
== TARGET_HALTED
) {
397 target
->state
= state
;
399 int retval
= adapter_debug_entry(target
);
400 if (retval
!= ERROR_OK
)
403 if (prev_target_state
== TARGET_DEBUG_RUNNING
) {
404 target_call_event_callbacks(target
, TARGET_EVENT_DEBUG_HALTED
);
406 if (arm_semihosting(target
, &retval
) != 0)
409 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
412 LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32));
418 static int adapter_assert_reset(struct target
*target
)
421 struct hl_interface_s
*adapter
= target_to_adapter(target
);
422 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
423 bool use_srst_fallback
= true;
425 LOG_DEBUG("%s", __func__
);
427 enum reset_types jtag_reset_config
= jtag_get_reset_config();
429 bool srst_asserted
= false;
431 if (jtag_reset_config
& RESET_SRST_NO_GATING
) {
432 jtag_add_reset(0, 1);
433 res
= adapter
->layout
->api
->assert_srst(adapter
->fd
, 0);
434 srst_asserted
= true;
437 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DHCSR
, DBGKEY
|C_DEBUGEN
);
439 /* only set vector catch if halt is requested */
440 if (target
->reset_halt
)
441 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DEMCR
, TRCENA
|VC_CORERESET
);
443 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DEMCR
, TRCENA
);
445 if (jtag_reset_config
& RESET_HAS_SRST
) {
446 if (!srst_asserted
) {
447 jtag_add_reset(0, 1);
448 res
= adapter
->layout
->api
->assert_srst(adapter
->fd
, 0);
450 if (res
== ERROR_COMMAND_NOTFOUND
)
451 LOG_ERROR("Hardware srst not supported, falling back to software reset");
452 else if (res
== ERROR_OK
) {
453 /* hardware srst supported */
454 use_srst_fallback
= false;
458 if (use_srst_fallback
) {
459 /* stlink v1 api does not support hardware srst, so we use a software reset fallback */
460 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, NVIC_AIRCR
, AIRCR_VECTKEY
| AIRCR_SYSRESETREQ
);
463 res
= adapter
->layout
->api
->reset(adapter
->fd
);
468 /* registers are now invalid */
469 register_cache_invalidate(armv7m
->arm
.core_cache
);
471 if (target
->reset_halt
) {
472 target
->state
= TARGET_RESET
;
473 target
->debug_reason
= DBG_REASON_DBGRQ
;
475 target
->state
= TARGET_HALTED
;
481 static int adapter_deassert_reset(struct target
*target
)
484 struct hl_interface_s
*adapter
= target_to_adapter(target
);
486 enum reset_types jtag_reset_config
= jtag_get_reset_config();
488 LOG_DEBUG("%s", __func__
);
490 if (jtag_reset_config
& RESET_HAS_SRST
)
491 adapter
->layout
->api
->assert_srst(adapter
->fd
, 1);
493 /* virtual deassert reset, we need it for the internal
496 jtag_add_reset(0, 0);
498 if (!target
->reset_halt
) {
499 res
= target_resume(target
, 1, 0, 0, 0);
508 static int adapter_soft_reset_halt(struct target
*target
)
510 LOG_DEBUG("%s", __func__
);
514 static int adapter_halt(struct target
*target
)
517 struct hl_interface_s
*adapter
= target_to_adapter(target
);
519 LOG_DEBUG("%s", __func__
);
521 if (target
->state
== TARGET_HALTED
) {
522 LOG_DEBUG("target was already halted");
526 if (target
->state
== TARGET_UNKNOWN
)
527 LOG_WARNING("target was in unknown state when halt was requested");
529 res
= adapter
->layout
->api
->halt(adapter
->fd
);
534 target
->debug_reason
= DBG_REASON_DBGRQ
;
539 static int adapter_resume(struct target
*target
, int current
,
540 uint32_t address
, int handle_breakpoints
,
544 struct hl_interface_s
*adapter
= target_to_adapter(target
);
545 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
547 struct breakpoint
*breakpoint
= NULL
;
550 LOG_DEBUG("%s %d 0x%08x %d %d", __func__
, current
, address
,
551 handle_breakpoints
, debug_execution
);
553 if (target
->state
!= TARGET_HALTED
) {
554 LOG_WARNING("target not halted");
555 return ERROR_TARGET_NOT_HALTED
;
558 if (!debug_execution
) {
559 target_free_all_working_areas(target
);
560 cortex_m3_enable_breakpoints(target
);
561 cortex_m3_enable_watchpoints(target
);
566 buf_set_u32(pc
->value
, 0, 32, address
);
571 if (!breakpoint_find(target
, buf_get_u32(pc
->value
, 0, 32))
572 && !debug_execution
) {
573 armv7m_maybe_skip_bkpt_inst(target
, NULL
);
576 resume_pc
= buf_get_u32(pc
->value
, 0, 32);
578 /* write any user vector flags */
579 res
= target_write_u32(target
, DCB_DEMCR
, TRCENA
| armv7m
->demcr
);
583 armv7m_restore_context(target
);
585 /* registers are now invalid */
586 register_cache_invalidate(armv7m
->arm
.core_cache
);
588 /* the front-end may request us not to handle breakpoints */
589 if (handle_breakpoints
) {
590 /* Single step past breakpoint at current address */
591 breakpoint
= breakpoint_find(target
, resume_pc
);
593 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32
" (ID: %d)",
595 breakpoint
->unique_id
);
596 cortex_m3_unset_breakpoint(target
, breakpoint
);
598 res
= adapter
->layout
->api
->step(adapter
->fd
);
603 cortex_m3_set_breakpoint(target
, breakpoint
);
607 res
= adapter
->layout
->api
->run(adapter
->fd
);
612 target
->debug_reason
= DBG_REASON_NOTHALTED
;
614 if (!debug_execution
) {
615 target
->state
= TARGET_RUNNING
;
616 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
618 target
->state
= TARGET_DEBUG_RUNNING
;
619 target_call_event_callbacks(target
, TARGET_EVENT_DEBUG_RESUMED
);
625 static int adapter_step(struct target
*target
, int current
,
626 uint32_t address
, int handle_breakpoints
)
629 struct hl_interface_s
*adapter
= target_to_adapter(target
);
630 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
631 struct breakpoint
*breakpoint
= NULL
;
632 struct reg
*pc
= armv7m
->arm
.pc
;
633 bool bkpt_inst_found
= false;
635 LOG_DEBUG("%s", __func__
);
637 if (target
->state
!= TARGET_HALTED
) {
638 LOG_WARNING("target not halted");
639 return ERROR_TARGET_NOT_HALTED
;
643 buf_set_u32(pc
->value
, 0, 32, address
);
648 uint32_t pc_value
= buf_get_u32(pc
->value
, 0, 32);
650 /* the front-end may request us not to handle breakpoints */
651 if (handle_breakpoints
) {
652 breakpoint
= breakpoint_find(target
, pc_value
);
654 cortex_m3_unset_breakpoint(target
, breakpoint
);
657 armv7m_maybe_skip_bkpt_inst(target
, &bkpt_inst_found
);
659 target
->debug_reason
= DBG_REASON_SINGLESTEP
;
661 armv7m_restore_context(target
);
663 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
665 res
= adapter
->layout
->api
->step(adapter
->fd
);
670 /* registers are now invalid */
671 register_cache_invalidate(armv7m
->arm
.core_cache
);
674 cortex_m3_set_breakpoint(target
, breakpoint
);
676 adapter_debug_entry(target
);
677 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
679 LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32));
684 static int adapter_read_memory(struct target
*target
, uint32_t address
,
685 uint32_t size
, uint32_t count
,
688 struct hl_interface_s
*adapter
= target_to_adapter(target
);
690 uint32_t buffer_threshold
= (adapter
->param
.max_buffer
/ 4);
691 uint32_t addr_increment
= 4;
694 if (!count
|| !buffer
)
695 return ERROR_COMMAND_SYNTAX_ERROR
;
697 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
699 /* prepare byte count, buffer threshold
700 * and address increment for none 32bit access
704 buffer_threshold
= (adapter
->param
.max_buffer
/ 4) / 2;
709 if (count
> buffer_threshold
)
710 c
= buffer_threshold
;
715 res
= adapter
->layout
->api
->read_mem8(adapter
->fd
,
718 res
= adapter
->layout
->api
->read_mem32(adapter
->fd
,
724 address
+= (c
* addr_increment
);
725 buffer
+= (c
* addr_increment
);
732 static int adapter_write_memory(struct target
*target
, uint32_t address
,
733 uint32_t size
, uint32_t count
,
734 const uint8_t *buffer
)
736 struct hl_interface_s
*adapter
= target_to_adapter(target
);
738 uint32_t buffer_threshold
= (adapter
->param
.max_buffer
/ 4);
739 uint32_t addr_increment
= 4;
742 if (!count
|| !buffer
)
743 return ERROR_COMMAND_SYNTAX_ERROR
;
745 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
747 /* prepare byte count, buffer threshold
748 * and address increment for none 32bit access
752 buffer_threshold
= (adapter
->param
.max_buffer
/ 4) / 2;
757 if (count
> buffer_threshold
)
758 c
= buffer_threshold
;
763 res
= adapter
->layout
->api
->write_mem8(adapter
->fd
,
766 res
= adapter
->layout
->api
->write_mem32(adapter
->fd
,
772 address
+= (c
* addr_increment
);
773 buffer
+= (c
* addr_increment
);
780 static const struct command_registration adapter_command_handlers
[] = {
782 .chain
= arm_command_handlers
,
784 COMMAND_REGISTRATION_DONE
787 struct target_type hla_target
= {
788 .name
= "hla_target",
789 .deprecated_name
= "stm32_stlink",
791 .init_target
= adapter_init_target
,
792 .target_create
= adapter_target_create
,
793 .examine
= cortex_m3_examine
,
794 .commands
= adapter_command_handlers
,
796 .poll
= adapter_poll
,
797 .arch_state
= armv7m_arch_state
,
799 .assert_reset
= adapter_assert_reset
,
800 .deassert_reset
= adapter_deassert_reset
,
801 .soft_reset_halt
= adapter_soft_reset_halt
,
803 .halt
= adapter_halt
,
804 .resume
= adapter_resume
,
805 .step
= adapter_step
,
807 .get_gdb_reg_list
= armv7m_get_gdb_reg_list
,
809 .read_memory
= adapter_read_memory
,
810 .write_memory
= adapter_write_memory
,
811 .checksum_memory
= armv7m_checksum_memory
,
812 .blank_check_memory
= armv7m_blank_check_memory
,
814 .run_algorithm
= armv7m_run_algorithm
,
815 .start_algorithm
= armv7m_start_algorithm
,
816 .wait_algorithm
= armv7m_wait_algorithm
,
818 .add_breakpoint
= cortex_m3_add_breakpoint
,
819 .remove_breakpoint
= cortex_m3_remove_breakpoint
,
820 .add_watchpoint
= cortex_m3_add_watchpoint
,
821 .remove_watchpoint
= cortex_m3_remove_watchpoint
,
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)