target/armv7m: rework Cortex-M register handling part 1
[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", "SecureFault",
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", 3, 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 uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
215 {
216 switch (arm_reg_id) {
217 case ARMV7M_R0 ... ARMV7M_R14:
218 case ARMV7M_PC:
219 case ARMV7M_xPSR:
220 case ARMV7M_MSP:
221 case ARMV7M_PSP:
222 /* NOTE: we "know" here that the register identifiers
223 * match the Cortex-M DCRSR.REGSEL selectors values
224 * for R0..R14, PC, xPSR, MSP, and PSP.
225 */
226 return arm_reg_id;
227
228 case ARMV7M_FPSCR:
229 return ARMV7M_REGSEL_FPSCR;
230
231 case ARMV7M_D0 ... ARMV7M_D15:
232 return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0);
233
234 /* TODO: remove. This is temporary hack until packing/unpacking
235 * of special regs is moved to armv7m.c */
236 case ARMV7M_PRIMASK:
237 case ARMV7M_BASEPRI:
238 case ARMV7M_FAULTMASK:
239 case ARMV7M_CONTROL:
240 return arm_reg_id;
241
242 default:
243 LOG_ERROR("Bad register ID %u", arm_reg_id);
244 return arm_reg_id;
245 }
246 }
247
248 static int armv7m_read_core_reg(struct target *target, struct reg *r,
249 int num, enum arm_mode mode)
250 {
251 uint32_t reg_value;
252 int retval;
253 struct arm_reg *armv7m_core_reg;
254 struct armv7m_common *armv7m = target_to_armv7m(target);
255
256 assert(num < (int)armv7m->arm.core_cache->num_regs);
257
258 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
259
260 uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num);
261
262 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
263 /* map D0..D15 to S0..S31 */
264 retval = armv7m->load_core_reg_u32(target, regsel, &reg_value);
265 if (retval != ERROR_OK)
266 return retval;
267 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value,
268 0, 32, reg_value);
269 retval = armv7m->load_core_reg_u32(target, regsel + 1, &reg_value);
270 if (retval != ERROR_OK)
271 return retval;
272 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4,
273 0, 32, reg_value);
274 } else {
275 retval = armv7m->load_core_reg_u32(target,
276 regsel, &reg_value);
277 if (retval != ERROR_OK)
278 return retval;
279 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
280 }
281
282 armv7m->arm.core_cache->reg_list[num].valid = true;
283 armv7m->arm.core_cache->reg_list[num].dirty = false;
284
285 return retval;
286 }
287
288 static int armv7m_write_core_reg(struct target *target, struct reg *r,
289 int num, enum arm_mode mode, uint8_t *value)
290 {
291 int retval;
292 struct arm_reg *armv7m_core_reg;
293 struct armv7m_common *armv7m = target_to_armv7m(target);
294
295 assert(num < (int)armv7m->arm.core_cache->num_regs);
296
297 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
298
299 uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num);
300
301 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
302 /* map D0..D15 to S0..S31 */
303 uint32_t t = buf_get_u32(value, 0, 32);
304 retval = armv7m->store_core_reg_u32(target, regsel, t);
305 if (retval != ERROR_OK)
306 goto out_error;
307
308 t = buf_get_u32(value + 4, 0, 32);
309 retval = armv7m->store_core_reg_u32(target, regsel + 1, t);
310 if (retval != ERROR_OK)
311 goto out_error;
312 } else {
313 uint32_t t = buf_get_u32(value, 0, 32);
314
315 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t);
316 retval = armv7m->store_core_reg_u32(target, regsel, t);
317 if (retval != ERROR_OK)
318 goto out_error;
319 }
320
321 armv7m->arm.core_cache->reg_list[num].valid = true;
322 armv7m->arm.core_cache->reg_list[num].dirty = false;
323
324 return ERROR_OK;
325
326 out_error:
327 LOG_ERROR("Error setting register");
328 armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
329 return ERROR_JTAG_DEVICE_ERROR;
330 }
331
332 /**
333 * Returns generic ARM userspace registers to GDB.
334 */
335 int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
336 int *reg_list_size, enum target_register_class reg_class)
337 {
338 struct armv7m_common *armv7m = target_to_armv7m(target);
339 int i, size;
340
341 if (reg_class == REG_CLASS_ALL)
342 size = armv7m->arm.core_cache->num_regs;
343 else
344 size = ARMV7M_NUM_CORE_REGS;
345
346 *reg_list = malloc(sizeof(struct reg *) * size);
347 if (*reg_list == NULL)
348 return ERROR_FAIL;
349
350 for (i = 0; i < size; i++)
351 (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
352
353 *reg_list_size = size;
354
355 return ERROR_OK;
356 }
357
358 /** Runs a Thumb algorithm in the target. */
359 int armv7m_run_algorithm(struct target *target,
360 int num_mem_params, struct mem_param *mem_params,
361 int num_reg_params, struct reg_param *reg_params,
362 target_addr_t entry_point, target_addr_t exit_point,
363 int timeout_ms, void *arch_info)
364 {
365 int retval;
366
367 retval = armv7m_start_algorithm(target,
368 num_mem_params, mem_params,
369 num_reg_params, reg_params,
370 entry_point, exit_point,
371 arch_info);
372
373 if (retval == ERROR_OK)
374 retval = armv7m_wait_algorithm(target,
375 num_mem_params, mem_params,
376 num_reg_params, reg_params,
377 exit_point, timeout_ms,
378 arch_info);
379
380 return retval;
381 }
382
383 /** Starts a Thumb algorithm in the target. */
384 int armv7m_start_algorithm(struct target *target,
385 int num_mem_params, struct mem_param *mem_params,
386 int num_reg_params, struct reg_param *reg_params,
387 target_addr_t entry_point, target_addr_t exit_point,
388 void *arch_info)
389 {
390 struct armv7m_common *armv7m = target_to_armv7m(target);
391 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
392 enum arm_mode core_mode = armv7m->arm.core_mode;
393 int retval = ERROR_OK;
394
395 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
396 * at the exit point */
397
398 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
399 LOG_ERROR("current target isn't an ARMV7M target");
400 return ERROR_TARGET_INVALID;
401 }
402
403 if (target->state != TARGET_HALTED) {
404 LOG_WARNING("target not halted");
405 return ERROR_TARGET_NOT_HALTED;
406 }
407
408 /* refresh core register cache
409 * Not needed if core register cache is always consistent with target process state */
410 for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
411
412 armv7m_algorithm_info->context[i] = buf_get_u32(
413 armv7m->arm.core_cache->reg_list[i].value,
414 0,
415 32);
416 }
417
418 for (int i = 0; i < num_mem_params; i++) {
419 if (mem_params[i].direction == PARAM_IN)
420 continue;
421 retval = target_write_buffer(target, mem_params[i].address,
422 mem_params[i].size,
423 mem_params[i].value);
424 if (retval != ERROR_OK)
425 return retval;
426 }
427
428 for (int i = 0; i < num_reg_params; i++) {
429 if (reg_params[i].direction == PARAM_IN)
430 continue;
431
432 struct reg *reg =
433 register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
434 /* uint32_t regvalue; */
435
436 if (!reg) {
437 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
438 return ERROR_COMMAND_SYNTAX_ERROR;
439 }
440
441 if (reg->size != reg_params[i].size) {
442 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
443 reg_params[i].reg_name);
444 return ERROR_COMMAND_SYNTAX_ERROR;
445 }
446
447 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
448 armv7m_set_core_reg(reg, reg_params[i].value);
449 }
450
451 {
452 /*
453 * Ensure xPSR.T is set to avoid trying to run things in arm
454 * (non-thumb) mode, which armv7m does not support.
455 *
456 * We do this by setting the entirety of xPSR, which should
457 * remove all the unknowns about xPSR state.
458 *
459 * Because xPSR.T is populated on reset from the vector table,
460 * it might be 0 if the vector table has "bad" data in it.
461 */
462 struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
463 buf_set_u32(reg->value, 0, 32, 0x01000000);
464 reg->valid = true;
465 reg->dirty = true;
466 }
467
468 if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
469 armv7m_algorithm_info->core_mode != core_mode) {
470
471 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
472 if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
473 armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
474 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
475 }
476
477 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
478 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
479 0, 1, armv7m_algorithm_info->core_mode);
480 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
481 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
482 }
483
484 /* save previous core mode */
485 armv7m_algorithm_info->core_mode = core_mode;
486
487 retval = target_resume(target, 0, entry_point, 1, 1);
488
489 return retval;
490 }
491
492 /** Waits for an algorithm in the target. */
493 int armv7m_wait_algorithm(struct target *target,
494 int num_mem_params, struct mem_param *mem_params,
495 int num_reg_params, struct reg_param *reg_params,
496 target_addr_t exit_point, int timeout_ms,
497 void *arch_info)
498 {
499 struct armv7m_common *armv7m = target_to_armv7m(target);
500 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
501 int retval = ERROR_OK;
502
503 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
504 * at the exit point */
505
506 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
507 LOG_ERROR("current target isn't an ARMV7M target");
508 return ERROR_TARGET_INVALID;
509 }
510
511 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
512 /* If the target fails to halt due to the breakpoint, force a halt */
513 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
514 retval = target_halt(target);
515 if (retval != ERROR_OK)
516 return retval;
517 retval = target_wait_state(target, TARGET_HALTED, 500);
518 if (retval != ERROR_OK)
519 return retval;
520 return ERROR_TARGET_TIMEOUT;
521 }
522
523 if (exit_point) {
524 /* PC value has been cached in cortex_m_debug_entry() */
525 uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32);
526 if (pc != exit_point) {
527 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR,
528 pc, exit_point);
529 return ERROR_TARGET_ALGO_EXIT;
530 }
531 }
532
533 /* Read memory values to mem_params[] */
534 for (int i = 0; i < num_mem_params; i++) {
535 if (mem_params[i].direction != PARAM_OUT) {
536 retval = target_read_buffer(target, mem_params[i].address,
537 mem_params[i].size,
538 mem_params[i].value);
539 if (retval != ERROR_OK)
540 return retval;
541 }
542 }
543
544 /* Copy core register values to reg_params[] */
545 for (int i = 0; i < num_reg_params; i++) {
546 if (reg_params[i].direction != PARAM_OUT) {
547 struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
548 reg_params[i].reg_name,
549 0);
550
551 if (!reg) {
552 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
553 return ERROR_COMMAND_SYNTAX_ERROR;
554 }
555
556 if (reg->size != reg_params[i].size) {
557 LOG_ERROR(
558 "BUG: register '%s' size doesn't match reg_params[i].size",
559 reg_params[i].reg_name);
560 return ERROR_COMMAND_SYNTAX_ERROR;
561 }
562
563 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
564 }
565 }
566
567 for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
568 uint32_t regvalue;
569 regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
570 if (regvalue != armv7m_algorithm_info->context[i]) {
571 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
572 armv7m->arm.core_cache->reg_list[i].name,
573 armv7m_algorithm_info->context[i]);
574 buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
575 0, 32, armv7m_algorithm_info->context[i]);
576 armv7m->arm.core_cache->reg_list[i].valid = true;
577 armv7m->arm.core_cache->reg_list[i].dirty = true;
578 }
579 }
580
581 /* restore previous core mode */
582 if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
583 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
584 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
585 0, 1, armv7m_algorithm_info->core_mode);
586 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
587 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
588 }
589
590 armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
591
592 return retval;
593 }
594
595 /** Logs summary of ARMv7-M state for a halted target. */
596 int armv7m_arch_state(struct target *target)
597 {
598 struct armv7m_common *armv7m = target_to_armv7m(target);
599 struct arm *arm = &armv7m->arm;
600 uint32_t ctrl, sp;
601
602 /* avoid filling log waiting for fileio reply */
603 if (target->semihosting && target->semihosting->hit_fileio)
604 return ERROR_OK;
605
606 ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
607 sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
608
609 LOG_USER("target halted due to %s, current mode: %s %s\n"
610 "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
611 debug_reason_name(target),
612 arm_mode_name(arm->core_mode),
613 armv7m_exception_string(armv7m->exception_number),
614 buf_get_u32(arm->cpsr->value, 0, 32),
615 buf_get_u32(arm->pc->value, 0, 32),
616 (ctrl & 0x02) ? 'p' : 'm',
617 sp,
618 (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
619 (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
620
621 return ERROR_OK;
622 }
623
624 static const struct reg_arch_type armv7m_reg_type = {
625 .get = armv7m_get_core_reg,
626 .set = armv7m_set_core_reg,
627 };
628
629 /** Builds cache of architecturally defined registers. */
630 struct reg_cache *armv7m_build_reg_cache(struct target *target)
631 {
632 struct armv7m_common *armv7m = target_to_armv7m(target);
633 struct arm *arm = &armv7m->arm;
634 int num_regs = ARMV7M_NUM_REGS;
635 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
636 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
637 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
638 struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
639 struct reg_feature *feature;
640 int i;
641
642 /* Build the process context cache */
643 cache->name = "arm v7m registers";
644 cache->next = NULL;
645 cache->reg_list = reg_list;
646 cache->num_regs = num_regs;
647 (*cache_p) = cache;
648
649 for (i = 0; i < num_regs; i++) {
650 arch_info[i].num = armv7m_regs[i].id;
651 arch_info[i].target = target;
652 arch_info[i].arm = arm;
653
654 reg_list[i].name = armv7m_regs[i].name;
655 reg_list[i].size = armv7m_regs[i].bits;
656 size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8);
657 if (storage_size < 4)
658 storage_size = 4;
659 reg_list[i].value = calloc(1, storage_size);
660 reg_list[i].dirty = false;
661 reg_list[i].valid = false;
662 reg_list[i].type = &armv7m_reg_type;
663 reg_list[i].arch_info = &arch_info[i];
664
665 reg_list[i].group = armv7m_regs[i].group;
666 reg_list[i].number = i;
667 reg_list[i].exist = true;
668 reg_list[i].caller_save = true; /* gdb defaults to true */
669
670 feature = calloc(1, sizeof(struct reg_feature));
671 if (feature) {
672 feature->name = armv7m_regs[i].feature;
673 reg_list[i].feature = feature;
674 } else
675 LOG_ERROR("unable to allocate feature list");
676
677 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
678 if (reg_list[i].reg_data_type)
679 reg_list[i].reg_data_type->type = armv7m_regs[i].type;
680 else
681 LOG_ERROR("unable to allocate reg type list");
682 }
683
684 arm->cpsr = reg_list + ARMV7M_xPSR;
685 arm->pc = reg_list + ARMV7M_PC;
686 arm->core_cache = cache;
687
688 return cache;
689 }
690
691 void armv7m_free_reg_cache(struct target *target)
692 {
693 struct armv7m_common *armv7m = target_to_armv7m(target);
694 struct arm *arm = &armv7m->arm;
695 struct reg_cache *cache;
696 struct reg *reg;
697 unsigned int i;
698
699 cache = arm->core_cache;
700
701 if (!cache)
702 return;
703
704 for (i = 0; i < cache->num_regs; i++) {
705 reg = &cache->reg_list[i];
706
707 free(reg->feature);
708 free(reg->reg_data_type);
709 free(reg->value);
710 }
711
712 free(cache->reg_list[0].arch_info);
713 free(cache->reg_list);
714 free(cache);
715
716 arm->core_cache = NULL;
717 }
718
719 static int armv7m_setup_semihosting(struct target *target, int enable)
720 {
721 /* nothing todo for armv7m */
722 return ERROR_OK;
723 }
724
725 /** Sets up target as a generic ARMv7-M core */
726 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
727 {
728 struct arm *arm = &armv7m->arm;
729
730 armv7m->common_magic = ARMV7M_COMMON_MAGIC;
731 armv7m->fp_feature = FP_NONE;
732 armv7m->trace_config.trace_bus_id = 1;
733 /* Enable stimulus port #0 by default */
734 armv7m->trace_config.itm_ter[0] = 1;
735
736 arm->core_type = ARM_CORE_TYPE_M_PROFILE;
737 arm->arch_info = armv7m;
738 arm->setup_semihosting = armv7m_setup_semihosting;
739
740 arm->read_core_reg = armv7m_read_core_reg;
741 arm->write_core_reg = armv7m_write_core_reg;
742
743 return arm_init_arch_info(target, arm);
744 }
745
746 /** Generates a CRC32 checksum of a memory region. */
747 int armv7m_checksum_memory(struct target *target,
748 target_addr_t address, uint32_t count, uint32_t *checksum)
749 {
750 struct working_area *crc_algorithm;
751 struct armv7m_algorithm armv7m_info;
752 struct reg_param reg_params[2];
753 int retval;
754
755 static const uint8_t cortex_m_crc_code[] = {
756 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
757 };
758
759 retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
760 if (retval != ERROR_OK)
761 return retval;
762
763 retval = target_write_buffer(target, crc_algorithm->address,
764 sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code);
765 if (retval != ERROR_OK)
766 goto cleanup;
767
768 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
769 armv7m_info.core_mode = ARM_MODE_THREAD;
770
771 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
772 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
773
774 buf_set_u32(reg_params[0].value, 0, 32, address);
775 buf_set_u32(reg_params[1].value, 0, 32, count);
776
777 int timeout = 20000 * (1 + (count / (1024 * 1024)));
778
779 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
780 crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
781 timeout, &armv7m_info);
782
783 if (retval == ERROR_OK)
784 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
785 else
786 LOG_ERROR("error executing cortex_m crc algorithm");
787
788 destroy_reg_param(&reg_params[0]);
789 destroy_reg_param(&reg_params[1]);
790
791 cleanup:
792 target_free_working_area(target, crc_algorithm);
793
794 return retval;
795 }
796
797 /** Checks an array of memory regions whether they are erased. */
798 int armv7m_blank_check_memory(struct target *target,
799 struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
800 {
801 struct working_area *erase_check_algorithm;
802 struct working_area *erase_check_params;
803 struct reg_param reg_params[2];
804 struct armv7m_algorithm armv7m_info;
805 int retval;
806
807 static bool timed_out;
808
809 static const uint8_t erase_check_code[] = {
810 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
811 };
812
813 const uint32_t code_size = sizeof(erase_check_code);
814
815 /* make sure we have a working area */
816 if (target_alloc_working_area(target, code_size,
817 &erase_check_algorithm) != ERROR_OK)
818 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
819
820 retval = target_write_buffer(target, erase_check_algorithm->address,
821 code_size, erase_check_code);
822 if (retval != ERROR_OK)
823 goto cleanup1;
824
825 /* prepare blocks array for algo */
826 struct algo_block {
827 union {
828 uint32_t size;
829 uint32_t result;
830 };
831 uint32_t address;
832 };
833
834 uint32_t avail = target_get_working_area_avail(target);
835 int blocks_to_check = avail / sizeof(struct algo_block) - 1;
836 if (num_blocks < blocks_to_check)
837 blocks_to_check = num_blocks;
838
839 struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block));
840 if (params == NULL) {
841 retval = ERROR_FAIL;
842 goto cleanup1;
843 }
844
845 int i;
846 uint32_t total_size = 0;
847 for (i = 0; i < blocks_to_check; i++) {
848 total_size += blocks[i].size;
849 target_buffer_set_u32(target, (uint8_t *)&(params[i].size),
850 blocks[i].size / sizeof(uint32_t));
851 target_buffer_set_u32(target, (uint8_t *)&(params[i].address),
852 blocks[i].address);
853 }
854 target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0);
855
856 uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block);
857 if (target_alloc_working_area(target, param_size,
858 &erase_check_params) != ERROR_OK) {
859 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
860 goto cleanup2;
861 }
862
863 retval = target_write_buffer(target, erase_check_params->address,
864 param_size, (uint8_t *)params);
865 if (retval != ERROR_OK)
866 goto cleanup3;
867
868 uint32_t erased_word = erased_value | (erased_value << 8)
869 | (erased_value << 16) | (erased_value << 24);
870
871 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
872 TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address);
873
874 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
875 armv7m_info.core_mode = ARM_MODE_THREAD;
876
877 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
878 buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address);
879
880 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
881 buf_set_u32(reg_params[1].value, 0, 32, erased_word);
882
883 /* assume CPU clk at least 1 MHz */
884 int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
885
886 retval = target_run_algorithm(target,
887 0, NULL,
888 ARRAY_SIZE(reg_params), reg_params,
889 erase_check_algorithm->address,
890 erase_check_algorithm->address + (code_size - 2),
891 timeout,
892 &armv7m_info);
893
894 timed_out = retval == ERROR_TARGET_TIMEOUT;
895 if (retval != ERROR_OK && !timed_out)
896 goto cleanup4;
897
898 retval = target_read_buffer(target, erase_check_params->address,
899 param_size, (uint8_t *)params);
900 if (retval != ERROR_OK)
901 goto cleanup4;
902
903 for (i = 0; i < blocks_to_check; i++) {
904 uint32_t result = target_buffer_get_u32(target,
905 (uint8_t *)&(params[i].result));
906 if (result != 0 && result != 1)
907 break;
908
909 blocks[i].result = result;
910 }
911 if (i && timed_out)
912 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i);
913
914 retval = i; /* return number of blocks really checked */
915
916 cleanup4:
917 destroy_reg_param(&reg_params[0]);
918 destroy_reg_param(&reg_params[1]);
919
920 cleanup3:
921 target_free_working_area(target, erase_check_params);
922 cleanup2:
923 free(params);
924 cleanup1:
925 target_free_working_area(target, erase_check_algorithm);
926
927 return retval;
928 }
929
930 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
931 {
932 struct armv7m_common *armv7m = target_to_armv7m(target);
933 struct reg *r = armv7m->arm.pc;
934 bool result = false;
935
936
937 /* if we halted last time due to a bkpt instruction
938 * then we have to manually step over it, otherwise
939 * the core will break again */
940
941 if (target->debug_reason == DBG_REASON_BREAKPOINT) {
942 uint16_t op;
943 uint32_t pc = buf_get_u32(r->value, 0, 32);
944
945 pc &= ~1;
946 if (target_read_u16(target, pc, &op) == ERROR_OK) {
947 if ((op & 0xFF00) == 0xBE00) {
948 pc = buf_get_u32(r->value, 0, 32) + 2;
949 buf_set_u32(r->value, 0, 32, pc);
950 r->dirty = true;
951 r->valid = true;
952 result = true;
953 LOG_DEBUG("Skipping over BKPT instruction");
954 }
955 }
956 }
957
958 if (inst_found)
959 *inst_found = result;
960
961 return ERROR_OK;
962 }
963
964 const struct command_registration armv7m_command_handlers[] = {
965 {
966 .chain = arm_command_handlers,
967 },
968 COMMAND_REGISTRATION_DONE
969 };

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)