coding style: avoid unnecessary line continuations
[openocd.git] / src / flash / nor / tcl.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
4 * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
5 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
6 * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> *
7 * *
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. *
12 * *
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. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "imp.h"
25 #include <helper/time_support.h>
26 #include <target/image.h>
27
28 /**
29 * @file
30 * Implements Tcl commands used to access NOR flash facilities.
31 */
32
33 COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
34 struct flash_bank **bank, bool do_probe)
35 {
36 const char *name = CMD_ARGV[name_index];
37 int retval;
38 if (do_probe) {
39 retval = get_flash_bank_by_name(name, bank);
40 } else {
41 *bank = get_flash_bank_by_name_noprobe(name);
42 retval = ERROR_OK;
43 }
44
45 if (retval != ERROR_OK)
46 return retval;
47 if (*bank)
48 return ERROR_OK;
49
50 unsigned bank_num;
51 COMMAND_PARSE_NUMBER(uint, name, bank_num);
52
53 if (do_probe) {
54 return get_flash_bank_by_num(bank_num, bank);
55 } else {
56 *bank = get_flash_bank_by_num_noprobe(bank_num);
57 retval = (bank) ? ERROR_OK : ERROR_FAIL;
58 return retval;
59 }
60 }
61
62 COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
63 struct flash_bank **bank)
64 {
65 return CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe,
66 name_index, bank, true);
67 }
68
69 COMMAND_HANDLER(handle_flash_info_command)
70 {
71 struct flash_bank *p;
72 int j = 0;
73 int retval;
74 bool show_sectors = false;
75 bool prot_block_available;
76
77 if (CMD_ARGC < 1 || CMD_ARGC > 2)
78 return ERROR_COMMAND_SYNTAX_ERROR;
79
80 if (CMD_ARGC == 2) {
81 if (strcmp("sectors", CMD_ARGV[1]) == 0)
82 show_sectors = true;
83 else
84 return ERROR_COMMAND_SYNTAX_ERROR;
85 }
86
87 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
88 if (retval != ERROR_OK)
89 return retval;
90
91 if (p != NULL) {
92 char buf[1024];
93 int num_blocks;
94 struct flash_sector *block_array;
95
96 /* attempt auto probe */
97 retval = p->driver->auto_probe(p);
98 if (retval != ERROR_OK)
99 return retval;
100
101 /* If the driver does not implement protection, we show the default
102 * state of is_protected array - usually protection state unknown */
103 if (p->driver->protect_check == NULL) {
104 retval = ERROR_FLASH_OPER_UNSUPPORTED;
105 } else {
106 /* We must query the hardware to avoid printing stale information! */
107 retval = p->driver->protect_check(p);
108 if (retval != ERROR_OK && retval != ERROR_FLASH_OPER_UNSUPPORTED)
109 return retval;
110 }
111 if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
112 LOG_INFO("Flash protection check is not implemented.");
113
114 command_print(CMD,
115 "#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32
116 ", buswidth %i, chipwidth %i",
117 p->bank_number,
118 p->driver->name,
119 p->base,
120 p->size,
121 p->bus_width,
122 p->chip_width);
123
124 prot_block_available = p->num_prot_blocks && p->prot_blocks;
125 if (!show_sectors && prot_block_available) {
126 block_array = p->prot_blocks;
127 num_blocks = p->num_prot_blocks;
128 } else {
129 block_array = p->sectors;
130 num_blocks = p->num_sectors;
131 }
132
133 for (j = 0; j < num_blocks; j++) {
134 char *protect_state = "";
135
136 if (block_array[j].is_protected == 0)
137 protect_state = "not protected";
138 else if (block_array[j].is_protected == 1)
139 protect_state = "protected";
140 else if (!show_sectors || !prot_block_available)
141 protect_state = "protection state unknown";
142
143 command_print(CMD,
144 "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
145 j,
146 block_array[j].offset,
147 block_array[j].size,
148 block_array[j].size >> 10,
149 protect_state);
150 }
151
152 if (p->driver->info != NULL) {
153 retval = p->driver->info(p, buf, sizeof(buf));
154 if (retval == ERROR_OK)
155 command_print(CMD, "%s", buf);
156 else
157 LOG_ERROR("error retrieving flash info");
158 }
159 }
160
161 return retval;
162 }
163
164 COMMAND_HANDLER(handle_flash_probe_command)
165 {
166 struct flash_bank *p;
167 int retval;
168
169 if (CMD_ARGC != 1)
170 return ERROR_COMMAND_SYNTAX_ERROR;
171
172 retval = CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, 0, &p, false);
173 if (retval != ERROR_OK)
174 return retval;
175
176 if (p) {
177 retval = p->driver->probe(p);
178 if (retval == ERROR_OK)
179 command_print(CMD,
180 "flash '%s' found at " TARGET_ADDR_FMT,
181 p->driver->name,
182 p->base);
183 } else {
184 command_print(CMD, "flash bank '#%s' is out of bounds", CMD_ARGV[0]);
185 retval = ERROR_FAIL;
186 }
187
188 return retval;
189 }
190
191 COMMAND_HANDLER(handle_flash_erase_check_command)
192 {
193 bool blank = true;
194 if (CMD_ARGC != 1)
195 return ERROR_COMMAND_SYNTAX_ERROR;
196
197 struct flash_bank *p;
198 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
199 if (ERROR_OK != retval)
200 return retval;
201
202 int j;
203 retval = p->driver->erase_check(p);
204 if (retval == ERROR_OK)
205 command_print(CMD, "successfully checked erase state");
206 else {
207 command_print(CMD,
208 "unknown error when checking erase state of flash bank #%s at "
209 TARGET_ADDR_FMT,
210 CMD_ARGV[0],
211 p->base);
212 }
213
214 for (j = 0; j < p->num_sectors; j++) {
215 char *erase_state;
216
217 if (p->sectors[j].is_erased == 0)
218 erase_state = "not erased";
219 else if (p->sectors[j].is_erased == 1)
220 continue;
221 else
222 erase_state = "erase state unknown";
223
224 blank = false;
225 command_print(CMD,
226 "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
227 j,
228 p->sectors[j].offset,
229 p->sectors[j].size,
230 p->sectors[j].size >> 10,
231 erase_state);
232 }
233
234 if (blank)
235 command_print(CMD, "\tBank is erased");
236 return retval;
237 }
238
239 COMMAND_HANDLER(handle_flash_erase_address_command)
240 {
241 struct flash_bank *p;
242 int retval = ERROR_OK;
243 target_addr_t address;
244 uint32_t length;
245 bool do_pad = false;
246 bool do_unlock = false;
247 struct target *target = get_current_target(CMD_CTX);
248
249 while (CMD_ARGC >= 3) {
250 /* Optionally pad out the address range to block/sector
251 * boundaries. We can't know if there's data in that part
252 * of the flash; only do padding if we're told to.
253 */
254 if (strcmp("pad", CMD_ARGV[0]) == 0)
255 do_pad = true;
256 else if (strcmp("unlock", CMD_ARGV[0]) == 0)
257 do_unlock = true;
258 else
259 return ERROR_COMMAND_SYNTAX_ERROR;
260 CMD_ARGC--;
261 CMD_ARGV++;
262 }
263 if (CMD_ARGC != 2)
264 return ERROR_COMMAND_SYNTAX_ERROR;
265
266 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
267 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
268
269 if (length <= 0) {
270 command_print(CMD, "Length must be >0");
271 return ERROR_COMMAND_SYNTAX_ERROR;
272 }
273
274 retval = get_flash_bank_by_addr(target, address, true, &p);
275 if (retval != ERROR_OK)
276 return retval;
277
278 /* We can't know if we did a resume + halt, in which case we no longer know the erased state
279 **/
280 flash_set_dirty();
281
282 struct duration bench;
283 duration_start(&bench);
284
285 if (do_unlock)
286 retval = flash_unlock_address_range(target, address, length);
287
288 if (retval == ERROR_OK)
289 retval = flash_erase_address_range(target, do_pad, address, length);
290
291 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
292 command_print(CMD, "erased address " TARGET_ADDR_FMT " (length %"
293 PRIi32 ")"
294 " in %fs (%0.3f KiB/s)", address, length,
295 duration_elapsed(&bench), duration_kbps(&bench, length));
296 }
297
298 return retval;
299 }
300
301 COMMAND_HANDLER(handle_flash_erase_command)
302 {
303 if (CMD_ARGC != 3)
304 return ERROR_COMMAND_SYNTAX_ERROR;
305
306 uint32_t first;
307 uint32_t last;
308
309 struct flash_bank *p;
310 int retval;
311
312 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
313 if (retval != ERROR_OK)
314 return retval;
315
316 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
317 if (strcmp(CMD_ARGV[2], "last") == 0)
318 last = p->num_sectors - 1;
319 else
320 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
321
322 if (!(first <= last)) {
323 command_print(CMD, "ERROR: "
324 "first sector must be <= last");
325 return ERROR_FAIL;
326 }
327
328 if (!(last <= (uint32_t)(p->num_sectors - 1))) {
329 command_print(CMD, "ERROR: "
330 "last sector must be <= %" PRIu32,
331 p->num_sectors - 1);
332 return ERROR_FAIL;
333 }
334
335 struct duration bench;
336 duration_start(&bench);
337
338 retval = flash_driver_erase(p, first, last);
339
340 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
341 command_print(CMD, "erased sectors %" PRIu32 " "
342 "through %" PRIu32 " on flash bank %d "
343 "in %fs", first, last, p->bank_number, duration_elapsed(&bench));
344 }
345
346 return retval;
347 }
348
349 COMMAND_HANDLER(handle_flash_protect_command)
350 {
351 if (CMD_ARGC != 4)
352 return ERROR_COMMAND_SYNTAX_ERROR;
353
354 uint32_t first;
355 uint32_t last;
356
357 struct flash_bank *p;
358 int retval;
359 int num_blocks;
360
361 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
362 if (retval != ERROR_OK)
363 return retval;
364
365 if (p->num_prot_blocks)
366 num_blocks = p->num_prot_blocks;
367 else
368 num_blocks = p->num_sectors;
369
370 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
371 if (strcmp(CMD_ARGV[2], "last") == 0)
372 last = num_blocks - 1;
373 else
374 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
375
376 bool set;
377 COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
378
379 if (!(first <= last)) {
380 command_print(CMD, "ERROR: "
381 "first %s must be <= last",
382 (p->num_prot_blocks) ? "block" : "sector");
383 return ERROR_FAIL;
384 }
385
386 if (!(last <= (uint32_t)(num_blocks - 1))) {
387 command_print(CMD, "ERROR: "
388 "last %s must be <= %" PRIu32,
389 (p->num_prot_blocks) ? "block" : "sector",
390 num_blocks - 1);
391 return ERROR_FAIL;
392 }
393
394 retval = flash_driver_protect(p, set, first, last);
395 if (retval == ERROR_OK) {
396 command_print(CMD, "%s protection for %s %" PRIu32
397 " through %" PRIu32 " on flash bank %d",
398 (set) ? "set" : "cleared",
399 (p->num_prot_blocks) ? "blocks" : "sectors",
400 first, last, p->bank_number);
401 }
402
403 return retval;
404 }
405
406 COMMAND_HANDLER(handle_flash_write_image_command)
407 {
408 struct target *target = get_current_target(CMD_CTX);
409
410 struct image image;
411 uint32_t written;
412
413 int retval;
414
415 /* flash auto-erase is disabled by default*/
416 int auto_erase = 0;
417 bool auto_unlock = false;
418
419 while (CMD_ARGC) {
420 if (strcmp(CMD_ARGV[0], "erase") == 0) {
421 auto_erase = 1;
422 CMD_ARGV++;
423 CMD_ARGC--;
424 command_print(CMD, "auto erase enabled");
425 } else if (strcmp(CMD_ARGV[0], "unlock") == 0) {
426 auto_unlock = true;
427 CMD_ARGV++;
428 CMD_ARGC--;
429 command_print(CMD, "auto unlock enabled");
430 } else
431 break;
432 }
433
434 if (CMD_ARGC < 1)
435 return ERROR_COMMAND_SYNTAX_ERROR;
436
437 if (!target) {
438 LOG_ERROR("no target selected");
439 return ERROR_FAIL;
440 }
441
442 struct duration bench;
443 duration_start(&bench);
444
445 if (CMD_ARGC >= 2) {
446 image.base_address_set = 1;
447 COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
448 } else {
449 image.base_address_set = 0;
450 image.base_address = 0x0;
451 }
452
453 image.start_address_set = 0;
454
455 retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
456 if (retval != ERROR_OK)
457 return retval;
458
459 retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock);
460 if (retval != ERROR_OK) {
461 image_close(&image);
462 return retval;
463 }
464
465 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
466 command_print(CMD, "wrote %" PRIu32 " bytes from file %s "
467 "in %fs (%0.3f KiB/s)", written, CMD_ARGV[0],
468 duration_elapsed(&bench), duration_kbps(&bench, written));
469 }
470
471 image_close(&image);
472
473 return retval;
474 }
475
476 COMMAND_HANDLER(handle_flash_fill_command)
477 {
478 target_addr_t address;
479 uint64_t pattern;
480 uint32_t count;
481 struct target *target = get_current_target(CMD_CTX);
482 unsigned i;
483 uint32_t wordsize;
484 int retval;
485
486 if (CMD_ARGC != 3)
487 return ERROR_COMMAND_SYNTAX_ERROR;
488
489 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
490 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern);
491 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
492
493 struct flash_bank *bank;
494 retval = get_flash_bank_by_addr(target, address, true, &bank);
495 if (retval != ERROR_OK)
496 return retval;
497
498 switch (CMD_NAME[4]) {
499 case 'd':
500 wordsize = 8;
501 break;
502 case 'w':
503 wordsize = 4;
504 break;
505 case 'h':
506 wordsize = 2;
507 break;
508 case 'b':
509 wordsize = 1;
510 break;
511 default:
512 return ERROR_COMMAND_SYNTAX_ERROR;
513 }
514
515 if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) {
516 command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize);
517 return ERROR_FAIL;
518 }
519
520 if (count == 0)
521 return ERROR_OK;
522
523 if (address + count * wordsize > bank->base + bank->size) {
524 LOG_ERROR("Cannot cross flash bank borders");
525 return ERROR_FAIL;
526 }
527
528 uint32_t size_bytes = count * wordsize;
529 target_addr_t aligned_start = flash_write_align_start(bank, address);
530 target_addr_t end_addr = address + size_bytes - 1;
531 target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
532 uint32_t aligned_size = aligned_end + 1 - aligned_start;
533 uint32_t padding_at_start = address - aligned_start;
534 uint32_t padding_at_end = aligned_end - end_addr;
535
536 uint8_t *buffer = malloc(aligned_size);
537 if (buffer == NULL)
538 return ERROR_FAIL;
539
540 if (padding_at_start) {
541 memset(buffer, bank->default_padded_value, padding_at_start);
542 LOG_WARNING("Start address " TARGET_ADDR_FMT
543 " breaks the required alignment of flash bank %s",
544 address, bank->name);
545 LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT,
546 padding_at_start, aligned_start);
547 }
548
549 uint8_t *ptr = buffer + padding_at_start;
550
551 switch (wordsize) {
552 case 8:
553 for (i = 0; i < count; i++, ptr += wordsize)
554 target_buffer_set_u64(target, ptr, pattern);
555 break;
556 case 4:
557 for (i = 0; i < count; i++, ptr += wordsize)
558 target_buffer_set_u32(target, ptr, pattern);
559 break;
560 case 2:
561 for (i = 0; i < count; i++, ptr += wordsize)
562 target_buffer_set_u16(target, ptr, pattern);
563 break;
564 case 1:
565 memset(ptr, pattern, count);
566 ptr += count;
567 break;
568 default:
569 LOG_ERROR("BUG: can't happen");
570 exit(-1);
571 }
572
573 if (padding_at_end) {
574 memset(ptr, bank->default_padded_value, padding_at_end);
575 LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32
576 " bytes (bank write end alignment)",
577 end_addr + 1, padding_at_end);
578 }
579
580 struct duration bench;
581 duration_start(&bench);
582
583 retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
584 if (retval != ERROR_OK)
585 goto done;
586
587 retval = flash_driver_read(bank, buffer, address - bank->base, size_bytes);
588 if (retval != ERROR_OK)
589 goto done;
590
591 for (i = 0, ptr = buffer; i < count; i++) {
592 uint64_t readback = 0;
593
594 switch (wordsize) {
595 case 8:
596 readback = target_buffer_get_u64(target, ptr);
597 break;
598 case 4:
599 readback = target_buffer_get_u32(target, ptr);
600 break;
601 case 2:
602 readback = target_buffer_get_u16(target, ptr);
603 break;
604 case 1:
605 readback = *ptr;
606 break;
607 }
608 if (readback != pattern) {
609 LOG_ERROR(
610 "Verification error address " TARGET_ADDR_FMT
611 ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64,
612 address + i * wordsize, readback, pattern);
613 retval = ERROR_FAIL;
614 goto done;
615 }
616 ptr += wordsize;
617 }
618
619 if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
620 command_print(CMD, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT
621 " in %fs (%0.3f KiB/s)", size_bytes, address,
622 duration_elapsed(&bench), duration_kbps(&bench, size_bytes));
623 }
624
625 done:
626 free(buffer);
627
628 return retval;
629 }
630
631 COMMAND_HANDLER(handle_flash_md_command)
632 {
633 int retval;
634
635 if (CMD_ARGC < 1 || CMD_ARGC > 2)
636 return ERROR_COMMAND_SYNTAX_ERROR;
637
638 target_addr_t address;
639 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
640
641 uint32_t count = 1;
642 if (CMD_ARGC == 2)
643 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
644
645 unsigned int wordsize;
646 switch (CMD_NAME[2]) {
647 case 'w':
648 wordsize = 4;
649 break;
650 case 'h':
651 wordsize = 2;
652 break;
653 case 'b':
654 wordsize = 1;
655 break;
656 default:
657 return ERROR_COMMAND_SYNTAX_ERROR;
658 }
659
660 if (count == 0)
661 return ERROR_OK;
662
663 struct target *target = get_current_target(CMD_CTX);
664 struct flash_bank *bank;
665 retval = get_flash_bank_by_addr(target, address, true, &bank);
666 if (retval != ERROR_OK)
667 return retval;
668
669 uint32_t offset = address - bank->base;
670 uint32_t sizebytes = count * wordsize;
671 if (offset + sizebytes > bank->size) {
672 command_print(CMD, "Cannot cross flash bank borders");
673 return ERROR_FAIL;
674 }
675
676 uint8_t *buffer = calloc(count, wordsize);
677 if (buffer == NULL) {
678 command_print(CMD, "No memory for flash read buffer");
679 return ERROR_FAIL;
680 }
681
682 retval = flash_driver_read(bank, buffer, offset, sizebytes);
683 if (retval == ERROR_OK)
684 target_handle_md_output(CMD, target, address, wordsize, count, buffer);
685
686 free(buffer);
687
688 return retval;
689 }
690
691
692 COMMAND_HANDLER(handle_flash_write_bank_command)
693 {
694 uint32_t offset;
695 uint8_t *buffer;
696 size_t length;
697 struct fileio *fileio;
698
699 if (CMD_ARGC < 2 || CMD_ARGC > 3)
700 return ERROR_COMMAND_SYNTAX_ERROR;
701
702 struct duration bench;
703 duration_start(&bench);
704
705 struct flash_bank *bank;
706 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
707 if (ERROR_OK != retval)
708 return retval;
709
710 offset = 0;
711
712 if (CMD_ARGC > 2)
713 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
714
715 if (offset > bank->size) {
716 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
717 offset);
718 return ERROR_COMMAND_ARGUMENT_INVALID;
719 }
720
721 if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
722 return ERROR_FAIL;
723
724 size_t filesize;
725 retval = fileio_size(fileio, &filesize);
726 if (retval != ERROR_OK) {
727 fileio_close(fileio);
728 return retval;
729 }
730
731 length = MIN(filesize, bank->size - offset);
732
733 if (!length) {
734 LOG_INFO("Nothing to write to flash bank");
735 fileio_close(fileio);
736 return ERROR_OK;
737 }
738
739 if (length != filesize)
740 LOG_INFO("File content exceeds flash bank size. Only writing the "
741 "first %zu bytes of the file", length);
742
743 target_addr_t start_addr = bank->base + offset;
744 target_addr_t aligned_start = flash_write_align_start(bank, start_addr);
745 target_addr_t end_addr = start_addr + length - 1;
746 target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
747 uint32_t aligned_size = aligned_end + 1 - aligned_start;
748 uint32_t padding_at_start = start_addr - aligned_start;
749 uint32_t padding_at_end = aligned_end - end_addr;
750
751 buffer = malloc(aligned_size);
752 if (buffer == NULL) {
753 fileio_close(fileio);
754 LOG_ERROR("Out of memory");
755 return ERROR_FAIL;
756 }
757
758 if (padding_at_start) {
759 memset(buffer, bank->default_padded_value, padding_at_start);
760 LOG_WARNING("Start offset 0x%08" PRIx32
761 " breaks the required alignment of flash bank %s",
762 offset, bank->name);
763 LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT,
764 padding_at_start, aligned_start);
765 }
766
767 uint8_t *ptr = buffer + padding_at_start;
768 size_t buf_cnt;
769 if (fileio_read(fileio, length, ptr, &buf_cnt) != ERROR_OK) {
770 free(buffer);
771 fileio_close(fileio);
772 return ERROR_FAIL;
773 }
774
775 if (buf_cnt != length) {
776 LOG_ERROR("Short read");
777 free(buffer);
778 return ERROR_FAIL;
779 }
780
781 ptr += length;
782
783 if (padding_at_end) {
784 memset(ptr, bank->default_padded_value, padding_at_end);
785 LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32
786 " bytes (bank write end alignment)",
787 end_addr + 1, padding_at_end);
788 }
789
790 retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
791
792 free(buffer);
793
794 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
795 command_print(CMD, "wrote %zu bytes from file %s to flash bank %u"
796 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
797 length, CMD_ARGV[1], bank->bank_number, offset,
798 duration_elapsed(&bench), duration_kbps(&bench, length));
799 }
800
801 fileio_close(fileio);
802
803 return retval;
804 }
805
806 COMMAND_HANDLER(handle_flash_read_bank_command)
807 {
808 uint32_t offset;
809 uint8_t *buffer;
810 struct fileio *fileio;
811 uint32_t length;
812 size_t written;
813
814 if (CMD_ARGC < 2 || CMD_ARGC > 4)
815 return ERROR_COMMAND_SYNTAX_ERROR;
816
817 struct duration bench;
818 duration_start(&bench);
819
820 struct flash_bank *p;
821 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
822
823 if (ERROR_OK != retval)
824 return retval;
825
826 offset = 0;
827
828 if (CMD_ARGC > 2)
829 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
830
831 if (offset > p->size) {
832 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
833 offset);
834 return ERROR_COMMAND_ARGUMENT_INVALID;
835 }
836
837 length = p->size - offset;
838
839 if (CMD_ARGC > 3)
840 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
841
842 if (offset + length > p->size) {
843 LOG_ERROR("Length of %" PRIu32 " bytes with offset 0x%8.8" PRIx32
844 " is out of range of the flash bank", length, offset);
845 return ERROR_COMMAND_ARGUMENT_INVALID;
846 }
847
848 buffer = malloc(length);
849 if (buffer == NULL) {
850 LOG_ERROR("Out of memory");
851 return ERROR_FAIL;
852 }
853
854 retval = flash_driver_read(p, buffer, offset, length);
855 if (retval != ERROR_OK) {
856 LOG_ERROR("Read error");
857 free(buffer);
858 return retval;
859 }
860
861 retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY);
862 if (retval != ERROR_OK) {
863 LOG_ERROR("Could not open file");
864 free(buffer);
865 return retval;
866 }
867
868 retval = fileio_write(fileio, length, buffer, &written);
869 fileio_close(fileio);
870 free(buffer);
871 if (retval != ERROR_OK) {
872 LOG_ERROR("Could not write file");
873 return ERROR_FAIL;
874 }
875
876 if (duration_measure(&bench) == ERROR_OK)
877 command_print(CMD, "wrote %zd bytes to file %s from flash bank %u"
878 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
879 written, CMD_ARGV[1], p->bank_number, offset,
880 duration_elapsed(&bench), duration_kbps(&bench, written));
881
882 return retval;
883 }
884
885
886 COMMAND_HANDLER(handle_flash_verify_bank_command)
887 {
888 uint32_t offset;
889 uint8_t *buffer_file, *buffer_flash;
890 struct fileio *fileio;
891 size_t read_cnt;
892 size_t filesize;
893 size_t length;
894 int differ;
895
896 if (CMD_ARGC < 2 || CMD_ARGC > 3)
897 return ERROR_COMMAND_SYNTAX_ERROR;
898
899 struct duration bench;
900 duration_start(&bench);
901
902 struct flash_bank *p;
903 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
904 if (ERROR_OK != retval)
905 return retval;
906
907 offset = 0;
908
909 if (CMD_ARGC > 2)
910 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
911
912 if (offset > p->size) {
913 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
914 offset);
915 return ERROR_COMMAND_ARGUMENT_INVALID;
916 }
917
918 retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
919 if (retval != ERROR_OK) {
920 LOG_ERROR("Could not open file");
921 return retval;
922 }
923
924 retval = fileio_size(fileio, &filesize);
925 if (retval != ERROR_OK) {
926 fileio_close(fileio);
927 return retval;
928 }
929
930 length = MIN(filesize, p->size - offset);
931
932 if (!length) {
933 LOG_INFO("Nothing to compare with flash bank");
934 fileio_close(fileio);
935 return ERROR_OK;
936 }
937
938 if (length != filesize)
939 LOG_INFO("File content exceeds flash bank size. Only comparing the "
940 "first %zu bytes of the file", length);
941
942 buffer_file = malloc(length);
943 if (buffer_file == NULL) {
944 LOG_ERROR("Out of memory");
945 fileio_close(fileio);
946 return ERROR_FAIL;
947 }
948
949 retval = fileio_read(fileio, length, buffer_file, &read_cnt);
950 fileio_close(fileio);
951 if (retval != ERROR_OK) {
952 LOG_ERROR("File read failure");
953 free(buffer_file);
954 return retval;
955 }
956
957 if (read_cnt != length) {
958 LOG_ERROR("Short read");
959 free(buffer_file);
960 return ERROR_FAIL;
961 }
962
963 buffer_flash = malloc(length);
964 if (buffer_flash == NULL) {
965 LOG_ERROR("Out of memory");
966 free(buffer_file);
967 return ERROR_FAIL;
968 }
969
970 retval = flash_driver_read(p, buffer_flash, offset, length);
971 if (retval != ERROR_OK) {
972 LOG_ERROR("Flash read error");
973 free(buffer_flash);
974 free(buffer_file);
975 return retval;
976 }
977
978 if (duration_measure(&bench) == ERROR_OK)
979 command_print(CMD, "read %zd bytes from file %s and flash bank %u"
980 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
981 length, CMD_ARGV[1], p->bank_number, offset,
982 duration_elapsed(&bench), duration_kbps(&bench, length));
983
984 differ = memcmp(buffer_file, buffer_flash, length);
985 command_print(CMD, "contents %s", differ ? "differ" : "match");
986 if (differ) {
987 uint32_t t;
988 int diffs = 0;
989 for (t = 0; t < length; t++) {
990 if (buffer_flash[t] == buffer_file[t])
991 continue;
992 command_print(CMD, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x",
993 diffs, t + offset, buffer_flash[t], buffer_file[t]);
994 if (diffs++ >= 127) {
995 command_print(CMD, "More than 128 errors, the rest are not printed.");
996 break;
997 }
998 keep_alive();
999 }
1000 }
1001 free(buffer_flash);
1002 free(buffer_file);
1003
1004 return differ ? ERROR_FAIL : ERROR_OK;
1005 }
1006
1007 void flash_set_dirty(void)
1008 {
1009 struct flash_bank *c;
1010 int i;
1011
1012 /* set all flash to require erasing */
1013 for (c = flash_bank_list(); c; c = c->next) {
1014 for (i = 0; i < c->num_sectors; i++)
1015 c->sectors[i].is_erased = 0;
1016 }
1017 }
1018
1019 COMMAND_HANDLER(handle_flash_padded_value_command)
1020 {
1021 if (CMD_ARGC != 2)
1022 return ERROR_COMMAND_SYNTAX_ERROR;
1023
1024 struct flash_bank *p;
1025 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
1026 if (ERROR_OK != retval)
1027 return retval;
1028
1029 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value);
1030
1031 command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u",
1032 p->default_padded_value, p->bank_number);
1033
1034 return retval;
1035 }
1036
1037 static const struct command_registration flash_exec_command_handlers[] = {
1038 {
1039 .name = "probe",
1040 .handler = handle_flash_probe_command,
1041 .mode = COMMAND_EXEC,
1042 .usage = "bank_id",
1043 .help = "Identify a flash bank.",
1044 },
1045 {
1046 .name = "info",
1047 .handler = handle_flash_info_command,
1048 .mode = COMMAND_EXEC,
1049 .usage = "bank_id ['sectors']",
1050 .help = "Print information about a flash bank.",
1051 },
1052 {
1053 .name = "erase_check",
1054 .handler = handle_flash_erase_check_command,
1055 .mode = COMMAND_EXEC,
1056 .usage = "bank_id",
1057 .help = "Check erase state of all blocks in a "
1058 "flash bank.",
1059 },
1060 {
1061 .name = "erase_sector",
1062 .handler = handle_flash_erase_command,
1063 .mode = COMMAND_EXEC,
1064 .usage = "bank_id first_sector_num (last_sector_num|'last')",
1065 .help = "Erase a range of sectors in a flash bank.",
1066 },
1067 {
1068 .name = "erase_address",
1069 .handler = handle_flash_erase_address_command,
1070 .mode = COMMAND_EXEC,
1071 .usage = "['pad'] ['unlock'] address length",
1072 .help = "Erase flash sectors starting at address and "
1073 "continuing for length bytes. If 'pad' is specified, "
1074 "data outside that range may also be erased: the start "
1075 "address may be decreased, and length increased, so "
1076 "that all of the first and last sectors are erased. "
1077 "If 'unlock' is specified, then the flash is unprotected "
1078 "before erasing.",
1079
1080 },
1081 {
1082 .name = "filld",
1083 .handler = handle_flash_fill_command,
1084 .mode = COMMAND_EXEC,
1085 .usage = "address value n",
1086 .help = "Fill n double-words with 64-bit value, starting at "
1087 "word address. (No autoerase.)",
1088 },
1089 {
1090 .name = "fillw",
1091 .handler = handle_flash_fill_command,
1092 .mode = COMMAND_EXEC,
1093 .usage = "address value n",
1094 .help = "Fill n words with 32-bit value, starting at "
1095 "word address. (No autoerase.)",
1096 },
1097 {
1098 .name = "fillh",
1099 .handler = handle_flash_fill_command,
1100 .mode = COMMAND_EXEC,
1101 .usage = "address value n",
1102 .help = "Fill n halfwords with 16-bit value, starting at "
1103 "word address. (No autoerase.)",
1104 },
1105 {
1106 .name = "fillb",
1107 .handler = handle_flash_fill_command,
1108 .mode = COMMAND_EXEC,
1109 .usage = "address value n",
1110 .help = "Fill n bytes with 8-bit value, starting at "
1111 "word address. (No autoerase.)",
1112 },
1113 {
1114 .name = "mdb",
1115 .handler = handle_flash_md_command,
1116 .mode = COMMAND_EXEC,
1117 .usage = "address [count]",
1118 .help = "Display bytes from flash.",
1119 },
1120 {
1121 .name = "mdh",
1122 .handler = handle_flash_md_command,
1123 .mode = COMMAND_EXEC,
1124 .usage = "address [count]",
1125 .help = "Display half-words from flash.",
1126 },
1127 {
1128 .name = "mdw",
1129 .handler = handle_flash_md_command,
1130 .mode = COMMAND_EXEC,
1131 .usage = "address [count]",
1132 .help = "Display words from flash.",
1133 },
1134 {
1135 .name = "write_bank",
1136 .handler = handle_flash_write_bank_command,
1137 .mode = COMMAND_EXEC,
1138 .usage = "bank_id filename [offset]",
1139 .help = "Write binary data from file to flash bank. Allow optional "
1140 "offset from beginning of the bank (defaults to zero).",
1141 },
1142 {
1143 .name = "write_image",
1144 .handler = handle_flash_write_image_command,
1145 .mode = COMMAND_EXEC,
1146 .usage = "[erase] [unlock] filename [offset [file_type]]",
1147 .help = "Write an image to flash. Optionally first unprotect "
1148 "and/or erase the region to be used. Allow optional "
1149 "offset from beginning of bank (defaults to zero)",
1150 },
1151 {
1152 .name = "read_bank",
1153 .handler = handle_flash_read_bank_command,
1154 .mode = COMMAND_EXEC,
1155 .usage = "bank_id filename [offset [length]]",
1156 .help = "Read binary data from flash bank to file. Allow optional "
1157 "offset from beginning of the bank (defaults to zero).",
1158 },
1159 {
1160 .name = "verify_bank",
1161 .handler = handle_flash_verify_bank_command,
1162 .mode = COMMAND_EXEC,
1163 .usage = "bank_id filename [offset]",
1164 .help = "Compare the contents of a file with the contents of the "
1165 "flash bank. Allow optional offset from beginning of the bank "
1166 "(defaults to zero).",
1167 },
1168 {
1169 .name = "protect",
1170 .handler = handle_flash_protect_command,
1171 .mode = COMMAND_EXEC,
1172 .usage = "bank_id first_block [last_block|'last'] "
1173 "('on'|'off')",
1174 .help = "Turn protection on or off for a range of protection "
1175 "blocks or sectors in a given flash bank. "
1176 "See 'flash info' output for a list of blocks.",
1177 },
1178 {
1179 .name = "padded_value",
1180 .handler = handle_flash_padded_value_command,
1181 .mode = COMMAND_EXEC,
1182 .usage = "bank_id value",
1183 .help = "Set default flash padded value",
1184 },
1185 COMMAND_REGISTRATION_DONE
1186 };
1187
1188 static int flash_init_drivers(struct command_context *cmd_ctx)
1189 {
1190 if (!flash_bank_list())
1191 return ERROR_OK;
1192
1193 struct command *parent = command_find_in_context(cmd_ctx, "flash");
1194 return register_commands(cmd_ctx, parent, flash_exec_command_handlers);
1195 }
1196
1197 COMMAND_HANDLER(handle_flash_bank_command)
1198 {
1199 if (CMD_ARGC < 7) {
1200 LOG_ERROR("usage: flash bank <name> <driver> "
1201 "<base> <size> <chip_width> <bus_width> <target>");
1202 return ERROR_COMMAND_SYNTAX_ERROR;
1203 }
1204 /* save bank name and advance arguments for compatibility */
1205 const char *bank_name = *CMD_ARGV++;
1206 CMD_ARGC--;
1207
1208 struct target *target = get_target(CMD_ARGV[5]);
1209 if (target == NULL) {
1210 LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
1211 return ERROR_FAIL;
1212 }
1213
1214 const char *driver_name = CMD_ARGV[0];
1215 const struct flash_driver *driver = flash_driver_find_by_name(driver_name);
1216 if (NULL == driver) {
1217 /* no matching flash driver found */
1218 LOG_ERROR("flash driver '%s' not found", driver_name);
1219 return ERROR_FAIL;
1220 }
1221
1222 /* check the flash bank name is unique */
1223 if (get_flash_bank_by_name_noprobe(bank_name) != NULL) {
1224 /* flash bank name already exists */
1225 LOG_ERROR("flash bank name '%s' already exists", bank_name);
1226 return ERROR_FAIL;
1227 }
1228
1229 /* register flash specific commands */
1230 if (NULL != driver->commands) {
1231 int retval = register_commands(CMD_CTX, NULL,
1232 driver->commands);
1233 if (ERROR_OK != retval) {
1234 LOG_ERROR("couldn't register '%s' commands",
1235 driver_name);
1236 return ERROR_FAIL;
1237 }
1238 }
1239
1240 struct flash_bank *c = calloc(1, sizeof(*c));
1241 c->name = strdup(bank_name);
1242 c->target = target;
1243 c->driver = driver;
1244 COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], c->base);
1245 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
1246 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width);
1247 COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width);
1248 c->default_padded_value = c->erased_value = 0xff;
1249 c->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
1250
1251 int retval;
1252 retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c);
1253 if (ERROR_OK != retval) {
1254 LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT
1255 "; usage: %s", driver_name, c->base, driver->usage);
1256 free(c);
1257 return retval;
1258 }
1259
1260 if (driver->usage == NULL)
1261 LOG_DEBUG("'%s' driver usage field missing", driver_name);
1262
1263 flash_bank_add(c);
1264
1265 return ERROR_OK;
1266 }
1267
1268 COMMAND_HANDLER(handle_flash_banks_command)
1269 {
1270 if (CMD_ARGC != 0)
1271 return ERROR_COMMAND_SYNTAX_ERROR;
1272
1273 unsigned n = 0;
1274 for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) {
1275 command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", "
1276 "buswidth %u, chipwidth %u", p->bank_number,
1277 p->name, p->driver->name, p->base, p->size,
1278 p->bus_width, p->chip_width);
1279 }
1280 return ERROR_OK;
1281 }
1282
1283 static int jim_flash_list(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
1284 {
1285 if (argc != 1) {
1286 Jim_WrongNumArgs(interp, 1, argv,
1287 "no arguments to 'flash list' command");
1288 return JIM_ERR;
1289 }
1290
1291 Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
1292
1293 for (struct flash_bank *p = flash_bank_list(); p; p = p->next) {
1294 Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
1295
1296 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
1297 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
1298 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
1299 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
1300 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
1301 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
1302 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
1303 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
1304 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
1305 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
1306
1307 Jim_ListAppendElement(interp, list, elem);
1308 }
1309
1310 Jim_SetResult(interp, list);
1311
1312 return JIM_OK;
1313 }
1314
1315 COMMAND_HANDLER(handle_flash_init_command)
1316 {
1317 if (CMD_ARGC != 0)
1318 return ERROR_COMMAND_SYNTAX_ERROR;
1319
1320 static bool flash_initialized;
1321 if (flash_initialized) {
1322 LOG_INFO("'flash init' has already been called");
1323 return ERROR_OK;
1324 }
1325 flash_initialized = true;
1326
1327 LOG_DEBUG("Initializing flash devices...");
1328 return flash_init_drivers(CMD_CTX);
1329 }
1330
1331 static const struct command_registration flash_config_command_handlers[] = {
1332 {
1333 .name = "bank",
1334 .handler = handle_flash_bank_command,
1335 .mode = COMMAND_CONFIG,
1336 .usage = "bank_id driver_name base_address size_bytes "
1337 "chip_width_bytes bus_width_bytes target "
1338 "[driver_options ...]",
1339 .help = "Define a new bank with the given name, "
1340 "using the specified NOR flash driver.",
1341 },
1342 {
1343 .name = "init",
1344 .mode = COMMAND_CONFIG,
1345 .handler = handle_flash_init_command,
1346 .help = "Initialize flash devices.",
1347 .usage = "",
1348 },
1349 {
1350 .name = "banks",
1351 .mode = COMMAND_ANY,
1352 .handler = handle_flash_banks_command,
1353 .help = "Display table with information about flash banks.",
1354 .usage = "",
1355 },
1356 {
1357 .name = "list",
1358 .mode = COMMAND_ANY,
1359 .jim_handler = jim_flash_list,
1360 .help = "Returns a list of details about the flash banks.",
1361 },
1362 COMMAND_REGISTRATION_DONE
1363 };
1364 static const struct command_registration flash_command_handlers[] = {
1365 {
1366 .name = "flash",
1367 .mode = COMMAND_ANY,
1368 .help = "NOR flash command group",
1369 .chain = flash_config_command_handlers,
1370 .usage = "",
1371 },
1372 COMMAND_REGISTRATION_DONE
1373 };
1374
1375 int flash_register_commands(struct command_context *cmd_ctx)
1376 {
1377 return register_commands(cmd_ctx, NULL, flash_command_handlers);
1378 }

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)