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

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)