837ccc94e75890ecd94bbcd7ef7d8e099560242f
[openocd.git] / src / target / armv7m.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2006 by Magnus Lundin *
6 * lundin@mlu.mine.nu *
7 * *
8 * Copyright (C) 2008 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
10 * *
11 * Copyright (C) 2007,2008 Øyvind Harboe *
12 * oyvind.harboe@zylin.com *
13 * *
14 * Copyright (C) 2018 by Liviu Ionescu *
15 * <ilg@livius.net> *
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 * This program is distributed in the hope that it will be useful, *
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
25 * GNU General Public License for more details. *
26 * *
27 * You should have received a copy of the GNU General Public License *
28 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
29 * *
30 * ARMv7-M Architecture, Application Level Reference Manual *
31 * ARM DDI 0405C (September 2008) *
32 * *
33 ***************************************************************************/
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "breakpoints.h"
40 #include "armv7m.h"
41 #include "algorithm.h"
42 #include "register.h"
43 #include "semihosting_common.h"
44
45 #if 0
46 #define _DEBUG_INSTRUCTION_EXECUTION_
47 #endif
48
49 static const char * const armv7m_exception_strings[] = {
50 "", "Reset", "NMI", "HardFault",
51 "MemManage", "BusFault", "UsageFault", "RESERVED",
52 "RESERVED", "RESERVED", "RESERVED", "SVCall",
53 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
54 };
55
56 /* PSP is used in some thread modes */
57 const int armv7m_psp_reg_map[ARMV7M_NUM_CORE_REGS] = {
58 ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
59 ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
60 ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
61 ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC,
62 ARMV7M_xPSR,
63 };
64
65 /* MSP is used in handler and some thread modes */
66 const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = {
67 ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
68 ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
69 ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
70 ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC,
71 ARMV7M_xPSR,
72 };
73
74 /*
75 * These registers are not memory-mapped. The ARMv7-M profile includes
76 * memory mapped registers too, such as for the NVIC (interrupt controller)
77 * and SysTick (timer) modules; those can mostly be treated as peripherals.
78 *
79 * The ARMv6-M profile is almost identical in this respect, except that it
80 * doesn't include basepri or faultmask registers.
81 */
82 static const struct {
83 unsigned id;
84 const char *name;
85 unsigned bits;
86 enum reg_type type;
87 const char *group;
88 const char *feature;
89 } armv7m_regs[] = {
90 { ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
91 { ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
92 { ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
93 { ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
101 { ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
103 { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" },
104 { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
105 { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" },
106 { ARMV7M_xPSR, "xPSR", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
107
108 { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
109 { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
110
111 { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
112 { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
113 { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
114 { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
115
116 { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
117 { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
118 { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
119 { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
120 { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
121 { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
122 { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
123 { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
124 { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
125 { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
126 { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
127 { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
128 { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
129 { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
130 { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
131 { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
132
133 { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" },
134 };
135
136 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
137
138 /**
139 * Restores target context using the cache of core registers set up
140 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
141 */
142 int armv7m_restore_context(struct target *target)
143 {
144 int i;
145 struct armv7m_common *armv7m = target_to_armv7m(target);
146 struct reg_cache *cache = armv7m->arm.core_cache;
147
148 LOG_DEBUG(" ");
149
150 if (armv7m->pre_restore_context)
151 armv7m->pre_restore_context(target);
152
153 for (i = cache->num_regs - 1; i >= 0; i--) {
154 if (cache->reg_list[i].dirty) {
155 armv7m->arm.write_core_reg(target, &cache->reg_list[i], i,
156 ARM_MODE_ANY, cache->reg_list[i].value);
157 }
158 }
159
160 return ERROR_OK;
161 }
162
163 /* Core state functions */
164
165 /**
166 * Maps ISR number (from xPSR) to name.
167 * Note that while names and meanings for the first sixteen are standardized
168 * (with zero not a true exception), external interrupts are only numbered.
169 * They are assigned by vendors, which generally assign different numbers to
170 * peripherals (such as UART0 or a USB peripheral controller).
171 */
172 const char *armv7m_exception_string(int number)
173 {
174 static char enamebuf[32];
175
176 if ((number < 0) | (number > 511))
177 return "Invalid exception";
178 if (number < 16)
179 return armv7m_exception_strings[number];
180 sprintf(enamebuf, "External Interrupt(%i)", number - 16);
181 return enamebuf;
182 }
183
184 static int armv7m_get_core_reg(struct reg *reg)
185 {
186 int retval;
187 struct arm_reg *armv7m_reg = reg->arch_info;
188 struct target *target = armv7m_reg->target;
189 struct arm *arm = target_to_arm(target);
190
191 if (target->state != TARGET_HALTED)
192 return ERROR_TARGET_NOT_HALTED;
193
194 retval = arm->read_core_reg(target, reg, reg->number, arm->core_mode);
195
196 return retval;
197 }
198
199 static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
200 {
201 struct arm_reg *armv7m_reg = reg->arch_info;
202 struct target *target = armv7m_reg->target;
203
204 if (target->state != TARGET_HALTED)
205 return ERROR_TARGET_NOT_HALTED;
206
207 buf_cpy(buf, reg->value, reg->size);
208 reg->dirty = true;
209 reg->valid = true;
210
211 return ERROR_OK;
212 }
213
214 static int armv7m_read_core_reg(struct target *target, struct reg *r,
215 int num, enum arm_mode mode)
216 {
217 uint32_t reg_value;
218 int retval;
219 struct arm_reg *armv7m_core_reg;
220 struct armv7m_common *armv7m = target_to_armv7m(target);
221
222 assert(num < (int)armv7m->arm.core_cache->num_regs);
223
224 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
225
226 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
227 /* map D0..D15 to S0..S31 */
228 size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
229 retval = armv7m->load_core_reg_u32(target, regidx, &reg_value);
230 if (retval != ERROR_OK)
231 return retval;
232 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value,
233 0, 32, reg_value);
234 retval = armv7m->load_core_reg_u32(target, regidx + 1, &reg_value);
235 if (retval != ERROR_OK)
236 return retval;
237 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4,
238 0, 32, reg_value);
239 } else {
240 retval = armv7m->load_core_reg_u32(target,
241 armv7m_core_reg->num, &reg_value);
242 if (retval != ERROR_OK)
243 return retval;
244 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
245 }
246
247 armv7m->arm.core_cache->reg_list[num].valid = true;
248 armv7m->arm.core_cache->reg_list[num].dirty = false;
249
250 return retval;
251 }
252
253 static int armv7m_write_core_reg(struct target *target, struct reg *r,
254 int num, enum arm_mode mode, uint8_t *value)
255 {
256 int retval;
257 struct arm_reg *armv7m_core_reg;
258 struct armv7m_common *armv7m = target_to_armv7m(target);
259
260 assert(num < (int)armv7m->arm.core_cache->num_regs);
261
262 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
263
264 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
265 /* map D0..D15 to S0..S31 */
266 size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
267
268 uint32_t t = buf_get_u32(value, 0, 32);
269 retval = armv7m->store_core_reg_u32(target, regidx, t);
270 if (retval != ERROR_OK)
271 goto out_error;
272
273 t = buf_get_u32(value + 4, 0, 32);
274 retval = armv7m->store_core_reg_u32(target, regidx + 1, t);
275 if (retval != ERROR_OK)
276 goto out_error;
277 } else {
278 uint32_t t = buf_get_u32(value, 0, 32);
279
280 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t);
281 retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t);
282 if (retval != ERROR_OK)
283 goto out_error;
284 }
285
286 armv7m->arm.core_cache->reg_list[num].valid = true;
287 armv7m->arm.core_cache->reg_list[num].dirty = false;
288
289 return ERROR_OK;
290
291 out_error:
292 LOG_ERROR("Error setting register");
293 armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
294 return ERROR_JTAG_DEVICE_ERROR;
295 }
296
297 /**
298 * Returns generic ARM userspace registers to GDB.
299 */
300 int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
301 int *reg_list_size, enum target_register_class reg_class)
302 {
303 struct armv7m_common *armv7m = target_to_armv7m(target);
304 int i;
305
306 if (reg_class == REG_CLASS_ALL)
307 *reg_list_size = armv7m->arm.core_cache->num_regs;
308 else
309 *reg_list_size = ARMV7M_NUM_CORE_REGS;
310
311 *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
312 if (*reg_list == NULL)
313 return ERROR_FAIL;
314
315 for (i = 0; i < *reg_list_size; i++)
316 (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
317
318 return ERROR_OK;
319 }
320
321 /** Runs a Thumb algorithm in the target. */
322 int armv7m_run_algorithm(struct target *target,
323 int num_mem_params, struct mem_param *mem_params,
324 int num_reg_params, struct reg_param *reg_params,
325 target_addr_t entry_point, target_addr_t exit_point,
326 int timeout_ms, void *arch_info)
327 {
328 int retval;
329
330 retval = armv7m_start_algorithm(target,
331 num_mem_params, mem_params,
332 num_reg_params, reg_params,
333 entry_point, exit_point,
334 arch_info);
335
336 if (retval == ERROR_OK)
337 retval = armv7m_wait_algorithm(target,
338 num_mem_params, mem_params,
339 num_reg_params, reg_params,
340 exit_point, timeout_ms,
341 arch_info);
342
343 return retval;
344 }
345
346 /** Starts a Thumb algorithm in the target. */
347 int armv7m_start_algorithm(struct target *target,
348 int num_mem_params, struct mem_param *mem_params,
349 int num_reg_params, struct reg_param *reg_params,
350 target_addr_t entry_point, target_addr_t exit_point,
351 void *arch_info)
352 {
353 struct armv7m_common *armv7m = target_to_armv7m(target);
354 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
355 enum arm_mode core_mode = armv7m->arm.core_mode;
356 int retval = ERROR_OK;
357
358 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
359 * at the exit point */
360
361 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
362 LOG_ERROR("current target isn't an ARMV7M target");
363 return ERROR_TARGET_INVALID;
364 }
365
366 if (target->state != TARGET_HALTED) {
367 LOG_WARNING("target not halted");
368 return ERROR_TARGET_NOT_HALTED;
369 }
370
371 /* refresh core register cache
372 * Not needed if core register cache is always consistent with target process state */
373 for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
374
375 armv7m_algorithm_info->context[i] = buf_get_u32(
376 armv7m->arm.core_cache->reg_list[i].value,
377 0,
378 32);
379 }
380
381 for (int i = 0; i < num_mem_params; i++) {
382 if (mem_params[i].direction == PARAM_IN)
383 continue;
384 retval = target_write_buffer(target, mem_params[i].address,
385 mem_params[i].size,
386 mem_params[i].value);
387 if (retval != ERROR_OK)
388 return retval;
389 }
390
391 for (int i = 0; i < num_reg_params; i++) {
392 if (reg_params[i].direction == PARAM_IN)
393 continue;
394
395 struct reg *reg =
396 register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
397 /* uint32_t regvalue; */
398
399 if (!reg) {
400 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
401 return ERROR_COMMAND_SYNTAX_ERROR;
402 }
403
404 if (reg->size != reg_params[i].size) {
405 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
406 reg_params[i].reg_name);
407 return ERROR_COMMAND_SYNTAX_ERROR;
408 }
409
410 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
411 armv7m_set_core_reg(reg, reg_params[i].value);
412 }
413
414 {
415 /*
416 * Ensure xPSR.T is set to avoid trying to run things in arm
417 * (non-thumb) mode, which armv7m does not support.
418 *
419 * We do this by setting the entirety of xPSR, which should
420 * remove all the unknowns about xPSR state.
421 *
422 * Because xPSR.T is populated on reset from the vector table,
423 * it might be 0 if the vector table has "bad" data in it.
424 */
425 struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
426 buf_set_u32(reg->value, 0, 32, 0x01000000);
427 reg->valid = true;
428 reg->dirty = true;
429 }
430
431 if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
432 armv7m_algorithm_info->core_mode != core_mode) {
433
434 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
435 if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
436 armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
437 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
438 }
439
440 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
441 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
442 0, 1, armv7m_algorithm_info->core_mode);
443 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
444 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
445 }
446
447 /* save previous core mode */
448 armv7m_algorithm_info->core_mode = core_mode;
449
450 retval = target_resume(target, 0, entry_point, 1, 1);
451
452 return retval;
453 }
454
455 /** Waits for an algorithm in the target. */
456 int armv7m_wait_algorithm(struct target *target,
457 int num_mem_params, struct mem_param *mem_params,
458 int num_reg_params, struct reg_param *reg_params,
459 target_addr_t exit_point, int timeout_ms,
460 void *arch_info)
461 {
462 struct armv7m_common *armv7m = target_to_armv7m(target);
463 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
464 int retval = ERROR_OK;
465
466 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
467 * at the exit point */
468
469 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
470 LOG_ERROR("current target isn't an ARMV7M target");
471 return ERROR_TARGET_INVALID;
472 }
473
474 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
475 /* If the target fails to halt due to the breakpoint, force a halt */
476 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
477 retval = target_halt(target);
478 if (retval != ERROR_OK)
479 return retval;
480 retval = target_wait_state(target, TARGET_HALTED, 500);
481 if (retval != ERROR_OK)
482 return retval;
483 return ERROR_TARGET_TIMEOUT;
484 }
485
486 if (exit_point) {
487 /* PC value has been cached in cortex_m_debug_entry() */
488 uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32);
489 if (pc != exit_point) {
490 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR,
491 pc, exit_point);
492 return ERROR_TARGET_ALGO_EXIT;
493 }
494 }
495
496 /* Read memory values to mem_params[] */
497 for (int i = 0; i < num_mem_params; i++) {
498 if (mem_params[i].direction != PARAM_OUT) {
499 retval = target_read_buffer(target, mem_params[i].address,
500 mem_params[i].size,
501 mem_params[i].value);
502 if (retval != ERROR_OK)
503 return retval;
504 }
505 }
506
507 /* Copy core register values to reg_params[] */
508 for (int i = 0; i < num_reg_params; i++) {
509 if (reg_params[i].direction != PARAM_OUT) {
510 struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
511 reg_params[i].reg_name,
512 0);
513
514 if (!reg) {
515 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
516 return ERROR_COMMAND_SYNTAX_ERROR;
517 }
518
519 if (reg->size != reg_params[i].size) {
520 LOG_ERROR(
521 "BUG: register '%s' size doesn't match reg_params[i].size",
522 reg_params[i].reg_name);
523 return ERROR_COMMAND_SYNTAX_ERROR;
524 }
525
526 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
527 }
528 }
529
530 for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
531 uint32_t regvalue;
532 regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
533 if (regvalue != armv7m_algorithm_info->context[i]) {
534 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
535 armv7m->arm.core_cache->reg_list[i].name,
536 armv7m_algorithm_info->context[i]);
537 buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
538 0, 32, armv7m_algorithm_info->context[i]);
539 armv7m->arm.core_cache->reg_list[i].valid = true;
540 armv7m->arm.core_cache->reg_list[i].dirty = true;
541 }
542 }
543
544 /* restore previous core mode */
545 if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
546 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
547 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
548 0, 1, armv7m_algorithm_info->core_mode);
549 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
550 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
551 }
552
553 armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
554
555 return retval;
556 }
557
558 /** Logs summary of ARMv7-M state for a halted target. */
559 int armv7m_arch_state(struct target *target)
560 {
561 struct armv7m_common *armv7m = target_to_armv7m(target);
562 struct arm *arm = &armv7m->arm;
563 uint32_t ctrl, sp;
564
565 /* avoid filling log waiting for fileio reply */
566 if (target->semihosting && target->semihosting->hit_fileio)
567 return ERROR_OK;
568
569 ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
570 sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
571
572 LOG_USER("target halted due to %s, current mode: %s %s\n"
573 "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
574 debug_reason_name(target),
575 arm_mode_name(arm->core_mode),
576 armv7m_exception_string(armv7m->exception_number),
577 buf_get_u32(arm->cpsr->value, 0, 32),
578 buf_get_u32(arm->pc->value, 0, 32),
579 (ctrl & 0x02) ? 'p' : 'm',
580 sp,
581 (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
582 (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
583
584 return ERROR_OK;
585 }
586
587 static const struct reg_arch_type armv7m_reg_type = {
588 .get = armv7m_get_core_reg,
589 .set = armv7m_set_core_reg,
590 };
591
592 /** Builds cache of architecturally defined registers. */
593 struct reg_cache *armv7m_build_reg_cache(struct target *target)
594 {
595 struct armv7m_common *armv7m = target_to_armv7m(target);
596 struct arm *arm = &armv7m->arm;
597 int num_regs = ARMV7M_NUM_REGS;
598 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
599 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
600 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
601 struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
602 struct reg_feature *feature;
603 int i;
604
605 /* Build the process context cache */
606 cache->name = "arm v7m registers";
607 cache->next = NULL;
608 cache->reg_list = reg_list;
609 cache->num_regs = num_regs;
610 (*cache_p) = cache;
611
612 for (i = 0; i < num_regs; i++) {
613 arch_info[i].num = armv7m_regs[i].id;
614 arch_info[i].target = target;
615 arch_info[i].arm = arm;
616
617 reg_list[i].name = armv7m_regs[i].name;
618 reg_list[i].size = armv7m_regs[i].bits;
619 size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8);
620 if (storage_size < 4)
621 storage_size = 4;
622 reg_list[i].value = calloc(1, storage_size);
623 reg_list[i].dirty = false;
624 reg_list[i].valid = false;
625 reg_list[i].type = &armv7m_reg_type;
626 reg_list[i].arch_info = &arch_info[i];
627
628 reg_list[i].group = armv7m_regs[i].group;
629 reg_list[i].number = i;
630 reg_list[i].exist = true;
631 reg_list[i].caller_save = true; /* gdb defaults to true */
632
633 feature = calloc(1, sizeof(struct reg_feature));
634 if (feature) {
635 feature->name = armv7m_regs[i].feature;
636 reg_list[i].feature = feature;
637 } else
638 LOG_ERROR("unable to allocate feature list");
639
640 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
641 if (reg_list[i].reg_data_type)
642 reg_list[i].reg_data_type->type = armv7m_regs[i].type;
643 else
644 LOG_ERROR("unable to allocate reg type list");
645 }
646
647 arm->cpsr = reg_list + ARMV7M_xPSR;
648 arm->pc = reg_list + ARMV7M_PC;
649 arm->core_cache = cache;
650
651 return cache;
652 }
653
654 void armv7m_free_reg_cache(struct target *target)
655 {
656 struct armv7m_common *armv7m = target_to_armv7m(target);
657 struct arm *arm = &armv7m->arm;
658 struct reg_cache *cache;
659 struct reg *reg;
660 unsigned int i;
661
662 cache = arm->core_cache;
663
664 if (!cache)
665 return;
666
667 for (i = 0; i < cache->num_regs; i++) {
668 reg = &cache->reg_list[i];
669
670 free(reg->feature);
671 free(reg->reg_data_type);
672 free(reg->value);
673 }
674
675 free(cache->reg_list[0].arch_info);
676 free(cache->reg_list);
677 free(cache);
678
679 arm->core_cache = NULL;
680 }
681
682 static int armv7m_setup_semihosting(struct target *target, int enable)
683 {
684 /* nothing todo for armv7m */
685 return ERROR_OK;
686 }
687
688 /** Sets up target as a generic ARMv7-M core */
689 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
690 {
691 struct arm *arm = &armv7m->arm;
692
693 armv7m->common_magic = ARMV7M_COMMON_MAGIC;
694 armv7m->fp_feature = FP_NONE;
695 armv7m->trace_config.trace_bus_id = 1;
696 /* Enable stimulus port #0 by default */
697 armv7m->trace_config.itm_ter[0] = 1;
698
699 arm->core_type = ARM_CORE_TYPE_M_PROFILE;
700 arm->arch_info = armv7m;
701 arm->setup_semihosting = armv7m_setup_semihosting;
702
703 arm->read_core_reg = armv7m_read_core_reg;
704 arm->write_core_reg = armv7m_write_core_reg;
705
706 return arm_init_arch_info(target, arm);
707 }
708
709 /** Generates a CRC32 checksum of a memory region. */
710 int armv7m_checksum_memory(struct target *target,
711 target_addr_t address, uint32_t count, uint32_t *checksum)
712 {
713 struct working_area *crc_algorithm;
714 struct armv7m_algorithm armv7m_info;
715 struct reg_param reg_params[2];
716 int retval;
717
718 static const uint8_t cortex_m_crc_code[] = {
719 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
720 };
721
722 retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
723 if (retval != ERROR_OK)
724 return retval;
725
726 retval = target_write_buffer(target, crc_algorithm->address,
727 sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code);
728 if (retval != ERROR_OK)
729 goto cleanup;
730
731 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
732 armv7m_info.core_mode = ARM_MODE_THREAD;
733
734 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
735 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
736
737 buf_set_u32(reg_params[0].value, 0, 32, address);
738 buf_set_u32(reg_params[1].value, 0, 32, count);
739
740 int timeout = 20000 * (1 + (count / (1024 * 1024)));
741
742 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
743 crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
744 timeout, &armv7m_info);
745
746 if (retval == ERROR_OK)
747 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
748 else
749 LOG_ERROR("error executing cortex_m crc algorithm");
750
751 destroy_reg_param(&reg_params[0]);
752 destroy_reg_param(&reg_params[1]);
753
754 cleanup:
755 target_free_working_area(target, crc_algorithm);
756
757 return retval;
758 }
759
760 /** Checks an array of memory regions whether they are erased. */
761 int armv7m_blank_check_memory(struct target *target,
762 struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
763 {
764 struct working_area *erase_check_algorithm;
765 struct working_area *erase_check_params;
766 struct reg_param reg_params[2];
767 struct armv7m_algorithm armv7m_info;
768 int retval;
769
770 static bool timed_out;
771
772 static const uint8_t erase_check_code[] = {
773 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
774 };
775
776 const uint32_t code_size = sizeof(erase_check_code);
777
778 /* make sure we have a working area */
779 if (target_alloc_working_area(target, code_size,
780 &erase_check_algorithm) != ERROR_OK)
781 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
782
783 retval = target_write_buffer(target, erase_check_algorithm->address,
784 code_size, erase_check_code);
785 if (retval != ERROR_OK)
786 goto cleanup1;
787
788 /* prepare blocks array for algo */
789 struct algo_block {
790 union {
791 uint32_t size;
792 uint32_t result;
793 };
794 uint32_t address;
795 };
796
797 uint32_t avail = target_get_working_area_avail(target);
798 int blocks_to_check = avail / sizeof(struct algo_block) - 1;
799 if (num_blocks < blocks_to_check)
800 blocks_to_check = num_blocks;
801
802 struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block));
803 if (params == NULL) {
804 retval = ERROR_FAIL;
805 goto cleanup1;
806 }
807
808 int i;
809 uint32_t total_size = 0;
810 for (i = 0; i < blocks_to_check; i++) {
811 total_size += blocks[i].size;
812 target_buffer_set_u32(target, (uint8_t *)&(params[i].size),
813 blocks[i].size / sizeof(uint32_t));
814 target_buffer_set_u32(target, (uint8_t *)&(params[i].address),
815 blocks[i].address);
816 }
817 target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0);
818
819 uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block);
820 if (target_alloc_working_area(target, param_size,
821 &erase_check_params) != ERROR_OK) {
822 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
823 goto cleanup2;
824 }
825
826 retval = target_write_buffer(target, erase_check_params->address,
827 param_size, (uint8_t *)params);
828 if (retval != ERROR_OK)
829 goto cleanup3;
830
831 uint32_t erased_word = erased_value | (erased_value << 8)
832 | (erased_value << 16) | (erased_value << 24);
833
834 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
835 TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address);
836
837 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
838 armv7m_info.core_mode = ARM_MODE_THREAD;
839
840 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
841 buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address);
842
843 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
844 buf_set_u32(reg_params[1].value, 0, 32, erased_word);
845
846 /* assume CPU clk at least 1 MHz */
847 int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
848
849 retval = target_run_algorithm(target,
850 0, NULL,
851 ARRAY_SIZE(reg_params), reg_params,
852 erase_check_algorithm->address,
853 erase_check_algorithm->address + (code_size - 2),
854 timeout,
855 &armv7m_info);
856
857 timed_out = retval == ERROR_TARGET_TIMEOUT;
858 if (retval != ERROR_OK && !timed_out)
859 goto cleanup4;
860
861 retval = target_read_buffer(target, erase_check_params->address,
862 param_size, (uint8_t *)params);
863 if (retval != ERROR_OK)
864 goto cleanup4;
865
866 for (i = 0; i < blocks_to_check; i++) {
867 uint32_t result = target_buffer_get_u32(target,
868 (uint8_t *)&(params[i].result));
869 if (result != 0 && result != 1)
870 break;
871
872 blocks[i].result = result;
873 }
874 if (i && timed_out)
875 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i);
876
877 retval = i; /* return number of blocks really checked */
878
879 cleanup4:
880 destroy_reg_param(&reg_params[0]);
881 destroy_reg_param(&reg_params[1]);
882
883 cleanup3:
884 target_free_working_area(target, erase_check_params);
885 cleanup2:
886 free(params);
887 cleanup1:
888 target_free_working_area(target, erase_check_algorithm);
889
890 return retval;
891 }
892
893 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
894 {
895 struct armv7m_common *armv7m = target_to_armv7m(target);
896 struct reg *r = armv7m->arm.pc;
897 bool result = false;
898
899
900 /* if we halted last time due to a bkpt instruction
901 * then we have to manually step over it, otherwise
902 * the core will break again */
903
904 if (target->debug_reason == DBG_REASON_BREAKPOINT) {
905 uint16_t op;
906 uint32_t pc = buf_get_u32(r->value, 0, 32);
907
908 pc &= ~1;
909 if (target_read_u16(target, pc, &op) == ERROR_OK) {
910 if ((op & 0xFF00) == 0xBE00) {
911 pc = buf_get_u32(r->value, 0, 32) + 2;
912 buf_set_u32(r->value, 0, 32, pc);
913 r->dirty = true;
914 r->valid = true;
915 result = true;
916 LOG_DEBUG("Skipping over BKPT instruction");
917 }
918 }
919 }
920
921 if (inst_found)
922 *inst_found = result;
923
924 return ERROR_OK;
925 }
926
927 const struct command_registration armv7m_command_handlers[] = {
928 {
929 .chain = arm_command_handlers,
930 },
931 COMMAND_REGISTRATION_DONE
932 };

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)