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

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)