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

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)