helper: Make unhexify() robust on invalid data
[openocd.git] / src / jtag / drivers / ti_icdi_usb.c
1 /***************************************************************************
2 * *
3 * Copyright (C) 2012 by Spencer Oliver *
4 * spen@spen-soft.co.uk *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 /* project specific includes */
25 #include <helper/binarybuffer.h>
26 #include <jtag/interface.h>
27 #include <jtag/hla/hla_layout.h>
28 #include <jtag/hla/hla_transport.h>
29 #include <jtag/hla/hla_interface.h>
30 #include <target/target.h>
31
32 #include <target/cortex_m.h>
33
34 #include <libusb.h>
35
36 #define ICDI_WRITE_ENDPOINT 0x02
37 #define ICDI_READ_ENDPOINT 0x83
38
39 #define ICDI_WRITE_TIMEOUT 1000
40 #define ICDI_READ_TIMEOUT 1000
41 #define ICDI_PACKET_SIZE 2048
42
43 #define PACKET_START "$"
44 #define PACKET_END "#"
45
46 struct icdi_usb_handle_s {
47 libusb_context *usb_ctx;
48 libusb_device_handle *usb_dev;
49
50 char *read_buffer;
51 char *write_buffer;
52 int max_packet;
53 int read_count;
54 uint32_t max_rw_packet; /* max X packet (read/write memory) transfers */
55 };
56
57 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
58 uint32_t count, uint8_t *buffer);
59 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
60 uint32_t count, const uint8_t *buffer);
61
62 static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen)
63 {
64 int input_index, output_index;
65
66 output_index = 0;
67
68 for (input_index = 0; input_index < len; input_index++) {
69
70 char b = buffer[input_index];
71
72 if (b == '$' || b == '#' || b == '}' || b == '*') {
73 /* These must be escaped. */
74 if (output_index + 2 > out_maxlen)
75 break;
76 out_buf[output_index++] = '}';
77 out_buf[output_index++] = b ^ 0x20;
78 } else {
79 if (output_index + 1 > out_maxlen)
80 break;
81 out_buf[output_index++] = b;
82 }
83 }
84
85 *out_len = input_index;
86 return output_index;
87 }
88
89 static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen)
90 {
91 int input_index, output_index;
92 int escaped;
93
94 output_index = 0;
95 escaped = 0;
96
97 for (input_index = 0; input_index < len; input_index++) {
98
99 char b = buffer[input_index];
100
101 if (output_index + 1 > out_maxlen)
102 LOG_ERROR("Received too much data from the target.");
103
104 if (escaped) {
105 out_buf[output_index++] = b ^ 0x20;
106 escaped = 0;
107 } else if (b == '}')
108 escaped = 1;
109 else
110 out_buf[output_index++] = b;
111 }
112
113 if (escaped)
114 LOG_ERROR("Unmatched escape character in target response.");
115
116 return output_index;
117 }
118
119 static int icdi_send_packet(void *handle, int len)
120 {
121 unsigned char cksum = 0;
122 struct icdi_usb_handle_s *h = handle;
123 int result, retry = 0;
124 int transferred = 0;
125
126 assert(handle != NULL);
127
128 /* check we have a large enough buffer for checksum "#00" */
129 if (len + 3 > h->max_packet) {
130 LOG_ERROR("packet buffer too small");
131 return ERROR_FAIL;
132 }
133
134 /* calculate checksum - offset start of packet */
135 for (int i = 1; i < len; i++)
136 cksum += h->write_buffer[i];
137
138 len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum);
139
140 #ifdef _DEBUG_USB_COMMS_
141 char buffer[50];
142 char ch = h->write_buffer[1];
143 if (ch == 'x' || ch == 'X')
144 LOG_DEBUG("writing packet: <binary>");
145 else {
146 memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len);
147 buffer[len] = 0;
148 LOG_DEBUG("writing packet: %s", buffer);
149 }
150 #endif
151
152 while (1) {
153
154 result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len,
155 &transferred, ICDI_WRITE_TIMEOUT);
156 if (result != 0 || transferred != len) {
157 LOG_DEBUG("Error TX Data %d", result);
158 return ERROR_FAIL;
159 }
160
161 /* check that the client got the message ok, or shall we resend */
162 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet,
163 &transferred, ICDI_READ_TIMEOUT);
164 if (result != 0 || transferred < 1) {
165 LOG_DEBUG("Error RX Data %d", result);
166 return ERROR_FAIL;
167 }
168
169 #ifdef _DEBUG_USB_COMMS_
170 LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred);
171 #endif
172
173 if (h->read_buffer[0] == '-') {
174 LOG_DEBUG("Resending packet %d", ++retry);
175 } else {
176 if (h->read_buffer[0] != '+')
177 LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]);
178 break;
179 }
180
181 if (retry == 3) {
182 LOG_DEBUG("maximum nack retries attempted");
183 return ERROR_FAIL;
184 }
185 }
186
187 retry = 0;
188 h->read_count = transferred;
189
190 while (1) {
191
192 /* read reply from icdi */
193 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count,
194 h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT);
195
196 #ifdef _DEBUG_USB_COMMS_
197 LOG_DEBUG("received data: count %d", transferred);
198 #endif
199
200 /* check for errors but retry for timeout */
201 if (result != 0) {
202
203 if (result == LIBUSB_ERROR_TIMEOUT) {
204 LOG_DEBUG("Error RX timeout %d", result);
205 } else {
206 LOG_DEBUG("Error RX Data %d", result);
207 return ERROR_FAIL;
208 }
209 }
210
211 h->read_count += transferred;
212
213 /* we need to make sure we have a full packet, including checksum */
214 if (h->read_count > 5) {
215
216 /* check that we have received an packet delimiter
217 * we do not validate the checksum
218 * reply should contain $...#AA - so we check for # */
219 if (h->read_buffer[h->read_count - 3] == '#')
220 return ERROR_OK;
221 }
222
223 if (retry++ == 3) {
224 LOG_DEBUG("maximum data retries attempted");
225 break;
226 }
227 }
228
229 return ERROR_FAIL;
230 }
231
232 static int icdi_send_cmd(void *handle, const char *cmd)
233 {
234 struct icdi_usb_handle_s *h = handle;
235
236 int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd);
237 return icdi_send_packet(handle, cmd_len);
238 }
239
240 static int icdi_send_remote_cmd(void *handle, const char *data)
241 {
242 struct icdi_usb_handle_s *h = handle;
243
244 size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,");
245 cmd_len += hexify(h->write_buffer + cmd_len, data, 0, h->max_packet - cmd_len);
246
247 return icdi_send_packet(handle, cmd_len);
248 }
249
250 static int icdi_get_cmd_result(void *handle)
251 {
252 struct icdi_usb_handle_s *h = handle;
253 int offset = 0;
254 char ch;
255
256 assert(handle != NULL);
257
258 do {
259 ch = h->read_buffer[offset++];
260 if (offset > h->read_count)
261 return ERROR_FAIL;
262 } while (ch != '$');
263
264 if (memcmp("OK", h->read_buffer + offset, 2) == 0)
265 return ERROR_OK;
266
267 if (h->read_buffer[offset] == 'E') {
268 /* get error code */
269 uint8_t result;
270 if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1)
271 return ERROR_FAIL;
272 return result;
273 }
274
275 /* for now we assume everything else is ok */
276 return ERROR_OK;
277 }
278
279 static int icdi_usb_idcode(void *handle, uint32_t *idcode)
280 {
281 *idcode = 0;
282 return ERROR_OK;
283 }
284
285 static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
286 {
287 uint8_t buf[4];
288 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_set_u32().
289 * I guess all supported chips are little-endian anyway. */
290 h_u32_to_le(buf, val);
291 return icdi_usb_write_mem(handle, addr, 4, 1, buf);
292 }
293
294 static enum target_state icdi_usb_state(void *handle)
295 {
296 int result;
297 struct icdi_usb_handle_s *h = handle;
298 uint32_t dhcsr;
299 uint8_t buf[4];
300
301 result = icdi_usb_read_mem(h, DCB_DHCSR, 4, 1, buf);
302 if (result != ERROR_OK)
303 return TARGET_UNKNOWN;
304
305 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_get_u32().
306 * I guess all supported chips are little-endian anyway. */
307 dhcsr = le_to_h_u32(buf);
308 if (dhcsr & S_HALT)
309 return TARGET_HALTED;
310
311 return TARGET_RUNNING;
312 }
313
314 static int icdi_usb_version(void *handle)
315 {
316 struct icdi_usb_handle_s *h = handle;
317
318 char version[20];
319
320 /* get info about icdi */
321 int result = icdi_send_remote_cmd(handle, "version");
322 if (result != ERROR_OK)
323 return result;
324
325 if (h->read_count < 8) {
326 LOG_ERROR("Invalid Reply Received");
327 return ERROR_FAIL;
328 }
329
330 /* convert reply */
331 if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) {
332 LOG_WARNING("unable to get ICDI version");
333 return ERROR_OK;
334 }
335
336 /* null terminate and print info */
337 version[4] = 0;
338
339 LOG_INFO("ICDI Firmware version: %s", version);
340
341 return ERROR_OK;
342 }
343
344 static int icdi_usb_query(void *handle)
345 {
346 int result;
347
348 struct icdi_usb_handle_s *h = handle;
349
350 result = icdi_send_cmd(handle, "qSupported");
351 if (result != ERROR_OK)
352 return result;
353
354 /* check result */
355 result = icdi_get_cmd_result(handle);
356 if (result != ERROR_OK) {
357 LOG_ERROR("query supported failed: 0x%x", result);
358 return ERROR_FAIL;
359 }
360
361 /* from this we can get the max packet supported */
362
363 /* query packet buffer size */
364 char *offset = strstr(h->read_buffer, "PacketSize");
365 if (offset) {
366 char *separator;
367 int max_packet;
368
369 max_packet = strtol(offset + 11, &separator, 16);
370 if (!max_packet)
371 LOG_ERROR("invalid max packet, using defaults");
372 else
373 h->max_packet = max_packet;
374 LOG_DEBUG("max packet supported : %i bytes", h->max_packet);
375 }
376
377
378 /* if required re allocate packet buffer */
379 if (h->max_packet != ICDI_PACKET_SIZE) {
380 h->read_buffer = realloc(h->read_buffer, h->max_packet);
381 h->write_buffer = realloc(h->write_buffer, h->max_packet);
382 if (h->read_buffer == 0 || h->write_buffer == 0) {
383 LOG_ERROR("unable to reallocate memory");
384 return ERROR_FAIL;
385 }
386 }
387
388 /* set extended mode */
389 result = icdi_send_cmd(handle, "!");
390 if (result != ERROR_OK)
391 return result;
392
393 /* check result */
394 result = icdi_get_cmd_result(handle);
395 if (result != ERROR_OK) {
396 LOG_ERROR("unable to enable extended mode: 0x%x", result);
397 return ERROR_FAIL;
398 }
399
400 return ERROR_OK;
401 }
402
403 static int icdi_usb_reset(void *handle)
404 {
405 /* we do this in hla_target.c */
406 return ERROR_OK;
407 }
408
409 static int icdi_usb_assert_srst(void *handle, int srst)
410 {
411 /* TODO not supported yet */
412 return ERROR_COMMAND_NOTFOUND;
413 }
414
415 static int icdi_usb_run(void *handle)
416 {
417 int result;
418
419 /* resume target at current address */
420 result = icdi_send_cmd(handle, "c");
421 if (result != ERROR_OK)
422 return result;
423
424 /* check result */
425 result = icdi_get_cmd_result(handle);
426 if (result != ERROR_OK) {
427 LOG_ERROR("continue failed: 0x%x", result);
428 return ERROR_FAIL;
429 }
430
431 return result;
432 }
433
434 static int icdi_usb_halt(void *handle)
435 {
436 int result;
437
438 /* this query halts the target ?? */
439 result = icdi_send_cmd(handle, "?");
440 if (result != ERROR_OK)
441 return result;
442
443 /* check result */
444 result = icdi_get_cmd_result(handle);
445 if (result != ERROR_OK) {
446 LOG_ERROR("halt failed: 0x%x", result);
447 return ERROR_FAIL;
448 }
449
450 return result;
451 }
452
453 static int icdi_usb_step(void *handle)
454 {
455 int result;
456
457 /* step target at current address */
458 result = icdi_send_cmd(handle, "s");
459 if (result != ERROR_OK)
460 return result;
461
462 /* check result */
463 result = icdi_get_cmd_result(handle);
464 if (result != ERROR_OK) {
465 LOG_ERROR("step failed: 0x%x", result);
466 return ERROR_FAIL;
467 }
468
469 return result;
470 }
471
472 static int icdi_usb_read_regs(void *handle)
473 {
474 /* currently unsupported */
475 return ERROR_OK;
476 }
477
478 static int icdi_usb_read_reg(void *handle, int num, uint32_t *val)
479 {
480 int result;
481 struct icdi_usb_handle_s *h = handle;
482 char cmd[10];
483
484 snprintf(cmd, sizeof(cmd), "p%x", num);
485 result = icdi_send_cmd(handle, cmd);
486 if (result != ERROR_OK)
487 return result;
488
489 /* check result */
490 result = icdi_get_cmd_result(handle);
491 if (result != ERROR_OK) {
492 LOG_ERROR("register read failed: 0x%x", result);
493 return ERROR_FAIL;
494 }
495
496 /* convert result */
497 uint8_t buf[4];
498 if (unhexify(buf, h->read_buffer + 2, 4) != 4) {
499 LOG_ERROR("failed to convert result");
500 return ERROR_FAIL;
501 }
502 *val = le_to_h_u32(buf);
503
504 return result;
505 }
506
507 static int icdi_usb_write_reg(void *handle, int num, uint32_t val)
508 {
509 int result;
510 char cmd[20];
511 uint8_t buf[4];
512 h_u32_to_le(buf, val);
513
514 int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num);
515 hexify(cmd + cmd_len, (const char *)buf, 4, sizeof(cmd));
516
517 result = icdi_send_cmd(handle, cmd);
518 if (result != ERROR_OK)
519 return result;
520
521 /* check result */
522 result = icdi_get_cmd_result(handle);
523 if (result != ERROR_OK) {
524 LOG_ERROR("register write failed: 0x%x", result);
525 return ERROR_FAIL;
526 }
527
528 return result;
529 }
530
531 static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer)
532 {
533 int result;
534 struct icdi_usb_handle_s *h = handle;
535 char cmd[20];
536
537 snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len);
538 result = icdi_send_cmd(handle, cmd);
539 if (result != ERROR_OK)
540 return result;
541
542 /* check result */
543 result = icdi_get_cmd_result(handle);
544 if (result != ERROR_OK) {
545 LOG_ERROR("memory read failed: 0x%x", result);
546 return ERROR_FAIL;
547 }
548
549 /* unescape input */
550 int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len);
551 if (read_len != (int)len) {
552 LOG_ERROR("read more bytes than expected: actual 0x%x expected 0x%" PRIx32, read_len, len);
553 return ERROR_FAIL;
554 }
555
556 return ERROR_OK;
557 }
558
559 static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer)
560 {
561 int result;
562 struct icdi_usb_handle_s *h = handle;
563
564 size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len);
565
566 int out_len;
567 cmd_len += remote_escape_output((const char *)buffer, len, h->write_buffer + cmd_len,
568 &out_len, h->max_packet - cmd_len);
569
570 if (out_len < (int)len) {
571 /* for now issue a error as we have no way of allocating a larger buffer */
572 LOG_ERROR("memory buffer too small: requires 0x%x actual 0x%" PRIx32, out_len, len);
573 return ERROR_FAIL;
574 }
575
576 result = icdi_send_packet(handle, cmd_len);
577 if (result != ERROR_OK)
578 return result;
579
580 /* check result */
581 result = icdi_get_cmd_result(handle);
582 if (result != ERROR_OK) {
583 LOG_ERROR("memory write failed: 0x%x", result);
584 return ERROR_FAIL;
585 }
586
587 return ERROR_OK;
588 }
589
590 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
591 uint32_t count, uint8_t *buffer)
592 {
593 int retval = ERROR_OK;
594 struct icdi_usb_handle_s *h = handle;
595 uint32_t bytes_remaining;
596
597 /* calculate byte count */
598 count *= size;
599
600 while (count) {
601
602 bytes_remaining = h->max_rw_packet;
603 if (count < bytes_remaining)
604 bytes_remaining = count;
605
606 retval = icdi_usb_read_mem_int(handle, addr, bytes_remaining, buffer);
607 if (retval != ERROR_OK)
608 return retval;
609
610 buffer += bytes_remaining;
611 addr += bytes_remaining;
612 count -= bytes_remaining;
613 }
614
615 return retval;
616 }
617
618 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
619 uint32_t count, const uint8_t *buffer)
620 {
621 int retval = ERROR_OK;
622 struct icdi_usb_handle_s *h = handle;
623 uint32_t bytes_remaining;
624
625 /* calculate byte count */
626 count *= size;
627
628 while (count) {
629
630 bytes_remaining = h->max_rw_packet;
631 if (count < bytes_remaining)
632 bytes_remaining = count;
633
634 retval = icdi_usb_write_mem_int(handle, addr, bytes_remaining, buffer);
635 if (retval != ERROR_OK)
636 return retval;
637
638 buffer += bytes_remaining;
639 addr += bytes_remaining;
640 count -= bytes_remaining;
641 }
642
643 return retval;
644 }
645
646 static int icdi_usb_override_target(const char *targetname)
647 {
648 return !strcmp(targetname, "cortex_m");
649 }
650
651 static int icdi_usb_close(void *handle)
652 {
653 struct icdi_usb_handle_s *h = handle;
654
655 if (!h)
656 return ERROR_OK;
657
658 if (h->usb_dev)
659 libusb_close(h->usb_dev);
660
661 if (h->usb_ctx)
662 libusb_exit(h->usb_ctx);
663
664 if (h->read_buffer)
665 free(h->read_buffer);
666
667 if (h->write_buffer)
668 free(h->write_buffer);
669
670 free(handle);
671
672 return ERROR_OK;
673 }
674
675 static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
676 {
677 int retval;
678 struct icdi_usb_handle_s *h;
679
680 LOG_DEBUG("icdi_usb_open");
681
682 h = calloc(1, sizeof(struct icdi_usb_handle_s));
683
684 if (h == 0) {
685 LOG_ERROR("unable to allocate memory");
686 return ERROR_FAIL;
687 }
688
689 LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
690 param->vid, param->pid);
691
692 if (libusb_init(&h->usb_ctx) != 0) {
693 LOG_ERROR("libusb init failed");
694 goto error_open;
695 }
696
697 h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid, param->pid);
698 if (!h->usb_dev) {
699 LOG_ERROR("open failed");
700 goto error_open;
701 }
702
703 if (libusb_claim_interface(h->usb_dev, 2)) {
704 LOG_DEBUG("claim interface failed");
705 goto error_open;
706 }
707
708 /* check if mode is supported */
709 retval = ERROR_OK;
710
711 switch (param->transport) {
712 #if 0
713 /* TODO place holder as swd is not currently supported */
714 case HL_TRANSPORT_SWD:
715 #endif
716 case HL_TRANSPORT_JTAG:
717 break;
718 default:
719 retval = ERROR_FAIL;
720 break;
721 }
722
723 if (retval != ERROR_OK) {
724 LOG_ERROR("mode (transport) not supported by device");
725 goto error_open;
726 }
727
728 /* allocate buffer */
729 h->read_buffer = malloc(ICDI_PACKET_SIZE);
730 h->write_buffer = malloc(ICDI_PACKET_SIZE);
731 h->max_packet = ICDI_PACKET_SIZE;
732
733 if (h->read_buffer == 0 || h->write_buffer == 0) {
734 LOG_DEBUG("malloc failed");
735 goto error_open;
736 }
737
738 /* query icdi version etc */
739 retval = icdi_usb_version(h);
740 if (retval != ERROR_OK)
741 goto error_open;
742
743 /* query icdi support */
744 retval = icdi_usb_query(h);
745 if (retval != ERROR_OK)
746 goto error_open;
747
748 *fd = h;
749
750 /* set the max target read/write buffer in bytes
751 * as we are using gdb binary packets to transfer memory we have to
752 * reserve half the buffer for any possible escape chars plus
753 * at least 64 bytes for the gdb packet header */
754 h->max_rw_packet = (((h->max_packet - 64) / 4) * 4) / 2;
755
756 return ERROR_OK;
757
758 error_open:
759 icdi_usb_close(h);
760
761 return ERROR_FAIL;
762 }
763
764 struct hl_layout_api_s icdi_usb_layout_api = {
765 .open = icdi_usb_open,
766 .close = icdi_usb_close,
767 .idcode = icdi_usb_idcode,
768 .state = icdi_usb_state,
769 .reset = icdi_usb_reset,
770 .assert_srst = icdi_usb_assert_srst,
771 .run = icdi_usb_run,
772 .halt = icdi_usb_halt,
773 .step = icdi_usb_step,
774 .read_regs = icdi_usb_read_regs,
775 .read_reg = icdi_usb_read_reg,
776 .write_reg = icdi_usb_write_reg,
777 .read_mem = icdi_usb_read_mem,
778 .write_mem = icdi_usb_write_mem,
779 .write_debug_reg = icdi_usb_write_debug_reg,
780 .override_target = icdi_usb_override_target,
781 .custom_command = icdi_send_remote_cmd,
782 };

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)