b4a9704c1de5805825c27ac0084f252db7167393
[openocd.git] / src / openocd.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "log.h"
28 #include "types.h"
29 #include "jtag.h"
30 #include "configuration.h"
31 #include "interpreter.h"
32 #include "xsvf.h"
33 #include "target.h"
34 #include "flash.h"
35 #include "nand.h"
36 #include "pld.h"
37
38 #include "command.h"
39 #include "server.h"
40 #include "telnet_server.h"
41 #include "gdb_server.h"
42 #include "tcl_server.h"
43
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <strings.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <errno.h>
52
53 #ifdef __ECOS
54 /* Jim is provied by eCos */
55 #include <cyg/jimtcl/jim.h>
56 #else
57 #define JIM_EMBEDDED
58 #include "jim.h"
59 #endif
60
61
62
63
64 int launchTarget(struct command_context_s *cmd_ctx)
65 {
66 int retval;
67 /* Try to examine & validate jtag chain, though this may require a reset first
68 * in which case we continue setup */
69 jtag_init(cmd_ctx);
70
71 /* try to examine target at this point. If it fails, perhaps a reset will
72 * bring it up later on via a telnet/gdb session */
73 target_examine(cmd_ctx);
74
75 retval=flash_init_drivers(cmd_ctx);
76 if (retval!=ERROR_OK)
77 return retval;
78 LOG_DEBUG("flash init complete");
79
80 retval=nand_init(cmd_ctx);
81 if (retval!=ERROR_OK)
82 return retval;
83 LOG_DEBUG("NAND init complete");
84
85 retval=pld_init(cmd_ctx);
86 if (retval!=ERROR_OK)
87 return retval;
88 LOG_DEBUG("pld init complete");
89 return retval;
90 }
91
92 /* Give TELNET a way to find out what version this is */
93 int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
94 {
95 command_print(cmd_ctx, OPENOCD_VERSION);
96
97 return ERROR_OK;
98 }
99
100 static int daemon_startup = 0;
101
102 int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
103 {
104 if (argc==0)
105 return ERROR_OK;
106 if (argc > 1 )
107 return ERROR_COMMAND_SYNTAX_ERROR;
108
109 daemon_startup = strcmp("reset", args[0])==0;
110
111 command_print(cmd_ctx, OPENOCD_VERSION);
112
113 return ERROR_OK;
114 }
115
116
117 void exit_handler(void)
118 {
119 /* close JTAG interface */
120 if (jtag && jtag->quit)
121 jtag->quit();
122 }
123
124
125 /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
126 int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
127 {
128 int retval;
129 static int initialized=0;
130 if (initialized)
131 return ERROR_OK;
132
133 initialized=1;
134
135 command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
136
137 atexit(exit_handler);
138
139
140 if (target_init(cmd_ctx) != ERROR_OK)
141 return ERROR_FAIL;
142 LOG_DEBUG("target init complete");
143
144 if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
145 {
146 /* we must be able to set up the jtag interface */
147 return retval;
148 }
149 LOG_DEBUG("jtag interface init complete");
150
151 /* Try to initialize & examine the JTAG chain at this point, but
152 * continue startup regardless
153 */
154 if (jtag_init(cmd_ctx) == ERROR_OK)
155 {
156 LOG_DEBUG("jtag init complete");
157 if (target_examine(cmd_ctx) == ERROR_OK)
158 {
159 LOG_DEBUG("jtag examine complete");
160 }
161 }
162
163
164 if (flash_init_drivers(cmd_ctx) != ERROR_OK)
165 return ERROR_FAIL;
166 LOG_DEBUG("flash init complete");
167
168 if (nand_init(cmd_ctx) != ERROR_OK)
169 return ERROR_FAIL;
170 LOG_DEBUG("NAND init complete");
171
172 if (pld_init(cmd_ctx) != ERROR_OK)
173 return ERROR_FAIL;
174 LOG_DEBUG("pld init complete");
175
176 /* initialize tcp server */
177 server_init();
178
179 /* initialize telnet subsystem */
180 telnet_init("Open On-Chip Debugger");
181 gdb_init();
182 tcl_init(); /* allows tcl to just connect without going thru telnet */
183
184 return ERROR_OK;
185 }
186
187
188 void lockBigLock();
189 void unlockBigLock();
190
191
192
193 Jim_Interp *interp;
194 command_context_t *active_cmd_ctx;
195
196 static int
197 new_int_array_element( Jim_Interp * interp,
198 const char *varname,
199 int idx,
200 u32 val )
201 {
202 char *namebuf;
203 Jim_Obj *nameObjPtr, *valObjPtr;
204 int result;
205
206 namebuf = alloc_printf("%s(%d)", varname, idx );
207
208
209 nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
210 valObjPtr = Jim_NewIntObj(interp, val );
211 Jim_IncrRefCount(nameObjPtr);
212 Jim_IncrRefCount(valObjPtr);
213 result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
214 Jim_DecrRefCount(interp, nameObjPtr);
215 Jim_DecrRefCount(interp, valObjPtr);
216 free(namebuf);
217 // printf( "%s = 0%08x\n", namebuf, val );
218 return result;
219 }
220
221 static int
222 Jim_Command_mem2array( Jim_Interp *interp, int argc, Jim_Obj *const *argv)
223 {
224 target_t *target;
225 long l;
226 u32 width;
227 u32 len;
228 u32 addr;
229 u32 count;
230 u32 v;
231 const char *varname;
232 u8 buffer[4096];
233 int i,n,e,retval;
234
235
236 /* argv[1] = name of array to receive the data
237 * argv[2] = desired width
238 * argv[3] = memory address
239 * argv[4] = length in bytes to read
240 */
241 if( argc != 5 ){
242 Jim_WrongNumArgs( interp, 1, argv, "varname width addr nelems" );
243 return JIM_ERR;
244 }
245 varname = Jim_GetString( argv[1], &len );
246 /* given "foo" get space for worse case "foo(%d)" .. add 20 */
247
248
249 e = Jim_GetLong( interp, argv[2], &l );
250 width = l;
251 if( e != JIM_OK ){
252 return e;
253 }
254
255 e = Jim_GetLong( interp, argv[3], &l );
256 addr = l;
257 if( e != JIM_OK ){
258 return e;
259 }
260 e = Jim_GetLong( interp, argv[4], &l );
261 len = l;
262 if( e != JIM_OK ){
263 return e;
264 }
265 switch(width){
266 case 8:
267 width = 1;
268 break;
269 case 16:
270 width = 2;
271 break;
272 case 32:
273 width = 4;
274 break;
275 default:
276 Jim_SetResult(interp,
277 Jim_NewEmptyStringObj(interp));
278 Jim_AppendStrings( interp, Jim_GetResult(interp),
279 "Invalid width param, must be 8/16/32", NULL );
280 return JIM_ERR;
281 }
282 if( len == 0 ){
283 Jim_SetResult(interp,
284 Jim_NewEmptyStringObj(interp));
285 Jim_AppendStrings( interp, Jim_GetResult(interp),
286 "mem2array: zero width read?", NULL );
287 return JIM_ERR;
288 }
289 if( (addr + (len * width)) < addr ){
290 Jim_SetResult(interp,
291 Jim_NewEmptyStringObj(interp));
292 Jim_AppendStrings( interp, Jim_GetResult(interp),
293 "mem2array: addr + len - wraps to zero?", NULL );
294 return JIM_ERR;
295 }
296 /* absurd transfer size? */
297 if( len > 65536 ){
298 Jim_SetResult(interp,
299 Jim_NewEmptyStringObj(interp));
300 Jim_AppendStrings( interp, Jim_GetResult(interp),
301 "mem2array: absurd > 64K item request", NULL );
302 return JIM_ERR;
303 }
304
305 if( (width == 1) ||
306 ((width == 2) && ((addr & 1) == 0)) ||
307 ((width == 4) && ((addr & 3) == 0)) ){
308 /* all is well */
309 } else {
310 char buf[100];
311 Jim_SetResult(interp,
312 Jim_NewEmptyStringObj(interp));
313 sprintf( buf,
314 "mem2array address: 0x%08x is not aligned for %d byte reads",
315 addr, width );
316
317 Jim_AppendStrings( interp, Jim_GetResult(interp),
318 buf , NULL );
319 return JIM_ERR;
320 }
321
322 target = get_current_target( active_cmd_ctx );
323
324 /* Transfer loop */
325
326 /* index counter */
327 n = 0;
328 /* assume ok */
329 e = JIM_OK;
330 while( len ){
331
332 /* Slurp... in buffer size chunks */
333
334 count = len; /* in objects.. */
335 if( count > (sizeof(buffer)/width)){
336 count = (sizeof(buffer)/width);
337 }
338
339 retval = target->type->read_memory( target,
340 addr,
341 width,
342 count,
343 buffer );
344
345 if( retval != ERROR_OK ){
346 /* BOO !*/
347 LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
348 addr, width, count );
349 Jim_SetResult(interp,
350 Jim_NewEmptyStringObj(interp));
351 Jim_AppendStrings( interp, Jim_GetResult(interp),
352 "mem2array: cannot read memory", NULL );
353 e = JIM_ERR;
354 len = 0;
355 } else {
356 v = 0; /* shut up gcc */
357 for( i = 0 ; i < count ; i++, n++ ){
358 switch(width){
359 case 4:
360 v = target_buffer_get_u32( target, &buffer[i*width] );
361 break;
362 case 2:
363 v = target_buffer_get_u16( target, &buffer[i*width] );
364 break;
365 case 1:
366 v = buffer[i] & 0x0ff;
367 break;
368 }
369 new_int_array_element( interp, varname, n, v );
370 }
371 len -= count;
372 }
373 }
374 Jim_SetResult(interp,
375 Jim_NewEmptyStringObj(interp));
376
377 return JIM_OK;
378 }
379
380 static void tcl_output(void *privData, const char *file, int line,
381 const char *function, const char *string)
382 {
383 Jim_Obj *tclOutput=(Jim_Obj *)privData;
384
385 Jim_AppendString(interp, tclOutput, string, strlen(string));
386 }
387
388 /* try to execute as Jim command, otherwise fall back to standard command.
389
390 Note that even if the Jim command caused an error, then we succeeded
391 to execute it, hence this fn pretty much always returns ERROR_OK.
392
393 */
394 int jim_command(command_context_t *context, char *line)
395 {
396 int retval=ERROR_OK;
397 /* FIX!!!! in reality there is only one cmd_ctx handler, but consider
398 what might happen here if there are multiple handlers w/reentrant callback
399 fn's... shudder! */
400 active_cmd_ctx=context;
401 int retcode=Jim_Eval(interp, line);
402
403 const char *result;
404 int reslen;
405 result = Jim_GetString(Jim_GetResult(interp), &reslen);
406 if (retcode == JIM_ERR) {
407 int len, i;
408
409 LOG_USER_N("Runtime error, file \"%s\", line %d:" JIM_NL,
410 interp->errorFileName, interp->errorLine);
411 LOG_USER_N(" %s" JIM_NL,
412 Jim_GetString(interp->result, NULL));
413 Jim_ListLength(interp, interp->stackTrace, &len);
414 for (i = 0; i < len; i+= 3) {
415 Jim_Obj *objPtr;
416 const char *proc, *file, *line;
417
418 Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
419 proc = Jim_GetString(objPtr, NULL);
420 Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
421 JIM_NONE);
422 file = Jim_GetString(objPtr, NULL);
423 Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
424 JIM_NONE);
425 line = Jim_GetString(objPtr, NULL);
426 LOG_USER_N("In procedure '%s' called at file \"%s\", line %s" JIM_NL,
427 proc, file, line);
428 }
429 } else if (retcode == JIM_EXIT) {
430 // ignore.
431 //exit(Jim_GetExitCode(interp));
432 } else {
433 if (reslen) {
434 int i;
435 char buff[256+1];
436 for (i=0; i<reslen; i+=256)
437 {
438 int chunk;
439 chunk=reslen-i;
440 if (chunk>256)
441 chunk=256;
442 strncpy(buff, result, chunk);
443 buff[chunk]=0;
444 LOG_USER_N("%s", buff);
445 }
446 LOG_USER_N("%s", "\n");
447 }
448 }
449 return retval;
450 }
451
452 int startLoop=0;
453
454 static int
455 Jim_Command_openocd_ignore(Jim_Interp *interp,
456 int argc,
457 Jim_Obj *const *argv,
458 int ignore)
459 {
460 int retval;
461 char *cmd = (char*)Jim_GetString(argv[1], NULL);
462
463 lockBigLock();
464
465 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
466
467 if (startLoop)
468 {
469 // We don't know whether or not the telnet/gdb server is running...
470 target_call_timer_callbacks_now();
471 }
472
473 log_add_callback(tcl_output, tclOutput);
474 retval=command_run_line_internal(active_cmd_ctx, cmd);
475
476 if (startLoop)
477 {
478 target_call_timer_callbacks_now();
479 }
480 log_remove_callback(tcl_output, tclOutput);
481
482 Jim_SetResult(interp, tclOutput);
483 unlockBigLock();
484
485 return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
486 }
487
488 static int
489 Jim_Command_openocd(Jim_Interp *interp,
490 int argc,
491 Jim_Obj *const *argv)
492 {
493 return Jim_Command_openocd_ignore(interp, argc, argv, 1);
494 }
495
496 static int
497 Jim_Command_openocd_throw(Jim_Interp *interp,
498 int argc,
499 Jim_Obj *const *argv)
500 {
501 return Jim_Command_openocd_ignore(interp, argc, argv, 0);
502 }
503
504
505
506
507 /* find full path to file */
508 static int
509 Jim_Command_find(Jim_Interp *interp,
510 int argc,
511 Jim_Obj *const *argv)
512 {
513 if (argc!=2)
514 return JIM_ERR;
515 char *file = (char*)Jim_GetString(argv[1], NULL);
516 char *full_path=find_file(file);
517 if (full_path==NULL)
518 return JIM_ERR;
519 Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
520 free(full_path);
521
522 Jim_SetResult(interp, result);
523 return JIM_OK;
524 }
525
526 static int
527 Jim_Command_echo(Jim_Interp *interp,
528 int argc,
529 Jim_Obj *const *argv)
530 {
531 if (argc!=2)
532 return JIM_ERR;
533 char *str = (char*)Jim_GetString(argv[1], NULL);
534 LOG_USER("%s", str);
535 return JIM_OK;
536 }
537
538 void command_output_text( command_context_t *context, const char *data );
539
540 static size_t
541 openocd_jim_fwrite( const void *_ptr, size_t size, size_t n, void *cookie )
542 {
543 size_t nbytes;
544 const char *ptr;
545
546 /* make it a char easier to read code */
547 ptr = _ptr;
548
549 nbytes = size * n;
550 if( nbytes == 0 ){
551 return 0;
552 }
553
554 if( !active_cmd_ctx ){
555 /* FIXME: Where should this go? */
556 return n;
557 }
558
559
560 /* do we have to chunk it? */
561 if( ptr[ nbytes ] == 0 ){
562 /* no it is a C style string */
563 command_output_text( active_cmd_ctx, ptr );
564 return strlen(ptr);
565 }
566 /* GRR we must chunk - not null terminated */
567 while( nbytes ){
568 char chunk[128+1];
569 int x;
570
571 x = nbytes;
572 if( x > 128 ){
573 x = 128;
574 }
575 /* copy it */
576 memcpy( chunk, ptr, x );
577 /* terminate it */
578 chunk[n] = 0;
579 /* output it */
580 command_output_text( active_cmd_ctx, chunk );
581 ptr += x;
582 nbytes -= x;
583 }
584
585 return n;
586 }
587
588 static size_t
589 openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
590 {
591 /* TCL wants to read... tell him no */
592 return 0;
593 }
594
595
596 static int
597 openocd_jim_vfprintf( void *cookie, const char *fmt, va_list ap )
598 {
599 char *cp;
600 int n;
601
602 n = -1;
603 if( active_cmd_ctx ){
604 cp = alloc_vprintf( fmt, ap );
605 if( cp ){
606 command_output_text( active_cmd_ctx, cp );
607 n = strlen(cp);
608 free(cp);
609 }
610 }
611 return n;
612 }
613
614 static int
615 openocd_jim_fflush( void *cookie )
616 {
617 /* nothing to flush */
618 return 0;
619 }
620
621 static char *
622 openocd_jim_fgets( char *s, int size, void *cookie )
623 {
624 /* not supported */
625 errno = ENOTSUP;
626 return NULL;
627 }
628
629
630
631 void initJim(void)
632 {
633 Jim_CreateCommand(interp, "openocd", Jim_Command_openocd, NULL, NULL);
634 Jim_CreateCommand(interp, "openocd_throw", Jim_Command_openocd_throw, NULL, NULL);
635 Jim_CreateCommand(interp, "find", Jim_Command_find, NULL, NULL);
636 Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
637 Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
638
639 /* Set Jim's STDIO */
640 interp->cookie_stdin = NULL;
641 interp->cookie_stdout = NULL;
642 interp->cookie_stderr = NULL;
643 interp->cb_fwrite = openocd_jim_fwrite;
644 interp->cb_fread = openocd_jim_fread ;
645 interp->cb_vfprintf = openocd_jim_vfprintf;
646 interp->cb_fflush = openocd_jim_fflush;
647 interp->cb_fgets = openocd_jim_fgets;
648 }
649
650 /* after command line parsing */
651 void initJim2(void)
652 {
653 Jim_Eval(interp, "source [find tcl/commands.tcl]");
654 }
655
656 command_context_t *setup_command_handler()
657 {
658 command_context_t *cmd_ctx;
659
660 cmd_ctx = command_init();
661
662 register_command(cmd_ctx, NULL, "version", handle_version_command,
663 COMMAND_EXEC, "show OpenOCD version");
664 register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG,
665 "deprecated - use \"init\" and \"reset\" at end of startup script instead");
666
667 /* register subsystem commands */
668 server_register_commands(cmd_ctx);
669 telnet_register_commands(cmd_ctx);
670 gdb_register_commands(cmd_ctx);
671 tcl_register_commands(cmd_ctx); /* tcl server commands */
672 log_register_commands(cmd_ctx);
673 jtag_register_commands(cmd_ctx);
674 interpreter_register_commands(cmd_ctx);
675 xsvf_register_commands(cmd_ctx);
676 target_register_commands(cmd_ctx);
677 flash_register_commands(cmd_ctx);
678 nand_register_commands(cmd_ctx);
679 pld_register_commands(cmd_ctx);
680
681 if (log_init(cmd_ctx) != ERROR_OK)
682 {
683 exit(-1);
684 }
685 LOG_DEBUG("log init complete");
686
687 LOG_OUTPUT( OPENOCD_VERSION "\n" );
688
689
690 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
691 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
692 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
693 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
694 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
695 LOG_OUTPUT( "$URL$\n");
696 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
697 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
698 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
699 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
700 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
701
702 register_command(cmd_ctx, NULL, "init", handle_init_command,
703 COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
704
705 return cmd_ctx;
706 }
707
708 /*
709 normally this is the main() function entry, but if OpenOCD is linked
710 into application, then this fn will not be invoked, but rather that
711 application will have it's own implementation of main().
712 */
713 int openocd_main(int argc, char *argv[])
714 {
715 #ifdef JIM_EMBEDDED
716 Jim_InitEmbedded();
717 /* Create an interpreter */
718 interp = Jim_CreateInterp();
719 /* Add all the Jim core commands */
720 Jim_RegisterCoreCommands(interp);
721 #endif
722
723 initJim();
724
725 /* initialize commandline interface */
726 command_context_t *cmd_ctx;
727 cmd_ctx=setup_command_handler();
728
729 command_context_t *cfg_cmd_ctx;
730 cfg_cmd_ctx = copy_command_context(cmd_ctx);
731 cfg_cmd_ctx->mode = COMMAND_CONFIG;
732 command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
733
734 if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
735 return EXIT_FAILURE;
736
737 initJim2();
738
739 if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
740 return EXIT_FAILURE;
741
742 command_done(cfg_cmd_ctx);
743
744 if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
745 return EXIT_FAILURE;
746
747 if (daemon_startup)
748 command_run_line(cmd_ctx, "reset");
749
750
751 startLoop=1;
752
753 /* handle network connections */
754 server_loop(cmd_ctx);
755
756 /* shut server down */
757 server_quit();
758
759 unregister_all_commands(cmd_ctx);
760
761 /* free commandline interface */
762 command_done(cmd_ctx);
763
764 return EXIT_SUCCESS;
765 }
766
767
768 /*
769 * Local Variables: **
770 * tab-width: 4 **
771 * c-basic-offset: 4 **
772 * End: **
773 */
774

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)