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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_HAS_SRST
) &&
432 (jtag_reset_config
& RESET_SRST_NO_GATING
)) {
433 jtag_add_reset(0, 1);
434 res
= adapter
->layout
->api
->assert_srst(adapter
->fd
, 0);
435 srst_asserted
= true;
438 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DHCSR
, DBGKEY
|C_DEBUGEN
);
440 /* only set vector catch if halt is requested */
441 if (target
->reset_halt
)
442 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DEMCR
, TRCENA
|VC_CORERESET
);
444 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, DCB_DEMCR
, TRCENA
);
446 if (jtag_reset_config
& RESET_HAS_SRST
) {
447 if (!srst_asserted
) {
448 jtag_add_reset(0, 1);
449 res
= adapter
->layout
->api
->assert_srst(adapter
->fd
, 0);
451 if (res
== ERROR_COMMAND_NOTFOUND
)
452 LOG_ERROR("Hardware srst not supported, falling back to software reset");
453 else if (res
== ERROR_OK
) {
454 /* hardware srst supported */
455 use_srst_fallback
= false;
459 if (use_srst_fallback
) {
460 /* stlink v1 api does not support hardware srst, so we use a software reset fallback */
461 adapter
->layout
->api
->write_debug_reg(adapter
->fd
, NVIC_AIRCR
, AIRCR_VECTKEY
| AIRCR_SYSRESETREQ
);
464 res
= adapter
->layout
->api
->reset(adapter
->fd
);
469 /* registers are now invalid */
470 register_cache_invalidate(armv7m
->arm
.core_cache
);
472 if (target
->reset_halt
) {
473 target
->state
= TARGET_RESET
;
474 target
->debug_reason
= DBG_REASON_DBGRQ
;
476 target
->state
= TARGET_HALTED
;
482 static int adapter_deassert_reset(struct target
*target
)
485 struct hl_interface_s
*adapter
= target_to_adapter(target
);
487 enum reset_types jtag_reset_config
= jtag_get_reset_config();
489 LOG_DEBUG("%s", __func__
);
491 if (jtag_reset_config
& RESET_HAS_SRST
)
492 adapter
->layout
->api
->assert_srst(adapter
->fd
, 1);
494 /* virtual deassert reset, we need it for the internal
497 jtag_add_reset(0, 0);
499 if (!target
->reset_halt
) {
500 res
= target_resume(target
, 1, 0, 0, 0);
509 static int adapter_soft_reset_halt(struct target
*target
)
511 LOG_DEBUG("%s", __func__
);
515 static int adapter_halt(struct target
*target
)
518 struct hl_interface_s
*adapter
= target_to_adapter(target
);
520 LOG_DEBUG("%s", __func__
);
522 if (target
->state
== TARGET_HALTED
) {
523 LOG_DEBUG("target was already halted");
527 if (target
->state
== TARGET_UNKNOWN
)
528 LOG_WARNING("target was in unknown state when halt was requested");
530 res
= adapter
->layout
->api
->halt(adapter
->fd
);
535 target
->debug_reason
= DBG_REASON_DBGRQ
;
540 static int adapter_resume(struct target
*target
, int current
,
541 uint32_t address
, int handle_breakpoints
,
545 struct hl_interface_s
*adapter
= target_to_adapter(target
);
546 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
548 struct breakpoint
*breakpoint
= NULL
;
551 LOG_DEBUG("%s %d 0x%08x %d %d", __func__
, current
, address
,
552 handle_breakpoints
, debug_execution
);
554 if (target
->state
!= TARGET_HALTED
) {
555 LOG_WARNING("target not halted");
556 return ERROR_TARGET_NOT_HALTED
;
559 if (!debug_execution
) {
560 target_free_all_working_areas(target
);
561 cortex_m3_enable_breakpoints(target
);
562 cortex_m3_enable_watchpoints(target
);
567 buf_set_u32(pc
->value
, 0, 32, address
);
572 if (!breakpoint_find(target
, buf_get_u32(pc
->value
, 0, 32))
573 && !debug_execution
) {
574 armv7m_maybe_skip_bkpt_inst(target
, NULL
);
577 resume_pc
= buf_get_u32(pc
->value
, 0, 32);
579 /* write any user vector flags */
580 res
= target_write_u32(target
, DCB_DEMCR
, TRCENA
| armv7m
->demcr
);
584 armv7m_restore_context(target
);
586 /* registers are now invalid */
587 register_cache_invalidate(armv7m
->arm
.core_cache
);
589 /* the front-end may request us not to handle breakpoints */
590 if (handle_breakpoints
) {
591 /* Single step past breakpoint at current address */
592 breakpoint
= breakpoint_find(target
, resume_pc
);
594 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32
" (ID: %d)",
596 breakpoint
->unique_id
);
597 cortex_m3_unset_breakpoint(target
, breakpoint
);
599 res
= adapter
->layout
->api
->step(adapter
->fd
);
604 cortex_m3_set_breakpoint(target
, breakpoint
);
608 res
= adapter
->layout
->api
->run(adapter
->fd
);
613 target
->debug_reason
= DBG_REASON_NOTHALTED
;
615 if (!debug_execution
) {
616 target
->state
= TARGET_RUNNING
;
617 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
619 target
->state
= TARGET_DEBUG_RUNNING
;
620 target_call_event_callbacks(target
, TARGET_EVENT_DEBUG_RESUMED
);
626 static int adapter_step(struct target
*target
, int current
,
627 uint32_t address
, int handle_breakpoints
)
630 struct hl_interface_s
*adapter
= target_to_adapter(target
);
631 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
632 struct breakpoint
*breakpoint
= NULL
;
633 struct reg
*pc
= armv7m
->arm
.pc
;
634 bool bkpt_inst_found
= false;
636 LOG_DEBUG("%s", __func__
);
638 if (target
->state
!= TARGET_HALTED
) {
639 LOG_WARNING("target not halted");
640 return ERROR_TARGET_NOT_HALTED
;
644 buf_set_u32(pc
->value
, 0, 32, address
);
649 uint32_t pc_value
= buf_get_u32(pc
->value
, 0, 32);
651 /* the front-end may request us not to handle breakpoints */
652 if (handle_breakpoints
) {
653 breakpoint
= breakpoint_find(target
, pc_value
);
655 cortex_m3_unset_breakpoint(target
, breakpoint
);
658 armv7m_maybe_skip_bkpt_inst(target
, &bkpt_inst_found
);
660 target
->debug_reason
= DBG_REASON_SINGLESTEP
;
662 armv7m_restore_context(target
);
664 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
666 res
= adapter
->layout
->api
->step(adapter
->fd
);
671 /* registers are now invalid */
672 register_cache_invalidate(armv7m
->arm
.core_cache
);
675 cortex_m3_set_breakpoint(target
, breakpoint
);
677 adapter_debug_entry(target
);
678 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
680 LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32));
685 static int adapter_read_memory(struct target
*target
, uint32_t address
,
686 uint32_t size
, uint32_t count
,
689 struct hl_interface_s
*adapter
= target_to_adapter(target
);
691 uint32_t buffer_threshold
= (adapter
->param
.max_buffer
/ 4);
692 uint32_t addr_increment
= 4;
695 if (!count
|| !buffer
)
696 return ERROR_COMMAND_SYNTAX_ERROR
;
698 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
700 /* prepare byte count, buffer threshold
701 * and address increment for none 32bit access
705 buffer_threshold
= (adapter
->param
.max_buffer
/ 4) / 2;
710 if (count
> buffer_threshold
)
711 c
= buffer_threshold
;
716 res
= adapter
->layout
->api
->read_mem8(adapter
->fd
,
719 res
= adapter
->layout
->api
->read_mem32(adapter
->fd
,
725 address
+= (c
* addr_increment
);
726 buffer
+= (c
* addr_increment
);
733 static int adapter_write_memory(struct target
*target
, uint32_t address
,
734 uint32_t size
, uint32_t count
,
735 const uint8_t *buffer
)
737 struct hl_interface_s
*adapter
= target_to_adapter(target
);
739 uint32_t buffer_threshold
= (adapter
->param
.max_buffer
/ 4);
740 uint32_t addr_increment
= 4;
743 if (!count
|| !buffer
)
744 return ERROR_COMMAND_SYNTAX_ERROR
;
746 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
748 /* prepare byte count, buffer threshold
749 * and address increment for none 32bit access
753 buffer_threshold
= (adapter
->param
.max_buffer
/ 4) / 2;
758 if (count
> buffer_threshold
)
759 c
= buffer_threshold
;
764 res
= adapter
->layout
->api
->write_mem8(adapter
->fd
,
767 res
= adapter
->layout
->api
->write_mem32(adapter
->fd
,
773 address
+= (c
* addr_increment
);
774 buffer
+= (c
* addr_increment
);
781 static const struct command_registration adapter_command_handlers
[] = {
783 .chain
= arm_command_handlers
,
785 COMMAND_REGISTRATION_DONE
788 struct target_type hla_target
= {
789 .name
= "hla_target",
790 .deprecated_name
= "stm32_stlink",
792 .init_target
= adapter_init_target
,
793 .target_create
= adapter_target_create
,
794 .examine
= cortex_m3_examine
,
795 .commands
= adapter_command_handlers
,
797 .poll
= adapter_poll
,
798 .arch_state
= armv7m_arch_state
,
800 .assert_reset
= adapter_assert_reset
,
801 .deassert_reset
= adapter_deassert_reset
,
802 .soft_reset_halt
= adapter_soft_reset_halt
,
804 .halt
= adapter_halt
,
805 .resume
= adapter_resume
,
806 .step
= adapter_step
,
808 .get_gdb_reg_list
= armv7m_get_gdb_reg_list
,
810 .read_memory
= adapter_read_memory
,
811 .write_memory
= adapter_write_memory
,
812 .checksum_memory
= armv7m_checksum_memory
,
813 .blank_check_memory
= armv7m_blank_check_memory
,
815 .run_algorithm
= armv7m_run_algorithm
,
816 .start_algorithm
= armv7m_start_algorithm
,
817 .wait_algorithm
= armv7m_wait_algorithm
,
819 .add_breakpoint
= cortex_m3_add_breakpoint
,
820 .remove_breakpoint
= cortex_m3_remove_breakpoint
,
821 .add_watchpoint
= cortex_m3_add_watchpoint
,
822 .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)