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/stlink/stlink_transport.h"
30 #include "jtag/stlink/stlink_interface.h"
31 #include "jtag/stlink/stlink_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 stlink_interface_s
*target_to_stlink(struct target
*target
)
46 return target
->tap
->priv
;
49 static int stm32_stlink_load_core_reg_u32(struct target
*target
,
50 enum armv7m_regtype type
,
51 uint32_t num
, uint32_t *value
)
54 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
56 LOG_DEBUG("%s", __func__
);
58 /* NOTE: we "know" here that the register identifiers used
59 * in the v7m header match the Cortex-M3 Debug Core Register
60 * Selector values for R0..R15, xPSR, MSP, and PSP.
64 /* read a normal core register */
65 retval
= stlink_if
->layout
->api
->read_reg(stlink_if
->fd
, num
, value
);
67 if (retval
!= ERROR_OK
) {
68 LOG_ERROR("JTAG failure %i", retval
);
69 return ERROR_JTAG_DEVICE_ERROR
;
71 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
80 /* Floating-point Status and Registers */
81 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, 33);
82 if (retval
!= ERROR_OK
)
84 retval
= target_read_u32(target
, ARMV7M_SCS_DCRDR
, value
);
85 if (retval
!= ERROR_OK
)
87 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
90 case ARMV7M_S0
... ARMV7M_S31
:
91 /* Floating-point Status and Registers */
92 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, num
-ARMV7M_S0
+64);
93 if (retval
!= ERROR_OK
)
95 retval
= target_read_u32(target
, ARMV7M_SCS_DCRDR
, value
);
96 if (retval
!= ERROR_OK
)
98 LOG_DEBUG("load from core reg %i value 0x%" PRIx32
"", (int)num
, *value
);
101 case ARMV7M_D0
... ARMV7M_D15
:
107 case ARMV7M_FAULTMASK
:
109 /* Cortex-M3 packages these four registers as bitfields
110 * in one Debug Core register. So say r0 and r2 docs;
111 * it was removed from r1 docs, but still works.
113 retval
= stlink_if
->layout
->api
->read_reg(stlink_if
->fd
, 20, value
);
114 if (retval
!= ERROR_OK
)
119 *value
= buf_get_u32((uint8_t *) value
, 0, 1);
123 *value
= buf_get_u32((uint8_t *) value
, 8, 8);
126 case ARMV7M_FAULTMASK
:
127 *value
= buf_get_u32((uint8_t *) value
, 16, 1);
131 *value
= buf_get_u32((uint8_t *) value
, 24, 2);
135 LOG_DEBUG("load from special reg %i value 0x%" PRIx32
"",
140 return ERROR_COMMAND_SYNTAX_ERROR
;
146 static int stm32_stlink_store_core_reg_u32(struct target
*target
,
147 enum armv7m_regtype type
,
148 uint32_t num
, uint32_t value
)
152 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
153 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
155 LOG_DEBUG("%s", __func__
);
157 #ifdef ARMV7_GDB_HACKS
158 /* If the LR register is being modified, make sure it will put us
159 * in "thumb" mode, or an INVSTATE exception will occur. This is a
160 * hack to deal with the fact that gdb will sometimes "forge"
161 * return addresses, and doesn't set the LSB correctly (i.e., when
162 * printing expressions containing function calls, it sets LR = 0.)
163 * Valid exception return codes have bit 0 set too.
165 if (num
== ARMV7M_R14
)
169 /* NOTE: we "know" here that the register identifiers used
170 * in the v7m header match the Cortex-M3 Debug Core Register
171 * Selector values for R0..R15, xPSR, MSP, and PSP.
175 retval
= stlink_if
->layout
->api
->write_reg(stlink_if
->fd
, num
, value
);
177 if (retval
!= ERROR_OK
) {
180 LOG_ERROR("JTAG failure");
181 r
= armv7m
->core_cache
->reg_list
+ num
;
183 return ERROR_JTAG_DEVICE_ERROR
;
185 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
193 /* Floating-point Status and Registers */
194 retval
= target_write_u32(target
, ARMV7M_SCS_DCRDR
, value
);
195 if (retval
!= ERROR_OK
)
197 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, 33 | (1<<16));
198 if (retval
!= ERROR_OK
)
200 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
203 case ARMV7M_S0
... ARMV7M_S31
:
204 /* Floating-point Status and Registers */
205 retval
= target_write_u32(target
, ARMV7M_SCS_DCRDR
, value
);
206 if (retval
!= ERROR_OK
)
208 retval
= target_write_u32(target
, ARMV7M_SCS_DCRSR
, (num
-ARMV7M_S0
+64) | (1<<16));
209 if (retval
!= ERROR_OK
)
211 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", (int)num
, value
);
214 case ARMV7M_D0
... ARMV7M_D15
:
219 case ARMV7M_FAULTMASK
:
221 /* Cortex-M3 packages these four registers as bitfields
222 * in one Debug Core register. So say r0 and r2 docs;
223 * it was removed from r1 docs, but still works.
226 stlink_if
->layout
->api
->read_reg(stlink_if
->fd
, 20, ®
);
230 buf_set_u32((uint8_t *) ®
, 0, 1, value
);
234 buf_set_u32((uint8_t *) ®
, 8, 8, value
);
237 case ARMV7M_FAULTMASK
:
238 buf_set_u32((uint8_t *) ®
, 16, 1, value
);
242 buf_set_u32((uint8_t *) ®
, 24, 2, value
);
246 stlink_if
->layout
->api
->write_reg(stlink_if
->fd
, 20, reg
);
248 LOG_DEBUG("write special reg %i value 0x%" PRIx32
" ", (int)num
, value
);
252 return ERROR_COMMAND_SYNTAX_ERROR
;
258 static int stm32_stlink_examine_debug_reason(struct target
*target
)
260 if ((target
->debug_reason
!= DBG_REASON_DBGRQ
)
261 && (target
->debug_reason
!= DBG_REASON_SINGLESTEP
)) {
262 target
->debug_reason
= DBG_REASON_BREAKPOINT
;
268 static int stm32_stlink_init_arch_info(struct target
*target
,
269 struct cortex_m3_common
*cortex_m3
,
270 struct jtag_tap
*tap
)
272 struct armv7m_common
*armv7m
;
274 LOG_DEBUG("%s", __func__
);
276 armv7m
= &cortex_m3
->armv7m
;
277 armv7m_init_arch_info(target
, armv7m
);
279 armv7m
->load_core_reg_u32
= stm32_stlink_load_core_reg_u32
;
280 armv7m
->store_core_reg_u32
= stm32_stlink_store_core_reg_u32
;
282 armv7m
->examine_debug_reason
= stm32_stlink_examine_debug_reason
;
283 armv7m
->stlink
= true;
288 static int stm32_stlink_init_target(struct command_context
*cmd_ctx
,
289 struct target
*target
)
291 LOG_DEBUG("%s", __func__
);
293 armv7m_build_reg_cache(target
);
298 static int stm32_stlink_target_create(struct target
*target
,
301 LOG_DEBUG("%s", __func__
);
303 struct cortex_m3_common
*cortex_m3
= calloc(1, sizeof(struct cortex_m3_common
));
306 return ERROR_COMMAND_SYNTAX_ERROR
;
308 stm32_stlink_init_arch_info(target
, cortex_m3
, target
->tap
);
313 static int stm32_stlink_load_context(struct target
*target
)
315 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
316 int num_regs
= armv7m
->core_cache
->num_regs
;
318 for (int i
= 0; i
< num_regs
; i
++) {
319 if (!armv7m
->core_cache
->reg_list
[i
].valid
)
320 armv7m
->read_core_reg(target
, i
);
326 static int stlink_debug_entry(struct target
*target
)
328 struct stlink_interface_s
*stlink_if
= target_to_stlink(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 stm32_stlink_load_context(target
);
341 /* make sure we clear the vector catch bit */
342 stlink_if
->layout
->api
->write_debug_reg(stlink_if
->fd
, DCB_DEMCR
, 0);
344 r
= armv7m
->core_cache
->reg_list
+ ARMV7M_xPSR
;
345 xPSR
= buf_get_u32(r
->value
, 0, 32);
347 /* Are we in an exception handler */
349 armv7m
->core_mode
= ARMV7M_MODE_HANDLER
;
350 armv7m
->exception_number
= (xPSR
& 0x1FF);
352 arm
->core_mode
= ARM_MODE_HANDLER
;
353 arm
->map
= armv7m_msp_reg_map
;
355 unsigned control
= buf_get_u32(armv7m
->core_cache
356 ->reg_list
[ARMV7M_CONTROL
].value
, 0, 2);
358 /* is this thread privileged? */
359 armv7m
->core_mode
= control
& 1;
360 arm
->core_mode
= armv7m
->core_mode
361 ? ARM_MODE_USER_THREAD
364 /* which stack is it using? */
366 arm
->map
= armv7m_psp_reg_map
;
368 arm
->map
= armv7m_msp_reg_map
;
370 armv7m
->exception_number
= 0;
373 LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32
", target->state: %s",
374 armv7m_mode_strings
[armv7m
->core_mode
],
375 *(uint32_t *)(arm
->pc
->value
),
376 target_state_name(target
));
381 static int stm32_stlink_poll(struct target
*target
)
383 enum target_state state
;
384 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
385 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
387 state
= stlink_if
->layout
->api
->state(stlink_if
->fd
);
389 if (state
== TARGET_UNKNOWN
) {
390 LOG_ERROR("jtag status contains invalid mode value - communication failure");
391 return ERROR_TARGET_FAILURE
;
394 if (target
->state
== state
)
397 if (state
== TARGET_HALTED
) {
398 target
->state
= state
;
400 int retval
= stlink_debug_entry(target
);
401 if (retval
!= ERROR_OK
)
404 if (arm_semihosting(target
, &retval
) != 0)
407 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
408 LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32));
414 static int stm32_stlink_assert_reset(struct target
*target
)
417 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
418 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
419 bool use_srst_fallback
= true;
421 LOG_DEBUG("%s", __func__
);
423 enum reset_types jtag_reset_config
= jtag_get_reset_config();
425 bool srst_asserted
= false;
427 if (jtag_reset_config
& RESET_SRST_NO_GATING
) {
428 jtag_add_reset(0, 1);
429 res
= stlink_if
->layout
->api
->assert_srst(stlink_if
->fd
, 0);
430 srst_asserted
= true;
433 stlink_if
->layout
->api
->write_debug_reg(stlink_if
->fd
, DCB_DHCSR
, DBGKEY
|C_DEBUGEN
);
435 /* only set vector catch if halt is requested */
436 if (target
->reset_halt
)
437 stlink_if
->layout
->api
->write_debug_reg(stlink_if
->fd
, DCB_DEMCR
, VC_CORERESET
);
439 stlink_if
->layout
->api
->write_debug_reg(stlink_if
->fd
, DCB_DEMCR
, 0);
441 if (jtag_reset_config
& RESET_HAS_SRST
) {
442 if (!srst_asserted
) {
443 jtag_add_reset(0, 1);
444 res
= stlink_if
->layout
->api
->assert_srst(stlink_if
->fd
, 0);
446 if (res
== ERROR_COMMAND_NOTFOUND
)
447 LOG_ERROR("Hardware srst not supported, falling back to software reset");
448 else if (res
== ERROR_OK
) {
449 /* hardware srst supported */
450 use_srst_fallback
= false;
454 if (use_srst_fallback
) {
455 /* stlink v1 api does not support hardware srst, so we use a software reset fallback */
456 stlink_if
->layout
->api
->write_debug_reg(stlink_if
->fd
, NVIC_AIRCR
, AIRCR_VECTKEY
| AIRCR_SYSRESETREQ
);
459 res
= stlink_if
->layout
->api
->reset(stlink_if
->fd
);
464 /* registers are now invalid */
465 register_cache_invalidate(armv7m
->core_cache
);
467 if (target
->reset_halt
) {
468 target
->state
= TARGET_RESET
;
469 target
->debug_reason
= DBG_REASON_DBGRQ
;
471 target
->state
= TARGET_HALTED
;
477 static int stm32_stlink_deassert_reset(struct target
*target
)
480 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
482 enum reset_types jtag_reset_config
= jtag_get_reset_config();
484 LOG_DEBUG("%s", __func__
);
486 if (jtag_reset_config
& RESET_HAS_SRST
)
487 stlink_if
->layout
->api
->assert_srst(stlink_if
->fd
, 1);
489 /* virtual deassert reset, we need it for the internal
492 jtag_add_reset(0, 0);
494 if (!target
->reset_halt
) {
495 res
= target_resume(target
, 1, 0, 0, 0);
504 static int stm32_stlink_soft_reset_halt(struct target
*target
)
506 LOG_DEBUG("%s", __func__
);
510 static int stm32_stlink_halt(struct target
*target
)
513 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
515 LOG_DEBUG("%s", __func__
);
517 if (target
->state
== TARGET_HALTED
) {
518 LOG_DEBUG("target was already halted");
522 if (target
->state
== TARGET_UNKNOWN
)
523 LOG_WARNING("target was in unknown state when halt was requested");
525 res
= stlink_if
->layout
->api
->halt(stlink_if
->fd
);
530 target
->debug_reason
= DBG_REASON_DBGRQ
;
535 static int stm32_stlink_resume(struct target
*target
, int current
,
536 uint32_t address
, int handle_breakpoints
,
540 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
541 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
543 struct breakpoint
*breakpoint
= NULL
;
546 LOG_DEBUG("%s %d 0x%08x %d %d", __func__
, current
, address
,
547 handle_breakpoints
, debug_execution
);
549 if (target
->state
!= TARGET_HALTED
) {
550 LOG_WARNING("target not halted");
551 return ERROR_TARGET_NOT_HALTED
;
556 buf_set_u32(pc
->value
, 0, 32, address
);
561 if (!breakpoint_find(target
, buf_get_u32(pc
->value
, 0, 32))
562 && !debug_execution
) {
563 armv7m_maybe_skip_bkpt_inst(target
, NULL
);
566 resume_pc
= buf_get_u32(pc
->value
, 0, 32);
568 armv7m_restore_context(target
);
570 /* registers are now invalid */
571 register_cache_invalidate(armv7m
->core_cache
);
573 /* the front-end may request us not to handle breakpoints */
574 if (handle_breakpoints
) {
575 /* Single step past breakpoint at current address */
576 breakpoint
= breakpoint_find(target
, resume_pc
);
578 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32
" (ID: %d)",
580 breakpoint
->unique_id
);
581 cortex_m3_unset_breakpoint(target
, breakpoint
);
583 res
= stlink_if
->layout
->api
->step(stlink_if
->fd
);
588 cortex_m3_set_breakpoint(target
, breakpoint
);
592 res
= stlink_if
->layout
->api
->run(stlink_if
->fd
);
597 target
->state
= TARGET_RUNNING
;
598 target
->debug_reason
= DBG_REASON_NOTHALTED
;
600 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
605 static int stm32_stlink_step(struct target
*target
, int current
,
606 uint32_t address
, int handle_breakpoints
)
609 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
610 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
611 struct breakpoint
*breakpoint
= NULL
;
612 struct reg
*pc
= armv7m
->arm
.pc
;
613 bool bkpt_inst_found
= false;
615 LOG_DEBUG("%s", __func__
);
617 if (target
->state
!= TARGET_HALTED
) {
618 LOG_WARNING("target not halted");
619 return ERROR_TARGET_NOT_HALTED
;
623 buf_set_u32(pc
->value
, 0, 32, address
);
628 uint32_t pc_value
= buf_get_u32(pc
->value
, 0, 32);
630 /* the front-end may request us not to handle breakpoints */
631 if (handle_breakpoints
) {
632 breakpoint
= breakpoint_find(target
, pc_value
);
634 cortex_m3_unset_breakpoint(target
, breakpoint
);
637 armv7m_maybe_skip_bkpt_inst(target
, &bkpt_inst_found
);
639 target
->debug_reason
= DBG_REASON_SINGLESTEP
;
641 armv7m_restore_context(target
);
643 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
645 res
= stlink_if
->layout
->api
->step(stlink_if
->fd
);
650 /* registers are now invalid */
651 register_cache_invalidate(armv7m
->core_cache
);
654 cortex_m3_set_breakpoint(target
, breakpoint
);
656 stlink_debug_entry(target
);
657 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
659 LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32));
664 static int stm32_stlink_read_memory(struct target
*target
, uint32_t address
,
665 uint32_t size
, uint32_t count
,
669 uint32_t buffer_threshold
= 128;
670 uint32_t addr_increment
= 4;
672 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
674 if (!count
|| !buffer
)
675 return ERROR_COMMAND_SYNTAX_ERROR
;
677 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
679 /* prepare byte count, buffer threshold
680 * and address increment for none 32bit access
684 buffer_threshold
= 64;
689 if (count
> buffer_threshold
)
690 c
= buffer_threshold
;
695 res
= stlink_if
->layout
->api
->read_mem8(stlink_if
->fd
,
698 res
= stlink_if
->layout
->api
->read_mem32(stlink_if
->fd
,
704 address
+= (c
* addr_increment
);
705 buffer
+= (c
* addr_increment
);
712 static int stm32_stlink_write_memory(struct target
*target
, uint32_t address
,
713 uint32_t size
, uint32_t count
,
714 const uint8_t *buffer
)
717 uint32_t buffer_threshold
= 128;
718 uint32_t addr_increment
= 4;
720 struct stlink_interface_s
*stlink_if
= target_to_stlink(target
);
722 if (!count
|| !buffer
)
723 return ERROR_COMMAND_SYNTAX_ERROR
;
725 LOG_DEBUG("%s 0x%08x %d %d", __func__
, address
, size
, count
);
727 /* prepare byte count, buffer threshold
728 * and address increment for none 32bit access
732 buffer_threshold
= 64;
737 if (count
> buffer_threshold
)
738 c
= buffer_threshold
;
743 res
= stlink_if
->layout
->api
->write_mem8(stlink_if
->fd
,
746 res
= stlink_if
->layout
->api
->write_mem32(stlink_if
->fd
,
752 address
+= (c
* addr_increment
);
753 buffer
+= (c
* addr_increment
);
760 static int stm32_stlink_bulk_write_memory(struct target
*target
,
761 uint32_t address
, uint32_t count
,
762 const uint8_t *buffer
)
764 return stm32_stlink_write_memory(target
, address
, 4, count
, buffer
);
767 static const struct command_registration stm32_stlink_command_handlers
[] = {
769 .chain
= arm_command_handlers
,
771 COMMAND_REGISTRATION_DONE
774 struct target_type stm32_stlink_target
= {
775 .name
= "stm32_stlink",
777 .init_target
= stm32_stlink_init_target
,
778 .target_create
= stm32_stlink_target_create
,
779 .examine
= cortex_m3_examine
,
780 .commands
= stm32_stlink_command_handlers
,
782 .poll
= stm32_stlink_poll
,
783 .arch_state
= armv7m_arch_state
,
785 .assert_reset
= stm32_stlink_assert_reset
,
786 .deassert_reset
= stm32_stlink_deassert_reset
,
787 .soft_reset_halt
= stm32_stlink_soft_reset_halt
,
789 .halt
= stm32_stlink_halt
,
790 .resume
= stm32_stlink_resume
,
791 .step
= stm32_stlink_step
,
793 .get_gdb_reg_list
= armv7m_get_gdb_reg_list
,
795 .read_memory
= stm32_stlink_read_memory
,
796 .write_memory
= stm32_stlink_write_memory
,
797 .bulk_write_memory
= stm32_stlink_bulk_write_memory
,
798 .checksum_memory
= armv7m_checksum_memory
,
799 .blank_check_memory
= armv7m_blank_check_memory
,
801 .run_algorithm
= armv7m_run_algorithm
,
802 .start_algorithm
= armv7m_start_algorithm
,
803 .wait_algorithm
= armv7m_wait_algorithm
,
805 .add_breakpoint
= cortex_m3_add_breakpoint
,
806 .remove_breakpoint
= cortex_m3_remove_breakpoint
,
807 .add_watchpoint
= cortex_m3_add_watchpoint
,
808 .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)