1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2008 by Spencer Oliver *
5 * spen@spen-soft.co.uk *
7 * Copyright (C) 2008 by David T.L. Wong *
9 * Copyright (C) 2007,2008 Øyvind Harboe *
10 * oyvind.harboe@zylin.com *
12 * Copyright (C) 2011 by Drasko DRASKOVIC *
13 * drasko.draskovic@gmail.com *
14 ***************************************************************************/
22 #include "breakpoints.h"
23 #include "algorithm.h"
26 static const char *mips_isa_strings
[] = {
27 "MIPS32", "MIPS16", "", "MICRO MIPS32",
30 #define MIPS32_GDB_DUMMY_FP_REG 1
34 * based on gdb-7.6.2/gdb/features/mips-{fpu,cp0,cpu}.xml
44 { 0, "r0", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
45 { 1, "r1", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
46 { 2, "r2", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
47 { 3, "r3", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
48 { 4, "r4", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
49 { 5, "r5", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
50 { 6, "r6", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
51 { 7, "r7", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
52 { 8, "r8", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
53 { 9, "r9", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
54 { 10, "r10", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
55 { 11, "r11", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
56 { 12, "r12", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
57 { 13, "r13", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
58 { 14, "r14", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
59 { 15, "r15", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
60 { 16, "r16", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
61 { 17, "r17", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
62 { 18, "r18", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
63 { 19, "r19", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
64 { 20, "r20", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
65 { 21, "r21", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
66 { 22, "r22", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
67 { 23, "r23", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
68 { 24, "r24", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
69 { 25, "r25", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
70 { 26, "r26", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
71 { 27, "r27", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
72 { 28, "r28", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
73 { 29, "r29", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
74 { 30, "r30", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
75 { 31, "r31", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
76 { 32, "status", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cp0", 0 },
77 { 33, "lo", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
78 { 34, "hi", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
79 { 35, "badvaddr", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cp0", 0 },
80 { 36, "cause", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cp0", 0 },
81 { 37, "pc", REG_TYPE_INT
, NULL
, "org.gnu.gdb.mips.cpu", 0 },
83 { 38, "f0", REG_TYPE_IEEE_SINGLE
, NULL
,
84 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
85 { 39, "f1", REG_TYPE_IEEE_SINGLE
, NULL
,
86 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
87 { 40, "f2", REG_TYPE_IEEE_SINGLE
, NULL
,
88 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
89 { 41, "f3", REG_TYPE_IEEE_SINGLE
, NULL
,
90 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
91 { 42, "f4", REG_TYPE_IEEE_SINGLE
, NULL
,
92 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
93 { 43, "f5", REG_TYPE_IEEE_SINGLE
, NULL
,
94 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
95 { 44, "f6", REG_TYPE_IEEE_SINGLE
, NULL
,
96 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
97 { 45, "f7", REG_TYPE_IEEE_SINGLE
, NULL
,
98 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
99 { 46, "f8", REG_TYPE_IEEE_SINGLE
, NULL
,
100 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
101 { 47, "f9", REG_TYPE_IEEE_SINGLE
, NULL
,
102 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
103 { 48, "f10", REG_TYPE_IEEE_SINGLE
, NULL
,
104 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
105 { 49, "f11", REG_TYPE_IEEE_SINGLE
, NULL
,
106 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
107 { 50, "f12", REG_TYPE_IEEE_SINGLE
, NULL
,
108 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
109 { 51, "f13", REG_TYPE_IEEE_SINGLE
, NULL
,
110 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
111 { 52, "f14", REG_TYPE_IEEE_SINGLE
, NULL
,
112 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
113 { 53, "f15", REG_TYPE_IEEE_SINGLE
, NULL
,
114 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
115 { 54, "f16", REG_TYPE_IEEE_SINGLE
, NULL
,
116 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
117 { 55, "f17", REG_TYPE_IEEE_SINGLE
, NULL
,
118 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
119 { 56, "f18", REG_TYPE_IEEE_SINGLE
, NULL
,
120 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
121 { 57, "f19", REG_TYPE_IEEE_SINGLE
, NULL
,
122 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
123 { 58, "f20", REG_TYPE_IEEE_SINGLE
, NULL
,
124 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
125 { 59, "f21", REG_TYPE_IEEE_SINGLE
, NULL
,
126 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
127 { 60, "f22", REG_TYPE_IEEE_SINGLE
, NULL
,
128 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
129 { 61, "f23", REG_TYPE_IEEE_SINGLE
, NULL
,
130 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
131 { 62, "f24", REG_TYPE_IEEE_SINGLE
, NULL
,
132 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
133 { 63, "f25", REG_TYPE_IEEE_SINGLE
, NULL
,
134 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
135 { 64, "f26", REG_TYPE_IEEE_SINGLE
, NULL
,
136 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
137 { 65, "f27", REG_TYPE_IEEE_SINGLE
, NULL
,
138 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
139 { 66, "f28", REG_TYPE_IEEE_SINGLE
, NULL
,
140 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
141 { 67, "f29", REG_TYPE_IEEE_SINGLE
, NULL
,
142 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
143 { 68, "f30", REG_TYPE_IEEE_SINGLE
, NULL
,
144 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
145 { 69, "f31", REG_TYPE_IEEE_SINGLE
, NULL
,
146 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
147 { 70, "fcsr", REG_TYPE_INT
, "float",
148 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
149 { 71, "fir", REG_TYPE_INT
, "float",
150 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG
},
154 #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs)
156 static uint8_t mips32_gdb_dummy_fp_value
[] = {0, 0, 0, 0};
158 static int mips32_get_core_reg(struct reg
*reg
)
161 struct mips32_core_reg
*mips32_reg
= reg
->arch_info
;
162 struct target
*target
= mips32_reg
->target
;
163 struct mips32_common
*mips32_target
= target_to_mips32(target
);
165 if (target
->state
!= TARGET_HALTED
)
166 return ERROR_TARGET_NOT_HALTED
;
168 retval
= mips32_target
->read_core_reg(target
, mips32_reg
->num
);
173 static int mips32_set_core_reg(struct reg
*reg
, uint8_t *buf
)
175 struct mips32_core_reg
*mips32_reg
= reg
->arch_info
;
176 struct target
*target
= mips32_reg
->target
;
177 uint32_t value
= buf_get_u32(buf
, 0, 32);
179 if (target
->state
!= TARGET_HALTED
)
180 return ERROR_TARGET_NOT_HALTED
;
182 buf_set_u32(reg
->value
, 0, 32, value
);
189 static int mips32_read_core_reg(struct target
*target
, unsigned int num
)
193 /* get pointers to arch-specific information */
194 struct mips32_common
*mips32
= target_to_mips32(target
);
196 if (num
>= MIPS32_NUM_REGS
)
197 return ERROR_COMMAND_SYNTAX_ERROR
;
199 reg_value
= mips32
->core_regs
[num
];
200 buf_set_u32(mips32
->core_cache
->reg_list
[num
].value
, 0, 32, reg_value
);
201 mips32
->core_cache
->reg_list
[num
].valid
= true;
202 mips32
->core_cache
->reg_list
[num
].dirty
= false;
207 static int mips32_write_core_reg(struct target
*target
, unsigned int num
)
211 /* get pointers to arch-specific information */
212 struct mips32_common
*mips32
= target_to_mips32(target
);
214 if (num
>= MIPS32_NUM_REGS
)
215 return ERROR_COMMAND_SYNTAX_ERROR
;
217 reg_value
= buf_get_u32(mips32
->core_cache
->reg_list
[num
].value
, 0, 32);
218 mips32
->core_regs
[num
] = reg_value
;
219 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", num
, reg_value
);
220 mips32
->core_cache
->reg_list
[num
].valid
= true;
221 mips32
->core_cache
->reg_list
[num
].dirty
= false;
226 int mips32_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
227 int *reg_list_size
, enum target_register_class reg_class
)
229 /* get pointers to arch-specific information */
230 struct mips32_common
*mips32
= target_to_mips32(target
);
233 /* include floating point registers */
234 *reg_list_size
= MIPS32_NUM_REGS
;
235 *reg_list
= malloc(sizeof(struct reg
*) * (*reg_list_size
));
237 for (i
= 0; i
< MIPS32_NUM_REGS
; i
++)
238 (*reg_list
)[i
] = &mips32
->core_cache
->reg_list
[i
];
243 int mips32_save_context(struct target
*target
)
247 /* get pointers to arch-specific information */
248 struct mips32_common
*mips32
= target_to_mips32(target
);
249 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
251 /* read core registers */
252 mips32_pracc_read_regs(ejtag_info
, mips32
->core_regs
);
254 for (i
= 0; i
< MIPS32_NUM_REGS
; i
++) {
255 if (!mips32
->core_cache
->reg_list
[i
].valid
)
256 mips32
->read_core_reg(target
, i
);
262 int mips32_restore_context(struct target
*target
)
266 /* get pointers to arch-specific information */
267 struct mips32_common
*mips32
= target_to_mips32(target
);
268 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
270 for (i
= 0; i
< MIPS32_NUM_REGS
; i
++) {
271 if (mips32
->core_cache
->reg_list
[i
].dirty
)
272 mips32
->write_core_reg(target
, i
);
275 /* write core regs */
276 mips32_pracc_write_regs(ejtag_info
, mips32
->core_regs
);
281 int mips32_arch_state(struct target
*target
)
283 struct mips32_common
*mips32
= target_to_mips32(target
);
285 LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32
"",
286 mips_isa_strings
[mips32
->isa_mode
],
287 debug_reason_name(target
),
288 buf_get_u32(mips32
->core_cache
->reg_list
[MIPS32_PC
].value
, 0, 32));
293 static const struct reg_arch_type mips32_reg_type
= {
294 .get
= mips32_get_core_reg
,
295 .set
= mips32_set_core_reg
,
298 struct reg_cache
*mips32_build_reg_cache(struct target
*target
)
300 /* get pointers to arch-specific information */
301 struct mips32_common
*mips32
= target_to_mips32(target
);
303 int num_regs
= MIPS32_NUM_REGS
;
304 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
305 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
306 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
307 struct mips32_core_reg
*arch_info
= malloc(sizeof(struct mips32_core_reg
) * num_regs
);
308 struct reg_feature
*feature
;
311 /* Build the process context cache */
312 cache
->name
= "mips32 registers";
314 cache
->reg_list
= reg_list
;
315 cache
->num_regs
= num_regs
;
317 mips32
->core_cache
= cache
;
319 for (i
= 0; i
< num_regs
; i
++) {
320 arch_info
[i
].num
= mips32_regs
[i
].id
;
321 arch_info
[i
].target
= target
;
322 arch_info
[i
].mips32_common
= mips32
;
324 reg_list
[i
].name
= mips32_regs
[i
].name
;
325 reg_list
[i
].size
= 32;
327 if (mips32_regs
[i
].flag
== MIPS32_GDB_DUMMY_FP_REG
) {
328 reg_list
[i
].value
= mips32_gdb_dummy_fp_value
;
329 reg_list
[i
].valid
= true;
330 reg_list
[i
].arch_info
= NULL
;
331 register_init_dummy(®_list
[i
]);
333 reg_list
[i
].value
= calloc(1, 4);
334 reg_list
[i
].valid
= false;
335 reg_list
[i
].type
= &mips32_reg_type
;
336 reg_list
[i
].arch_info
= &arch_info
[i
];
338 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
339 if (reg_list
[i
].reg_data_type
)
340 reg_list
[i
].reg_data_type
->type
= mips32_regs
[i
].type
;
342 LOG_ERROR("unable to allocate reg type list");
345 reg_list
[i
].dirty
= false;
347 reg_list
[i
].group
= mips32_regs
[i
].group
;
348 reg_list
[i
].number
= i
;
349 reg_list
[i
].exist
= true;
350 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
352 feature
= calloc(1, sizeof(struct reg_feature
));
354 feature
->name
= mips32_regs
[i
].feature
;
355 reg_list
[i
].feature
= feature
;
357 LOG_ERROR("unable to allocate feature list");
363 int mips32_init_arch_info(struct target
*target
, struct mips32_common
*mips32
, struct jtag_tap
*tap
)
365 target
->arch_info
= mips32
;
366 mips32
->common_magic
= MIPS32_COMMON_MAGIC
;
367 mips32
->fast_data_area
= NULL
;
368 mips32
->isa_imp
= MIPS32_ONLY
; /* default */
370 /* has breakpoint/watchpoint unit been scanned */
371 mips32
->bp_scanned
= 0;
372 mips32
->data_break_list
= NULL
;
374 mips32
->ejtag_info
.tap
= tap
;
375 mips32
->read_core_reg
= mips32_read_core_reg
;
376 mips32
->write_core_reg
= mips32_write_core_reg
;
377 /* if unknown endianness defaults to little endian, 1 */
378 mips32
->ejtag_info
.endianness
= target
->endianness
== TARGET_BIG_ENDIAN
? 0 : 1;
379 mips32
->ejtag_info
.scan_delay
= MIPS32_SCAN_DELAY_LEGACY_MODE
;
380 mips32
->ejtag_info
.mode
= 0; /* Initial default value */
381 mips32
->ejtag_info
.isa
= 0; /* isa on debug mips32, updated by poll function */
382 mips32
->ejtag_info
.config_regs
= 0; /* no config register read */
386 /* run to exit point. return error if exit point was not reached. */
387 static int mips32_run_and_wait(struct target
*target
, target_addr_t entry_point
,
388 unsigned int timeout_ms
, target_addr_t exit_point
, struct mips32_common
*mips32
)
392 /* This code relies on the target specific resume() and poll()->debug_entry()
393 * sequence to write register values to the processor and the read them back */
394 retval
= target_resume(target
, 0, entry_point
, 0, 1);
395 if (retval
!= ERROR_OK
)
398 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
399 /* If the target fails to halt due to the breakpoint, force a halt */
400 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
401 retval
= target_halt(target
);
402 if (retval
!= ERROR_OK
)
404 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
405 if (retval
!= ERROR_OK
)
407 return ERROR_TARGET_TIMEOUT
;
410 pc
= buf_get_u32(mips32
->core_cache
->reg_list
[MIPS32_PC
].value
, 0, 32);
411 if (exit_point
&& (pc
!= exit_point
)) {
412 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
" ", pc
);
413 return ERROR_TARGET_TIMEOUT
;
419 int mips32_run_algorithm(struct target
*target
, int num_mem_params
,
420 struct mem_param
*mem_params
, int num_reg_params
,
421 struct reg_param
*reg_params
, target_addr_t entry_point
,
422 target_addr_t exit_point
, unsigned int timeout_ms
, void *arch_info
)
424 struct mips32_common
*mips32
= target_to_mips32(target
);
425 struct mips32_algorithm
*mips32_algorithm_info
= arch_info
;
426 enum mips32_isa_mode isa_mode
= mips32
->isa_mode
;
428 uint32_t context
[MIPS32_NUM_REGS
];
429 int retval
= ERROR_OK
;
431 LOG_DEBUG("Running algorithm");
433 /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint
434 * at the exit point */
436 if (mips32
->common_magic
!= MIPS32_COMMON_MAGIC
) {
437 LOG_ERROR("current target isn't a MIPS32 target");
438 return ERROR_TARGET_INVALID
;
441 if (target
->state
!= TARGET_HALTED
) {
442 LOG_TARGET_ERROR(target
, "not halted (run target algo)");
443 return ERROR_TARGET_NOT_HALTED
;
446 /* refresh core register cache */
447 for (unsigned int i
= 0; i
< MIPS32_NUM_REGS
; i
++) {
448 if (!mips32
->core_cache
->reg_list
[i
].valid
)
449 mips32
->read_core_reg(target
, i
);
450 context
[i
] = buf_get_u32(mips32
->core_cache
->reg_list
[i
].value
, 0, 32);
453 for (int i
= 0; i
< num_mem_params
; i
++) {
454 if (mem_params
[i
].direction
== PARAM_IN
)
456 retval
= target_write_buffer(target
, mem_params
[i
].address
,
457 mem_params
[i
].size
, mem_params
[i
].value
);
458 if (retval
!= ERROR_OK
)
462 for (int i
= 0; i
< num_reg_params
; i
++) {
463 if (reg_params
[i
].direction
== PARAM_IN
)
466 struct reg
*reg
= register_get_by_name(mips32
->core_cache
, reg_params
[i
].reg_name
, false);
469 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
470 return ERROR_COMMAND_SYNTAX_ERROR
;
473 if (reg
->size
!= reg_params
[i
].size
) {
474 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
475 reg_params
[i
].reg_name
);
476 return ERROR_COMMAND_SYNTAX_ERROR
;
479 mips32_set_core_reg(reg
, reg_params
[i
].value
);
482 mips32
->isa_mode
= mips32_algorithm_info
->isa_mode
;
484 retval
= mips32_run_and_wait(target
, entry_point
, timeout_ms
, exit_point
, mips32
);
486 if (retval
!= ERROR_OK
)
489 for (int i
= 0; i
< num_mem_params
; i
++) {
490 if (mem_params
[i
].direction
!= PARAM_OUT
) {
491 retval
= target_read_buffer(target
, mem_params
[i
].address
, mem_params
[i
].size
,
492 mem_params
[i
].value
);
493 if (retval
!= ERROR_OK
)
498 for (int i
= 0; i
< num_reg_params
; i
++) {
499 if (reg_params
[i
].direction
!= PARAM_OUT
) {
500 struct reg
*reg
= register_get_by_name(mips32
->core_cache
, reg_params
[i
].reg_name
, false);
502 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
503 return ERROR_COMMAND_SYNTAX_ERROR
;
506 if (reg
->size
!= reg_params
[i
].size
) {
507 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
508 reg_params
[i
].reg_name
);
509 return ERROR_COMMAND_SYNTAX_ERROR
;
512 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
516 /* restore everything we saved before */
517 for (unsigned int i
= 0; i
< MIPS32_NUM_REGS
; i
++) {
519 regvalue
= buf_get_u32(mips32
->core_cache
->reg_list
[i
].value
, 0, 32);
520 if (regvalue
!= context
[i
]) {
521 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
522 mips32
->core_cache
->reg_list
[i
].name
, context
[i
]);
523 buf_set_u32(mips32
->core_cache
->reg_list
[i
].value
,
525 mips32
->core_cache
->reg_list
[i
].valid
= true;
526 mips32
->core_cache
->reg_list
[i
].dirty
= true;
530 mips32
->isa_mode
= isa_mode
;
535 int mips32_examine(struct target
*target
)
537 struct mips32_common
*mips32
= target_to_mips32(target
);
539 if (!target_was_examined(target
)) {
540 target_set_examined(target
);
542 /* we will configure later */
543 mips32
->bp_scanned
= 0;
544 mips32
->num_inst_bpoints
= 0;
545 mips32
->num_data_bpoints
= 0;
546 mips32
->num_inst_bpoints_avail
= 0;
547 mips32
->num_data_bpoints_avail
= 0;
553 static int mips32_configure_ibs(struct target
*target
)
555 struct mips32_common
*mips32
= target_to_mips32(target
);
556 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
560 /* get number of inst breakpoints */
561 retval
= target_read_u32(target
, ejtag_info
->ejtag_ibs_addr
, &bpinfo
);
562 if (retval
!= ERROR_OK
)
565 mips32
->num_inst_bpoints
= (bpinfo
>> 24) & 0x0F;
566 mips32
->num_inst_bpoints_avail
= mips32
->num_inst_bpoints
;
567 mips32
->inst_break_list
= calloc(mips32
->num_inst_bpoints
,
568 sizeof(struct mips32_comparator
));
570 for (i
= 0; i
< mips32
->num_inst_bpoints
; i
++)
571 mips32
->inst_break_list
[i
].reg_address
=
572 ejtag_info
->ejtag_iba0_addr
+
573 (ejtag_info
->ejtag_iba_step_size
* i
);
576 retval
= target_write_u32(target
, ejtag_info
->ejtag_ibs_addr
, 0);
580 static int mips32_configure_dbs(struct target
*target
)
582 struct mips32_common
*mips32
= target_to_mips32(target
);
583 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
587 /* get number of data breakpoints */
588 retval
= target_read_u32(target
, ejtag_info
->ejtag_dbs_addr
, &bpinfo
);
589 if (retval
!= ERROR_OK
)
592 mips32
->num_data_bpoints
= (bpinfo
>> 24) & 0x0F;
593 mips32
->num_data_bpoints_avail
= mips32
->num_data_bpoints
;
594 mips32
->data_break_list
= calloc(mips32
->num_data_bpoints
,
595 sizeof(struct mips32_comparator
));
597 for (i
= 0; i
< mips32
->num_data_bpoints
; i
++)
598 mips32
->data_break_list
[i
].reg_address
=
599 ejtag_info
->ejtag_dba0_addr
+
600 (ejtag_info
->ejtag_dba_step_size
* i
);
603 retval
= target_write_u32(target
, ejtag_info
->ejtag_dbs_addr
, 0);
607 int mips32_configure_break_unit(struct target
*target
)
609 /* get pointers to arch-specific information */
610 struct mips32_common
*mips32
= target_to_mips32(target
);
611 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
615 if (mips32
->bp_scanned
)
618 /* get info about breakpoint support */
619 retval
= target_read_u32(target
, EJTAG_DCR
, &dcr
);
620 if (retval
!= ERROR_OK
)
623 /* EJTAG 2.0 defines IB and DB bits in IMP instead of DCR. */
624 if (ejtag_info
->ejtag_version
== EJTAG_VERSION_20
) {
625 ejtag_info
->debug_caps
= dcr
& EJTAG_DCR_ENM
;
626 if (!(ejtag_info
->impcode
& EJTAG_V20_IMP_NOIB
))
627 ejtag_info
->debug_caps
|= EJTAG_DCR_IB
;
628 if (!(ejtag_info
->impcode
& EJTAG_V20_IMP_NODB
))
629 ejtag_info
->debug_caps
|= EJTAG_DCR_DB
;
631 /* keep debug caps for later use */
632 ejtag_info
->debug_caps
= dcr
& (EJTAG_DCR_ENM
633 | EJTAG_DCR_IB
| EJTAG_DCR_DB
);
636 if (ejtag_info
->debug_caps
& EJTAG_DCR_IB
) {
637 retval
= mips32_configure_ibs(target
);
638 if (retval
!= ERROR_OK
)
642 if (ejtag_info
->debug_caps
& EJTAG_DCR_DB
) {
643 retval
= mips32_configure_dbs(target
);
644 if (retval
!= ERROR_OK
)
648 /* check if target endianness settings matches debug control register */
649 if (((ejtag_info
->debug_caps
& EJTAG_DCR_ENM
)
650 && (target
->endianness
== TARGET_LITTLE_ENDIAN
)) ||
651 (!(ejtag_info
->debug_caps
& EJTAG_DCR_ENM
)
652 && (target
->endianness
== TARGET_BIG_ENDIAN
)))
653 LOG_WARNING("DCR endianness settings does not match target settings");
655 LOG_DEBUG("DCR 0x%" PRIx32
" numinst %i numdata %i", dcr
, mips32
->num_inst_bpoints
,
656 mips32
->num_data_bpoints
);
658 mips32
->bp_scanned
= 1;
663 int mips32_enable_interrupts(struct target
*target
, int enable
)
669 /* read debug control register */
670 retval
= target_read_u32(target
, EJTAG_DCR
, &dcr
);
671 if (retval
!= ERROR_OK
)
675 if (!(dcr
& EJTAG_DCR_INTE
)) {
676 /* enable interrupts */
677 dcr
|= EJTAG_DCR_INTE
;
681 if (dcr
& EJTAG_DCR_INTE
) {
682 /* disable interrupts */
683 dcr
&= ~EJTAG_DCR_INTE
;
689 retval
= target_write_u32(target
, EJTAG_DCR
, dcr
);
690 if (retval
!= ERROR_OK
)
697 /* read processor identification cp0 register */
698 static int mips32_read_c0_prid(struct target
*target
)
700 struct mips32_common
*mips32
= target_to_mips32(target
);
701 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
704 retval
= mips32_cp0_read(ejtag_info
, &mips32
->prid
, 15, 0);
705 if (retval
!= ERROR_OK
) {
706 LOG_ERROR("processor id not available, failed to read cp0 PRId register");
714 * Detect processor type and apply required quirks.
716 * NOTE: The proper detection of certain CPUs can become quite complicated.
717 * Please consult the following Linux kernel code when adding new CPUs:
718 * arch/mips/include/asm/cpu.h
719 * arch/mips/kernel/cpu-probe.c
721 int mips32_cpu_probe(struct target
*target
)
723 struct mips32_common
*mips32
= target_to_mips32(target
);
724 const char *cpu_name
= "unknown";
728 return ERROR_OK
; /* Already probed once, return early. */
730 retval
= mips32_read_c0_prid(target
);
731 if (retval
!= ERROR_OK
)
734 switch (mips32
->prid
& PRID_COMP_MASK
) {
735 case PRID_COMP_INGENIC_E1
:
736 switch (mips32
->prid
& PRID_IMP_MASK
) {
737 case PRID_IMP_XBURST_REV1
:
738 cpu_name
= "Ingenic XBurst rev1";
739 mips32
->cpu_quirks
|= EJTAG_QUIRK_PAD_DRET
;
749 LOG_DEBUG("CPU: %s (PRId %08x)", cpu_name
, mips32
->prid
);
754 /* read config to config3 cp0 registers and log isa implementation */
755 int mips32_read_config_regs(struct target
*target
)
757 struct mips32_common
*mips32
= target_to_mips32(target
);
758 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
760 if (ejtag_info
->config_regs
== 0)
761 for (int i
= 0; i
!= 4; i
++) {
762 int retval
= mips32_cp0_read(ejtag_info
, &ejtag_info
->config
[i
], 16, i
);
763 if (retval
!= ERROR_OK
) {
764 LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32
, i
);
765 ejtag_info
->config_regs
= 0;
768 ejtag_info
->config_regs
= i
+ 1;
769 if ((ejtag_info
->config
[i
] & (1 << 31)) == 0)
770 break; /* no more config registers implemented */
773 return ERROR_OK
; /* already successfully read */
775 LOG_DEBUG("read %"PRIu32
" config registers", ejtag_info
->config_regs
);
777 if (ejtag_info
->impcode
& EJTAG_IMP_MIPS16
) {
778 mips32
->isa_imp
= MIPS32_MIPS16
;
779 LOG_USER("MIPS32 with MIPS16 support implemented");
781 } else if (ejtag_info
->config_regs
>= 4) { /* config3 implemented */
782 unsigned isa_imp
= (ejtag_info
->config
[3] & MIPS32_CONFIG3_ISA_MASK
) >> MIPS32_CONFIG3_ISA_SHIFT
;
784 mips32
->isa_imp
= MMIPS32_ONLY
;
785 LOG_USER("MICRO MIPS32 only implemented");
787 } else if (isa_imp
!= 0) {
788 mips32
->isa_imp
= MIPS32_MMIPS32
;
789 LOG_USER("MIPS32 and MICRO MIPS32 implemented");
793 if (mips32
->isa_imp
== MIPS32_ONLY
) /* initial default value */
794 LOG_USER("MIPS32 only implemented");
798 int mips32_checksum_memory(struct target
*target
, target_addr_t address
,
799 uint32_t count
, uint32_t *checksum
)
801 struct working_area
*crc_algorithm
;
802 struct reg_param reg_params
[2];
803 struct mips32_algorithm mips32_info
;
805 struct mips32_common
*mips32
= target_to_mips32(target
);
806 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
808 /* see contrib/loaders/checksum/mips32.s for src */
809 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
811 uint32_t mips_crc_code
[] = {
812 MIPS32_ADDIU(isa
, 12, 4, 0), /* addiu $t4, $a0, 0 */
813 MIPS32_ADDIU(isa
, 10, 5, 0), /* addiu $t2, $a1, 0 */
814 MIPS32_ADDIU(isa
, 4, 0, 0xFFFF), /* addiu $a0, $zero, 0xffff */
815 MIPS32_BEQ(isa
, 0, 0, 0x10 << isa
), /* beq $zero, $zero, ncomp */
816 MIPS32_ADDIU(isa
, 11, 0, 0), /* addiu $t3, $zero, 0 */
818 MIPS32_LB(isa
, 5, 0, 12), /* lb $a1, ($t4) */
819 MIPS32_ADDI(isa
, 12, 12, 1), /* addi $t4, $t4, 1 */
820 MIPS32_SLL(isa
, 5, 5, 24), /* sll $a1, $a1, 24 */
821 MIPS32_LUI(isa
, 2, 0x04c1), /* lui $v0, 0x04c1 */
822 MIPS32_XOR(isa
, 4, 4, 5), /* xor $a0, $a0, $a1 */
823 MIPS32_ORI(isa
, 7, 2, 0x1db7), /* ori $a3, $v0, 0x1db7 */
824 MIPS32_ADDU(isa
, 6, 0, 0), /* addu $a2, $zero, $zero */
826 MIPS32_SLL(isa
, 8, 4, 1), /* sll $t0, $a0, 1 */
827 MIPS32_ADDIU(isa
, 6, 6, 1), /* addiu $a2, $a2, 1 */
828 MIPS32_SLTI(isa
, 4, 4, 0), /* slti $a0, $a0, 0 */
829 MIPS32_XOR(isa
, 9, 8, 7), /* xor $t1, $t0, $a3 */
830 MIPS32_MOVN(isa
, 8, 9, 4), /* movn $t0, $t1, $a0 */
831 MIPS32_SLTI(isa
, 3, 6, 8), /* slti $v1, $a2, 8 */
832 MIPS32_BNE(isa
, 3, 0, NEG16(7 << isa
)), /* bne $v1, $zero, loop */
833 MIPS32_ADDU(isa
, 4, 8, 0), /* addu $a0, $t0, $zero */
835 MIPS32_BNE(isa
, 10, 11, NEG16(16 << isa
)), /* bne $t2, $t3, nbyte */
836 MIPS32_ADDIU(isa
, 11, 11, 1), /* addiu $t3, $t3, 1 */
840 /* make sure we have a working area */
841 if (target_alloc_working_area(target
, sizeof(mips_crc_code
), &crc_algorithm
) != ERROR_OK
)
842 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
844 pracc_swap16_array(ejtag_info
, mips_crc_code
, ARRAY_SIZE(mips_crc_code
));
846 /* convert mips crc code into a buffer in target endianness */
847 uint8_t mips_crc_code_8
[sizeof(mips_crc_code
)];
848 target_buffer_set_u32_array(target
, mips_crc_code_8
,
849 ARRAY_SIZE(mips_crc_code
), mips_crc_code
);
851 int retval
= target_write_buffer(target
, crc_algorithm
->address
, sizeof(mips_crc_code
), mips_crc_code_8
);
852 if (retval
!= ERROR_OK
)
855 mips32_info
.common_magic
= MIPS32_COMMON_MAGIC
;
856 mips32_info
.isa_mode
= isa
? MIPS32_ISA_MMIPS32
: MIPS32_ISA_MIPS32
; /* run isa as in debug mode */
858 init_reg_param(®_params
[0], "r4", 32, PARAM_IN_OUT
);
859 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
861 init_reg_param(®_params
[1], "r5", 32, PARAM_OUT
);
862 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
864 unsigned int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
866 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
867 crc_algorithm
->address
+ (sizeof(mips_crc_code
) - 4), timeout
, &mips32_info
);
869 if (retval
== ERROR_OK
)
870 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
872 destroy_reg_param(®_params
[0]);
873 destroy_reg_param(®_params
[1]);
875 target_free_working_area(target
, crc_algorithm
);
880 /** Checks whether a memory region is erased. */
881 int mips32_blank_check_memory(struct target
*target
,
882 struct target_memory_check_block
*blocks
, int num_blocks
,
883 uint8_t erased_value
)
885 struct working_area
*erase_check_algorithm
;
886 struct reg_param reg_params
[3];
887 struct mips32_algorithm mips32_info
;
889 struct mips32_common
*mips32
= target_to_mips32(target
);
890 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
892 if (erased_value
!= 0xff) {
893 LOG_ERROR("Erase value 0x%02" PRIx8
" not yet supported for MIPS32",
897 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
898 uint32_t erase_check_code
[] = {
900 MIPS32_LB(isa
, 8, 0, 4), /* lb $t0, ($a0) */
901 MIPS32_AND(isa
, 6, 6, 8), /* and $a2, $a2, $t0 */
902 MIPS32_ADDIU(isa
, 5, 5, NEG16(1)), /* addiu $a1, $a1, -1 */
903 MIPS32_BNE(isa
, 5, 0, NEG16(4 << isa
)), /* bne $a1, $zero, nbyte */
904 MIPS32_ADDIU(isa
, 4, 4, 1), /* addiu $a0, $a0, 1 */
905 MIPS32_SDBBP(isa
) /* sdbbp */
908 /* make sure we have a working area */
909 if (target_alloc_working_area(target
, sizeof(erase_check_code
), &erase_check_algorithm
) != ERROR_OK
)
910 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
912 pracc_swap16_array(ejtag_info
, erase_check_code
, ARRAY_SIZE(erase_check_code
));
914 /* convert erase check code into a buffer in target endianness */
915 uint8_t erase_check_code_8
[sizeof(erase_check_code
)];
916 target_buffer_set_u32_array(target
, erase_check_code_8
,
917 ARRAY_SIZE(erase_check_code
), erase_check_code
);
919 int retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
920 sizeof(erase_check_code
), erase_check_code_8
);
921 if (retval
!= ERROR_OK
)
924 mips32_info
.common_magic
= MIPS32_COMMON_MAGIC
;
925 mips32_info
.isa_mode
= isa
? MIPS32_ISA_MMIPS32
: MIPS32_ISA_MIPS32
;
927 init_reg_param(®_params
[0], "r4", 32, PARAM_OUT
);
928 buf_set_u32(reg_params
[0].value
, 0, 32, blocks
[0].address
);
930 init_reg_param(®_params
[1], "r5", 32, PARAM_OUT
);
931 buf_set_u32(reg_params
[1].value
, 0, 32, blocks
[0].size
);
933 init_reg_param(®_params
[2], "r6", 32, PARAM_IN_OUT
);
934 buf_set_u32(reg_params
[2].value
, 0, 32, erased_value
);
936 retval
= target_run_algorithm(target
, 0, NULL
, 3, reg_params
, erase_check_algorithm
->address
,
937 erase_check_algorithm
->address
+ (sizeof(erase_check_code
) - 4), 10000, &mips32_info
);
939 if (retval
== ERROR_OK
)
940 blocks
[0].result
= buf_get_u32(reg_params
[2].value
, 0, 32);
942 destroy_reg_param(®_params
[0]);
943 destroy_reg_param(®_params
[1]);
944 destroy_reg_param(®_params
[2]);
947 target_free_working_area(target
, erase_check_algorithm
);
949 if (retval
!= ERROR_OK
)
952 return 1; /* only one block has been checked */
955 static int mips32_verify_pointer(struct command_invocation
*cmd
,
956 struct mips32_common
*mips32
)
958 if (mips32
->common_magic
!= MIPS32_COMMON_MAGIC
) {
959 command_print(cmd
, "target is not an MIPS32");
960 return ERROR_TARGET_INVALID
;
966 * MIPS32 targets expose command interface
967 * to manipulate CP0 registers
969 COMMAND_HANDLER(mips32_handle_cp0_command
)
972 struct target
*target
= get_current_target(CMD_CTX
);
973 struct mips32_common
*mips32
= target_to_mips32(target
);
974 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
977 retval
= mips32_verify_pointer(CMD
, mips32
);
978 if (retval
!= ERROR_OK
)
981 if (target
->state
!= TARGET_HALTED
) {
982 command_print(CMD
, "Error: target must be stopped for \"%s\" command", CMD_NAME
);
983 return ERROR_TARGET_NOT_HALTED
;
986 /* two or more argument, access a single register/select (write if third argument is given) */
988 return ERROR_COMMAND_SYNTAX_ERROR
;
990 uint32_t cp0_reg
, cp0_sel
;
991 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], cp0_reg
);
992 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], cp0_sel
);
997 retval
= mips32_cp0_read(ejtag_info
, &value
, cp0_reg
, cp0_sel
);
998 if (retval
!= ERROR_OK
) {
1000 "couldn't access reg %" PRIu32
,
1004 command_print(CMD
, "cp0 reg %" PRIu32
", select %" PRIu32
": %8.8" PRIx32
,
1005 cp0_reg
, cp0_sel
, value
);
1007 } else if (CMD_ARGC
== 3) {
1009 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], value
);
1010 retval
= mips32_cp0_write(ejtag_info
, value
, cp0_reg
, cp0_sel
);
1011 if (retval
!= ERROR_OK
) {
1013 "couldn't access cp0 reg %" PRIu32
", select %" PRIu32
,
1017 command_print(CMD
, "cp0 reg %" PRIu32
", select %" PRIu32
": %8.8" PRIx32
,
1018 cp0_reg
, cp0_sel
, value
);
1025 COMMAND_HANDLER(mips32_handle_scan_delay_command
)
1027 struct target
*target
= get_current_target(CMD_CTX
);
1028 struct mips32_common
*mips32
= target_to_mips32(target
);
1029 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
1032 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], ejtag_info
->scan_delay
);
1033 else if (CMD_ARGC
> 1)
1034 return ERROR_COMMAND_SYNTAX_ERROR
;
1036 command_print(CMD
, "scan delay: %d nsec", ejtag_info
->scan_delay
);
1037 if (ejtag_info
->scan_delay
>= MIPS32_SCAN_DELAY_LEGACY_MODE
) {
1038 ejtag_info
->mode
= 0;
1039 command_print(CMD
, "running in legacy mode");
1041 ejtag_info
->mode
= 1;
1042 command_print(CMD
, "running in fast queued mode");
1048 static const struct command_registration mips32_exec_command_handlers
[] = {
1051 .handler
= mips32_handle_cp0_command
,
1052 .mode
= COMMAND_EXEC
,
1053 .usage
= "regnum select [value]",
1054 .help
= "display/modify cp0 register",
1057 .name
= "scan_delay",
1058 .handler
= mips32_handle_scan_delay_command
,
1059 .mode
= COMMAND_ANY
,
1060 .help
= "display/set scan delay in nano seconds",
1063 COMMAND_REGISTRATION_DONE
1066 const struct command_registration mips32_command_handlers
[] = {
1069 .mode
= COMMAND_ANY
,
1070 .help
= "mips32 command group",
1072 .chain
= mips32_exec_command_handlers
,
1074 COMMAND_REGISTRATION_DONE
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)