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

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)