gdb: connect will now fail if flash autoprobe fails
[openocd.git] / src / flash / nor / core.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2007-2010 Ø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 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <flash/common.h>
27 #include <flash/nor/core.h>
28 #include <flash/nor/imp.h>
29 #include <target/image.h>
30
31
32 /**
33 * @file
34 * Upper level of NOR flash framework.
35 * The lower level interfaces are to drivers. These upper level ones
36 * primarily support access from Tcl scripts or from GDB.
37 */
38
39 static struct flash_bank *flash_banks;
40
41 int flash_driver_erase(struct flash_bank *bank, int first, int last)
42 {
43 int retval;
44
45 retval = bank->driver->erase(bank, first, last);
46 if (retval != ERROR_OK)
47 {
48 LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
49 }
50
51 return retval;
52 }
53
54 int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
55 {
56 int retval;
57 bool updated = false;
58
59 /* NOTE: "first == last" means (un?)protect just that sector.
60 code including Lower level ddrivers may rely on this "first <= last"
61 * invariant.
62 */
63
64 /* callers may not supply illegal parameters ... */
65 if (first < 0 || first > last || last >= bank->num_sectors)
66 return ERROR_FAIL;
67
68 /* force "set" to 0/1 */
69 set = !!set;
70
71 /*
72 * Filter out what trivial nonsense we can, so drivers don't have to.
73 *
74 * Don't tell drivers to change to the current state... it's needless,
75 * and reducing the amount of work to be done (potentially to nothing)
76 * speeds at least some things up.
77 */
78 scan:
79 for (int i = first; i <= last; i++) {
80 struct flash_sector *sector = bank->sectors + i;
81
82 /* Only filter requests to protect the already-protected, or
83 * to unprotect the already-unprotected. Changing from the
84 * unknown state (-1) to a known one is unwise but allowed;
85 * protection status is best checked first.
86 */
87 if (sector->is_protected != set)
88 continue;
89
90 /* Shrink this range of sectors from the start; don't overrun
91 * the end. Also shrink from the end; don't overun the start.
92 *
93 * REVISIT we could handle discontiguous regions by issuing
94 * more than one driver request. How much would that matter?
95 */
96 if (i == first && i != last) {
97 updated = true;
98 first++;
99 } else if (i == last && i != first) {
100 updated = true;
101 last--;
102 }
103 }
104
105 /* updating the range affects the tests in the scan loop above; so
106 * re-scan, to make sure we didn't miss anything.
107 */
108 if (updated) {
109 updated = false;
110 goto scan;
111 }
112
113 /* Single sector, already protected? Nothing to do!
114 * We may have trimmed our parameters into this degenerate case.
115 *
116 * FIXME repeating the "is_protected==set" test is a giveaway that
117 * this fast-exit belongs earlier, in the trim-it-down loop; mve.
118 * */
119 if (first == last && bank->sectors[first].is_protected == set)
120 return ERROR_OK;
121
122
123 /* Note that we don't pass illegal parameters to drivers; any
124 * trimming just turns one valid range into another one.
125 */
126 retval = bank->driver->protect(bank, set, first, last);
127 if (retval != ERROR_OK)
128 {
129 LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
130 }
131
132 return retval;
133 }
134
135 int flash_driver_write(struct flash_bank *bank,
136 uint8_t *buffer, uint32_t offset, uint32_t count)
137 {
138 int retval;
139
140 retval = bank->driver->write(bank, buffer, offset, count);
141 if (retval != ERROR_OK)
142 {
143 LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)",
144 bank->base, offset, retval);
145 }
146
147 return retval;
148 }
149
150 void flash_bank_add(struct flash_bank *bank)
151 {
152 /* put flash bank in linked list */
153 unsigned bank_num = 0;
154 if (flash_banks)
155 {
156 /* find last flash bank */
157 struct flash_bank *p = flash_banks;
158 while (NULL != p->next)
159 {
160 bank_num += 1;
161 p = p->next;
162 }
163 p->next = bank;
164 bank_num += 1;
165 }
166 else
167 flash_banks = bank;
168
169 bank->bank_number = bank_num;
170 }
171
172 struct flash_bank *flash_bank_list(void)
173 {
174 return flash_banks;
175 }
176
177 struct flash_bank *get_flash_bank_by_num_noprobe(int num)
178 {
179 struct flash_bank *p;
180 int i = 0;
181
182 for (p = flash_banks; p; p = p->next)
183 {
184 if (i++ == num)
185 {
186 return p;
187 }
188 }
189 LOG_ERROR("flash bank %d does not exist", num);
190 return NULL;
191 }
192
193 int flash_get_bank_count(void)
194 {
195 struct flash_bank *p;
196 int i = 0;
197 for (p = flash_banks; p; p = p->next)
198 {
199 i++;
200 }
201 return i;
202 }
203
204 struct flash_bank *get_flash_bank_by_name(const char *name)
205 {
206 unsigned requested = get_flash_name_index(name);
207 unsigned found = 0;
208
209 struct flash_bank *bank;
210 for (bank = flash_banks; NULL != bank; bank = bank->next)
211 {
212 if (strcmp(bank->name, name) == 0)
213 return bank;
214 if (!flash_driver_name_matches(bank->driver->name, name))
215 continue;
216 if (++found < requested)
217 continue;
218 return bank;
219 }
220 return NULL;
221 }
222
223 int get_flash_bank_by_num(int num, struct flash_bank **bank)
224 {
225 struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
226 int retval;
227
228 if (p == NULL)
229 {
230 return ERROR_FAIL;
231 }
232
233 retval = p->driver->auto_probe(p);
234
235 if (retval != ERROR_OK)
236 {
237 LOG_ERROR("auto_probe failed %d\n", retval);
238 return retval;
239 }
240 *bank = p;
241 return ERROR_OK;
242 }
243
244 /* lookup flash bank by address */
245 struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
246 {
247 struct flash_bank *c;
248
249 /* cycle through bank list */
250 for (c = flash_banks; c; c = c->next)
251 {
252 int retval;
253 retval = c->driver->auto_probe(c);
254
255 if (retval != ERROR_OK)
256 {
257 LOG_ERROR("auto_probe failed %d\n", retval);
258 return NULL;
259 }
260 /* check whether address belongs to this flash bank */
261 if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
262 return c;
263 }
264 LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
265 return NULL;
266 }
267
268 int default_flash_mem_blank_check(struct flash_bank *bank)
269 {
270 struct target *target = bank->target;
271 const int buffer_size = 1024;
272 int i;
273 uint32_t nBytes;
274 int retval = ERROR_OK;
275
276 if (bank->target->state != TARGET_HALTED)
277 {
278 LOG_ERROR("Target not halted");
279 return ERROR_TARGET_NOT_HALTED;
280 }
281
282 uint8_t *buffer = malloc(buffer_size);
283
284 for (i = 0; i < bank->num_sectors; i++)
285 {
286 uint32_t j;
287 bank->sectors[i].is_erased = 1;
288
289 for (j = 0; j < bank->sectors[i].size; j += buffer_size)
290 {
291 uint32_t chunk;
292 chunk = buffer_size;
293 if (chunk > (j - bank->sectors[i].size))
294 {
295 chunk = (j - bank->sectors[i].size);
296 }
297
298 retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
299 if (retval != ERROR_OK)
300 {
301 goto done;
302 }
303
304 for (nBytes = 0; nBytes < chunk; nBytes++)
305 {
306 if (buffer[nBytes] != 0xFF)
307 {
308 bank->sectors[i].is_erased = 0;
309 break;
310 }
311 }
312 }
313 }
314
315 done:
316 free(buffer);
317
318 return retval;
319 }
320
321 int default_flash_blank_check(struct flash_bank *bank)
322 {
323 struct target *target = bank->target;
324 int i;
325 int retval;
326 int fast_check = 0;
327 uint32_t blank;
328
329 if (bank->target->state != TARGET_HALTED)
330 {
331 LOG_ERROR("Target not halted");
332 return ERROR_TARGET_NOT_HALTED;
333 }
334
335 for (i = 0; i < bank->num_sectors; i++)
336 {
337 uint32_t address = bank->base + bank->sectors[i].offset;
338 uint32_t size = bank->sectors[i].size;
339
340 if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
341 {
342 fast_check = 0;
343 break;
344 }
345 if (blank == 0xFF)
346 bank->sectors[i].is_erased = 1;
347 else
348 bank->sectors[i].is_erased = 0;
349 fast_check = 1;
350 }
351
352 if (!fast_check)
353 {
354 LOG_USER("Running slow fallback erase check - add working memory");
355 return default_flash_mem_blank_check(bank);
356 }
357
358 return ERROR_OK;
359 }
360
361 /* Manipulate given flash region, selecting the bank according to target
362 * and address. Maps an address range to a set of sectors, and issues
363 * the callback() on that set ... e.g. to erase or unprotect its members.
364 *
365 * (Note a current bad assumption: that protection operates on the same
366 * size sectors as erase operations use.)
367 *
368 * The "pad_reason" parameter is a kind of boolean: when it's NULL, the
369 * range must fit those sectors exactly. This is clearly safe; it can't
370 * erase data which the caller said to leave alone, for example. If it's
371 * non-NULL, rather than failing, extra data in the first and/or last
372 * sectors will be added to the range, and that reason string is used when
373 * warning about those additions.
374 */
375 static int flash_iterate_address_range(struct target *target,
376 char *pad_reason, uint32_t addr, uint32_t length,
377 int (*callback)(struct flash_bank *bank, int first, int last))
378 {
379 struct flash_bank *c;
380 uint32_t last_addr = addr + length; /* first address AFTER end */
381 int first = -1;
382 int last = -1;
383 int i;
384
385 if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
386 return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */
387
388 if (c->size == 0 || c->num_sectors == 0)
389 {
390 LOG_ERROR("Bank is invalid");
391 return ERROR_FLASH_BANK_INVALID;
392 }
393
394 if (length == 0)
395 {
396 /* special case, erase whole bank when length is zero */
397 if (addr != c->base)
398 {
399 LOG_ERROR("Whole bank access must start at beginning of bank.");
400 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
401 }
402
403 return callback(c, 0, c->num_sectors - 1);
404 }
405
406 /* check whether it all fits in this bank */
407 if (addr + length - 1 > c->base + c->size - 1)
408 {
409 LOG_ERROR("Flash access does not fit into bank.");
410 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
411 }
412
413 /** @todo: handle erasures that cross into adjacent banks */
414
415 addr -= c->base;
416 last_addr -= c->base;
417
418 for (i = 0; i < c->num_sectors; i++)
419 {
420 struct flash_sector *f = c->sectors + i;
421 uint32_t end = f->offset + f->size;
422
423 /* start only on a sector boundary */
424 if (first < 0) {
425 /* scanned past the first sector? */
426 if (addr < f->offset)
427 break;
428
429 /* is this the first sector? */
430 if (addr == f->offset)
431 first = i;
432
433 /* Does this need head-padding? If so, pad and warn;
434 * or else force an error.
435 *
436 * Such padding can make trouble, since *WE* can't
437 * ever know if that data was in use. The warning
438 * should help users sort out messes later.
439 */
440 else if (addr < end && pad_reason) {
441 /* FIXME say how many bytes (e.g. 80 KB) */
442 LOG_WARNING("Adding extra %s range, "
443 "%#8.8x to %#8.8x",
444 pad_reason,
445 (unsigned) f->offset,
446 (unsigned) addr - 1);
447 first = i;
448 } else
449 continue;
450 }
451
452 /* is this (also?) the last sector? */
453 if (last_addr == end) {
454 last = i;
455 break;
456 }
457
458 /* Does this need tail-padding? If so, pad and warn;
459 * or else force an error.
460 */
461 if (last_addr < end && pad_reason) {
462 /* FIXME say how many bytes (e.g. 80 KB) */
463 LOG_WARNING("Adding extra %s range, "
464 "%#8.8x to %#8.8x",
465 pad_reason,
466 (unsigned) last_addr,
467 (unsigned) end - 1);
468 last = i;
469 break;
470 }
471
472 /* MUST finish on a sector boundary */
473 if (last_addr <= f->offset)
474 break;
475 }
476
477 /* invalid start or end address? */
478 if (first == -1 || last == -1) {
479 LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
480 "is not sector-aligned",
481 (unsigned) (c->base + addr),
482 (unsigned) (c->base + last_addr - 1));
483 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
484 }
485
486 /* The NOR driver may trim this range down, based on what
487 * sectors are already erased/unprotected. GDB currently
488 * blocks such optimizations.
489 */
490 return callback(c, first, last);
491 }
492
493 int flash_erase_address_range(struct target *target,
494 bool pad, uint32_t addr, uint32_t length)
495 {
496 return flash_iterate_address_range(target, pad ? "erase" : NULL,
497 addr, length, &flash_driver_erase);
498 }
499
500 static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
501 {
502 return flash_driver_protect(bank, 0, first, last);
503 }
504
505 static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
506 {
507 /* By default, pad to sector boundaries ... the real issue here
508 * is that our (only) caller *permanently* removes protection,
509 * and doesn't restore it.
510 */
511 return flash_iterate_address_range(target, "unprotect",
512 addr, length, &flash_driver_unprotect);
513 }
514
515 static int compare_section (const void * a, const void * b)
516 {
517 struct imageection *b1, *b2;
518 b1=*((struct imageection **)a);
519 b2=*((struct imageection **)b);
520
521 if (b1->base_address == b2->base_address)
522 {
523 return 0;
524 } else if (b1->base_address > b2->base_address)
525 {
526 return 1;
527 } else
528 {
529 return -1;
530 }
531 }
532
533
534 int flash_write_unlock(struct target *target, struct image *image,
535 uint32_t *written, int erase, bool unlock)
536 {
537 int retval = ERROR_OK;
538
539 int section;
540 uint32_t section_offset;
541 struct flash_bank *c;
542 int *padding;
543
544 section = 0;
545 section_offset = 0;
546
547 if (written)
548 *written = 0;
549
550 if (erase)
551 {
552 /* assume all sectors need erasing - stops any problems
553 * when flash_write is called multiple times */
554
555 flash_set_dirty();
556 }
557
558 /* allocate padding array */
559 padding = calloc(image->num_sections, sizeof(*padding));
560
561 /* This fn requires all sections to be in ascending order of addresses,
562 * whereas an image can have sections out of order. */
563 struct imageection **sections = malloc(sizeof(struct imageection *) *
564 image->num_sections);
565 int i;
566 for (i = 0; i < image->num_sections; i++)
567 {
568 sections[i] = &image->sections[i];
569 }
570
571 qsort(sections, image->num_sections, sizeof(struct imageection *),
572 compare_section);
573
574 /* loop until we reach end of the image */
575 while (section < image->num_sections)
576 {
577 uint32_t buffer_size;
578 uint8_t *buffer;
579 int section_first;
580 int section_last;
581 uint32_t run_address = sections[section]->base_address + section_offset;
582 uint32_t run_size = sections[section]->size - section_offset;
583 int pad_bytes = 0;
584
585 if (sections[section]->size == 0)
586 {
587 LOG_WARNING("empty section %d", section);
588 section++;
589 section_offset = 0;
590 continue;
591 }
592
593 /* find the corresponding flash bank */
594 if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
595 {
596 section++; /* and skip it */
597 section_offset = 0;
598 continue;
599 }
600
601 /* collect consecutive sections which fall into the same bank */
602 section_first = section;
603 section_last = section;
604 padding[section] = 0;
605 while ((run_address + run_size - 1 < c->base + c->size - 1)
606 && (section_last + 1 < image->num_sections))
607 {
608 /* sections are sorted */
609 assert(sections[section_last + 1]->base_address >= c->base);
610 if (sections[section_last + 1]->base_address >= (c->base + c->size))
611 {
612 /* Done with this bank */
613 break;
614 }
615
616 /* FIXME This needlessly touches sectors BETWEEN the
617 * sections it's writing. Without auto erase, it just
618 * writes ones. That WILL INVALIDATE data in cases
619 * like Stellaris Tempest chips, corrupting internal
620 * ECC codes; and at least FreeScale suggests issues
621 * with that approach (in HC11 documentation).
622 *
623 * With auto erase enabled, data in those sectors will
624 * be needlessly destroyed; and some of the limited
625 * number of flash erase cycles will be wasted...
626 *
627 * In both cases, the extra writes slow things down.
628 */
629
630 /* if we have multiple sections within our image,
631 * flash programming could fail due to alignment issues
632 * attempt to rebuild a consecutive buffer for the flash loader */
633 pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size);
634 padding[section_last] = pad_bytes;
635 run_size += sections[++section_last]->size;
636 run_size += pad_bytes;
637
638 if (pad_bytes > 0)
639 LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
640 }
641
642 assert (run_address + run_size - 1 <= c->base + c->size - 1);
643
644 /* If we're applying any sector automagic, then pad this
645 * (maybe-combined) segment to the end of its last sector.
646 */
647 if (unlock || erase) {
648 int sector;
649 uint32_t offset_start = run_address - c->base;
650 uint32_t offset_end = offset_start + run_size;
651 uint32_t end = offset_end, delta;
652
653 for (sector = 0; sector < c->num_sectors; sector++) {
654 end = c->sectors[sector].offset
655 + c->sectors[sector].size;
656 if (offset_end <= end)
657 break;
658 }
659
660 delta = end - offset_end;
661 padding[section_last] += delta;
662 run_size += delta;
663 }
664
665 /* allocate buffer */
666 buffer = malloc(run_size);
667 buffer_size = 0;
668
669 /* read sections to the buffer */
670 while (buffer_size < run_size)
671 {
672 size_t size_read;
673
674 size_read = run_size - buffer_size;
675 if (size_read > sections[section]->size - section_offset)
676 size_read = sections[section]->size - section_offset;
677
678 /* KLUDGE!
679 *
680 * #¤%#"%¤% we have to figure out the section # from the sorted
681 * list of pointers to sections to invoke image_read_section()...
682 */
683 intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
684 int t_section_num = diff / sizeof(struct imageection);
685
686 LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, section_offset = %d, buffer_size = %d, size_read = %d",
687 (int)section,
688 (int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read);
689 if ((retval = image_read_section(image, t_section_num, section_offset,
690 size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
691 {
692 free(buffer);
693 goto done;
694 }
695
696 /* see if we need to pad the section */
697 while (padding[section]--)
698 (buffer + buffer_size)[size_read++] = 0xff;
699
700 buffer_size += size_read;
701 section_offset += size_read;
702
703 if (section_offset >= sections[section]->size)
704 {
705 section++;
706 section_offset = 0;
707 }
708 }
709
710 retval = ERROR_OK;
711
712 if (unlock)
713 {
714 retval = flash_unlock_address_range(target, run_address, run_size);
715 }
716 if (retval == ERROR_OK)
717 {
718 if (erase)
719 {
720 /* calculate and erase sectors */
721 retval = flash_erase_address_range(target,
722 true, run_address, run_size);
723 }
724 }
725
726 if (retval == ERROR_OK)
727 {
728 /* write flash sectors */
729 retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
730 }
731
732 free(buffer);
733
734 if (retval != ERROR_OK)
735 {
736 /* abort operation */
737 goto done;
738 }
739
740 if (written != NULL)
741 *written += run_size; /* add run size to total written counter */
742 }
743
744
745 done:
746 free(sections);
747 free(padding);
748
749 return retval;
750 }
751
752 int flash_write(struct target *target, struct image *image,
753 uint32_t *written, int erase)
754 {
755 return flash_write_unlock(target, image, written, erase, false);
756 }
757
758 /**
759 * Invalidates cached flash state which a target can change as it runs.
760 *
761 * @param target The target being resumed
762 *
763 * OpenOCD caches some flash state for brief periods. For example, a sector
764 * that is protected must be unprotected before OpenOCD tries to write it,
765 * Also, a sector that's not erased must be erased before it's written.
766 *
767 * As a rule, OpenOCD and target firmware can both modify the flash, so when
768 * a target starts running, OpenOCD needs to invalidate its cached state.
769 */
770 void nor_resume(struct target *target)
771 {
772 struct flash_bank *bank;
773
774 for (bank = flash_banks; bank; bank = bank->next) {
775 int i;
776
777 if (bank->target != target)
778 continue;
779
780 for (i = 0; i < bank->num_sectors; i++) {
781 struct flash_sector *sector = bank->sectors + i;
782
783 sector->is_erased = -1;
784 sector->is_protected = -1;
785 }
786 }
787 }

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)