target: change prototype of handle_bp_command_list()
[openocd.git] / src / target / armv7a.c
1 /***************************************************************************
2 * Copyright (C) 2009 by David Brownell *
3 * *
4 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <helper/replacements.h>
25
26 #include "armv7a.h"
27 #include "armv7a_mmu.h"
28 #include "arm_disassembler.h"
29
30 #include "register.h"
31 #include <helper/binarybuffer.h>
32 #include <helper/command.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "arm_opcodes.h"
39 #include "target.h"
40 #include "target_type.h"
41
42 static void armv7a_show_fault_registers(struct target *target)
43 {
44 uint32_t dfsr, ifsr, dfar, ifar;
45 struct armv7a_common *armv7a = target_to_armv7a(target);
46 struct arm_dpm *dpm = armv7a->arm.dpm;
47 int retval;
48
49 retval = dpm->prepare(dpm);
50 if (retval != ERROR_OK)
51 return;
52
53 /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */
54
55 /* c5/c0 - {data, instruction} fault status registers */
56 retval = dpm->instr_read_data_r0(dpm,
57 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
58 &dfsr);
59 if (retval != ERROR_OK)
60 goto done;
61
62 retval = dpm->instr_read_data_r0(dpm,
63 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
64 &ifsr);
65 if (retval != ERROR_OK)
66 goto done;
67
68 /* c6/c0 - {data, instruction} fault address registers */
69 retval = dpm->instr_read_data_r0(dpm,
70 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
71 &dfar);
72 if (retval != ERROR_OK)
73 goto done;
74
75 retval = dpm->instr_read_data_r0(dpm,
76 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
77 &ifar);
78 if (retval != ERROR_OK)
79 goto done;
80
81 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
82 ", DFAR: %8.8" PRIx32, dfsr, dfar);
83 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
84 ", IFAR: %8.8" PRIx32, ifsr, ifar);
85
86 done:
87 /* (void) */ dpm->finish(dpm);
88 }
89
90
91 /* retrieve main id register */
92 static int armv7a_read_midr(struct target *target)
93 {
94 int retval = ERROR_FAIL;
95 struct armv7a_common *armv7a = target_to_armv7a(target);
96 struct arm_dpm *dpm = armv7a->arm.dpm;
97 uint32_t midr;
98 retval = dpm->prepare(dpm);
99 if (retval != ERROR_OK)
100 goto done;
101 /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/
102
103 retval = dpm->instr_read_data_r0(dpm,
104 ARMV4_5_MRC(15, 0, 0, 0, 0, 0),
105 &midr);
106 if (retval != ERROR_OK)
107 goto done;
108
109 armv7a->rev = (midr & 0xf);
110 armv7a->partnum = (midr >> 4) & 0xfff;
111 armv7a->arch = (midr >> 16) & 0xf;
112 armv7a->variant = (midr >> 20) & 0xf;
113 armv7a->implementor = (midr >> 24) & 0xff;
114 LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
115 ", variant %" PRIx32 ", implementor %" PRIx32,
116 target->cmd_name,
117 armv7a->rev,
118 armv7a->partnum,
119 armv7a->arch,
120 armv7a->variant,
121 armv7a->implementor);
122
123 done:
124 dpm->finish(dpm);
125 return retval;
126 }
127
128 int armv7a_read_ttbcr(struct target *target)
129 {
130 struct armv7a_common *armv7a = target_to_armv7a(target);
131 struct arm_dpm *dpm = armv7a->arm.dpm;
132 uint32_t ttbcr, ttbcr_n;
133 int ttbidx;
134 int retval;
135
136 retval = dpm->prepare(dpm);
137 if (retval != ERROR_OK)
138 goto done;
139
140 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
141 retval = dpm->instr_read_data_r0(dpm,
142 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
143 &ttbcr);
144 if (retval != ERROR_OK)
145 goto done;
146
147 LOG_DEBUG("ttbcr %" PRIx32, ttbcr);
148
149 ttbcr_n = ttbcr & 0x7;
150 armv7a->armv7a_mmu.ttbcr = ttbcr;
151 armv7a->armv7a_mmu.cached = 1;
152
153 for (ttbidx = 0; ttbidx < 2; ttbidx++) {
154 /* MRC p15,0,<Rt>,c2,c0,ttbidx */
155 retval = dpm->instr_read_data_r0(dpm,
156 ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
157 &armv7a->armv7a_mmu.ttbr[ttbidx]);
158 if (retval != ERROR_OK)
159 goto done;
160 }
161
162 /*
163 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
164 * document # ARM DDI 0406C
165 */
166 armv7a->armv7a_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n;
167 armv7a->armv7a_mmu.ttbr_range[1] = 0xffffffff;
168 armv7a->armv7a_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n);
169 armv7a->armv7a_mmu.ttbr_mask[1] = 0xffffffff << 14;
170 armv7a->armv7a_mmu.cached = 1;
171
172 retval = armv7a_read_midr(target);
173 if (retval != ERROR_OK)
174 goto done;
175
176 /* FIXME: why this special case based on part number? */
177 if ((armv7a->partnum & 0xf) == 0) {
178 /* ARM DDI 0344H , ARM DDI 0407F */
179 armv7a->armv7a_mmu.ttbr_mask[0] = 7 << (32 - ttbcr_n);
180 }
181
182 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32,
183 (ttbcr_n != 0) ? "used" : "not used",
184 armv7a->armv7a_mmu.ttbr_mask[0],
185 armv7a->armv7a_mmu.ttbr_mask[1]);
186
187 done:
188 dpm->finish(dpm);
189 return retval;
190 }
191
192 /* FIXME: remove it */
193 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
194 {
195 struct armv7a_l2x_cache *l2x_cache;
196 struct target_list *head = target->head;
197 struct target *curr;
198
199 struct armv7a_common *armv7a = target_to_armv7a(target);
200 l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
201 l2x_cache->base = base;
202 l2x_cache->way = way;
203 /*LOG_INFO("cache l2 initialized base %x way %d",
204 l2x_cache->base,l2x_cache->way);*/
205 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
206 LOG_INFO("outer cache already initialized\n");
207 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
208 /* initialize all target in this cluster (smp target)
209 * l2 cache must be configured after smp declaration */
210 while (head != (struct target_list *)NULL) {
211 curr = head->target;
212 if (curr != target) {
213 armv7a = target_to_armv7a(curr);
214 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
215 LOG_ERROR("smp target : outer cache already initialized\n");
216 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
217 }
218 head = head->next;
219 }
220 return JIM_OK;
221 }
222
223 /* FIXME: remove it */
224 COMMAND_HANDLER(handle_cache_l2x)
225 {
226 struct target *target = get_current_target(CMD_CTX);
227 uint32_t base, way;
228
229 if (CMD_ARGC != 2)
230 return ERROR_COMMAND_SYNTAX_ERROR;
231
232 /* command_print(CMD_CTX, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
233 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
234 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
235
236 /* AP address is in bits 31:24 of DP_SELECT */
237 armv7a_l2x_cache_init(target, base, way);
238
239 return ERROR_OK;
240 }
241
242 int armv7a_handle_cache_info_command(struct command_invocation *cmd,
243 struct armv7a_cache_common *armv7a_cache)
244 {
245 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
246 (armv7a_cache->outer_cache);
247
248 int cl;
249
250 if (armv7a_cache->info == -1) {
251 command_print(cmd->ctx, "cache not yet identified");
252 return ERROR_OK;
253 }
254
255 for (cl = 0; cl < armv7a_cache->loc; cl++) {
256 struct armv7a_arch_cache *arch = &(armv7a_cache->arch[cl]);
257
258 if (arch->ctype & 1) {
259 command_print(cmd->ctx,
260 "L%d I-Cache: linelen %" PRIi32
261 ", associativity %" PRIi32
262 ", nsets %" PRIi32
263 ", cachesize %" PRId32 " KBytes",
264 cl+1,
265 arch->i_size.linelen,
266 arch->i_size.associativity,
267 arch->i_size.nsets,
268 arch->i_size.cachesize);
269 }
270
271 if (arch->ctype >= 2) {
272 command_print(cmd->ctx,
273 "L%d D-Cache: linelen %" PRIi32
274 ", associativity %" PRIi32
275 ", nsets %" PRIi32
276 ", cachesize %" PRId32 " KBytes",
277 cl+1,
278 arch->d_u_size.linelen,
279 arch->d_u_size.associativity,
280 arch->d_u_size.nsets,
281 arch->d_u_size.cachesize);
282 }
283 }
284
285 if (l2x_cache != NULL)
286 command_print(cmd->ctx, "Outer unified cache Base Address 0x%" PRIx32 ", %" PRId32 " ways",
287 l2x_cache->base, l2x_cache->way);
288
289 return ERROR_OK;
290 }
291
292 /* retrieve core id cluster id */
293 static int armv7a_read_mpidr(struct target *target)
294 {
295 int retval = ERROR_FAIL;
296 struct armv7a_common *armv7a = target_to_armv7a(target);
297 struct arm_dpm *dpm = armv7a->arm.dpm;
298 uint32_t mpidr;
299 retval = dpm->prepare(dpm);
300 if (retval != ERROR_OK)
301 goto done;
302 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
303
304 retval = dpm->instr_read_data_r0(dpm,
305 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
306 &mpidr);
307 if (retval != ERROR_OK)
308 goto done;
309
310 /* Is register in Multiprocessing Extensions register format? */
311 if (mpidr & MPIDR_MP_EXT) {
312 LOG_DEBUG("%s: MPIDR 0x%" PRIx32, target_name(target), mpidr);
313 armv7a->multi_processor_system = (mpidr >> 30) & 1;
314 armv7a->multi_threading_processor = (mpidr >> 24) & 1;
315 armv7a->level2_id = (mpidr >> 16) & 0xf;
316 armv7a->cluster_id = (mpidr >> 8) & 0xf;
317 armv7a->cpu_id = mpidr & 0xf;
318 LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s",
319 target_name(target),
320 armv7a->level2_id,
321 armv7a->cluster_id,
322 armv7a->cpu_id,
323 armv7a->multi_processor_system == 0 ? "multi core" : "mono core",
324 armv7a->multi_threading_processor == 1 ? "SMT" : "no SMT");
325
326 } else
327 LOG_ERROR("MPIDR not in multiprocessor format");
328
329 done:
330 dpm->finish(dpm);
331 return retval;
332
333
334 }
335
336 static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
337 {
338 int retval = ERROR_OK;
339
340 /* select cache level */
341 retval = dpm->instr_write_data_r0(dpm,
342 ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
343 (cl << 1) | (ct == 1 ? 1 : 0));
344 if (retval != ERROR_OK)
345 goto done;
346
347 retval = dpm->instr_read_data_r0(dpm,
348 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
349 cache_reg);
350 done:
351 return retval;
352 }
353
354 static struct armv7a_cachesize decode_cache_reg(uint32_t cache_reg)
355 {
356 struct armv7a_cachesize size;
357 int i = 0;
358
359 size.linelen = 16 << (cache_reg & 0x7);
360 size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
361 size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
362 size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
363
364 /* compute info for set way operation on cache */
365 size.index_shift = (cache_reg & 0x7) + 4;
366 size.index = (cache_reg >> 13) & 0x7fff;
367 size.way = ((cache_reg >> 3) & 0x3ff);
368
369 while (((size.way << i) & 0x80000000) == 0)
370 i++;
371 size.way_shift = i;
372
373 return size;
374 }
375
376 int armv7a_identify_cache(struct target *target)
377 {
378 /* read cache descriptor */
379 int retval = ERROR_FAIL;
380 struct armv7a_common *armv7a = target_to_armv7a(target);
381 struct arm_dpm *dpm = armv7a->arm.dpm;
382 uint32_t csselr, clidr, ctr;
383 uint32_t cache_reg;
384 int cl, ctype;
385 struct armv7a_cache_common *cache =
386 &(armv7a->armv7a_mmu.armv7a_cache);
387
388 retval = dpm->prepare(dpm);
389 if (retval != ERROR_OK)
390 goto done;
391
392 /* retrieve CTR
393 * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
394 retval = dpm->instr_read_data_r0(dpm,
395 ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
396 &ctr);
397 if (retval != ERROR_OK)
398 goto done;
399
400 cache->iminline = 4UL << (ctr & 0xf);
401 cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
402 LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRId32 " ctr.dminline %" PRId32,
403 ctr, cache->iminline, cache->dminline);
404
405 /* retrieve CLIDR
406 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
407 retval = dpm->instr_read_data_r0(dpm,
408 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
409 &clidr);
410 if (retval != ERROR_OK)
411 goto done;
412
413 cache->loc = (clidr & 0x7000000) >> 24;
414 LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc);
415
416 /* retrieve selected cache for later restore
417 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
418 retval = dpm->instr_read_data_r0(dpm,
419 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
420 &csselr);
421 if (retval != ERROR_OK)
422 goto done;
423
424 /* retrieve all available inner caches */
425 for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
426
427 /* isolate cache type at current level */
428 ctype = clidr & 7;
429
430 /* skip reserved values */
431 if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE)
432 continue;
433
434 /* separate d or unified d/i cache at this level ? */
435 if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) {
436 /* retrieve d-cache info */
437 retval = get_cache_info(dpm, cl, 0, &cache_reg);
438 if (retval != ERROR_OK)
439 goto done;
440 cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
441
442 LOG_DEBUG("data/unified cache index %d << %d, way %d << %d",
443 cache->arch[cl].d_u_size.index,
444 cache->arch[cl].d_u_size.index_shift,
445 cache->arch[cl].d_u_size.way,
446 cache->arch[cl].d_u_size.way_shift);
447
448 LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
449 cache->arch[cl].d_u_size.linelen,
450 cache->arch[cl].d_u_size.cachesize,
451 cache->arch[cl].d_u_size.associativity);
452 }
453
454 /* separate i-cache at this level ? */
455 if (ctype & CACHE_LEVEL_HAS_I_CACHE) {
456 /* retrieve i-cache info */
457 retval = get_cache_info(dpm, cl, 1, &cache_reg);
458 if (retval != ERROR_OK)
459 goto done;
460 cache->arch[cl].i_size = decode_cache_reg(cache_reg);
461
462 LOG_DEBUG("instruction cache index %d << %d, way %d << %d",
463 cache->arch[cl].i_size.index,
464 cache->arch[cl].i_size.index_shift,
465 cache->arch[cl].i_size.way,
466 cache->arch[cl].i_size.way_shift);
467
468 LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
469 cache->arch[cl].i_size.linelen,
470 cache->arch[cl].i_size.cachesize,
471 cache->arch[cl].i_size.associativity);
472 }
473
474 cache->arch[cl].ctype = ctype;
475 }
476
477 /* restore selected cache */
478 dpm->instr_write_data_r0(dpm,
479 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
480 csselr);
481
482 if (retval != ERROR_OK)
483 goto done;
484
485 /* if no l2 cache initialize l1 data cache flush function function */
486 if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
487 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
488 armv7a_cache_auto_flush_all_data;
489 }
490
491 armv7a->armv7a_mmu.armv7a_cache.info = 1;
492 done:
493 dpm->finish(dpm);
494 armv7a_read_mpidr(target);
495 return retval;
496
497 }
498
499 static int armv7a_setup_semihosting(struct target *target, int enable)
500 {
501 struct armv7a_common *armv7a = target_to_armv7a(target);
502 uint32_t vcr;
503 int ret;
504
505 ret = mem_ap_read_atomic_u32(armv7a->debug_ap,
506 armv7a->debug_base + CPUDBG_VCR,
507 &vcr);
508 if (ret < 0) {
509 LOG_ERROR("Failed to read VCR register\n");
510 return ret;
511 }
512
513 if (enable)
514 vcr |= DBG_VCR_SVC_MASK;
515 else
516 vcr &= ~DBG_VCR_SVC_MASK;
517
518 ret = mem_ap_write_atomic_u32(armv7a->debug_ap,
519 armv7a->debug_base + CPUDBG_VCR,
520 vcr);
521 if (ret < 0)
522 LOG_ERROR("Failed to write VCR register\n");
523
524 return ret;
525 }
526
527 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
528 {
529 struct arm *arm = &armv7a->arm;
530 arm->arch_info = armv7a;
531 target->arch_info = &armv7a->arm;
532 arm->setup_semihosting = armv7a_setup_semihosting;
533 /* target is useful in all function arm v4 5 compatible */
534 armv7a->arm.target = target;
535 armv7a->arm.common_magic = ARM_COMMON_MAGIC;
536 armv7a->common_magic = ARMV7_COMMON_MAGIC;
537 armv7a->armv7a_mmu.armv7a_cache.info = -1;
538 armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL;
539 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
540 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = 1;
541 return ERROR_OK;
542 }
543
544 int armv7a_arch_state(struct target *target)
545 {
546 static const char *state[] = {
547 "disabled", "enabled"
548 };
549
550 struct armv7a_common *armv7a = target_to_armv7a(target);
551 struct arm *arm = &armv7a->arm;
552
553 if (armv7a->common_magic != ARMV7_COMMON_MAGIC) {
554 LOG_ERROR("BUG: called for a non-ARMv7A target");
555 return ERROR_COMMAND_SYNTAX_ERROR;
556 }
557
558 arm_arch_state(target);
559
560 if (armv7a->is_armv7r) {
561 LOG_USER("D-Cache: %s, I-Cache: %s",
562 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
563 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
564 } else {
565 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
566 state[armv7a->armv7a_mmu.mmu_enabled],
567 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
568 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
569 }
570
571 if (arm->core_mode == ARM_MODE_ABT)
572 armv7a_show_fault_registers(target);
573 if (target->debug_reason == DBG_REASON_WATCHPOINT)
574 LOG_USER("Watchpoint triggered at PC %#08x",
575 (unsigned) armv7a->dpm.wp_pc);
576
577 return ERROR_OK;
578 }
579
580 static const struct command_registration l2_cache_commands[] = {
581 {
582 .name = "l2x",
583 .handler = handle_cache_l2x,
584 .mode = COMMAND_EXEC,
585 .help = "configure l2x cache",
586 .usage = "[base_addr] [number_of_way]",
587 },
588 COMMAND_REGISTRATION_DONE
589
590 };
591
592 const struct command_registration l2x_cache_command_handlers[] = {
593 {
594 .name = "cache_config",
595 .mode = COMMAND_EXEC,
596 .help = "cache configuration for a target",
597 .usage = "",
598 .chain = l2_cache_commands,
599 },
600 COMMAND_REGISTRATION_DONE
601 };
602
603 const struct command_registration armv7a_command_handlers[] = {
604 {
605 .chain = l2x_cache_command_handlers,
606 },
607 {
608 .chain = arm7a_cache_command_handlers,
609 },
610 COMMAND_REGISTRATION_DONE
611 };

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)