armv7m: remove magic numbers for number of core registers
[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 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
28 * *
29 * ARMv7-M Architecture, Application Level Reference Manual *
30 * ARM DDI 0405C (September 2008) *
31 * *
32 ***************************************************************************/
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "breakpoints.h"
39 #include "armv7m.h"
40 #include "algorithm.h"
41 #include "register.h"
42
43 #if 0
44 #define _DEBUG_INSTRUCTION_EXECUTION_
45 #endif
46
47 static char *armv7m_exception_strings[] = {
48 "", "Reset", "NMI", "HardFault",
49 "MemManage", "BusFault", "UsageFault", "RESERVED",
50 "RESERVED", "RESERVED", "RESERVED", "SVCall",
51 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
52 };
53
54 /* PSP is used in some thread modes */
55 const int armv7m_psp_reg_map[ARMV7M_NUM_CORE_REGS] = {
56 ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
57 ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
58 ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
59 ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC,
60 ARMV7M_xPSR,
61 };
62
63 /* MSP is used in handler and some thread modes */
64 const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = {
65 ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
66 ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
67 ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
68 ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC,
69 ARMV7M_xPSR,
70 };
71
72 /*
73 * These registers are not memory-mapped. The ARMv7-M profile includes
74 * memory mapped registers too, such as for the NVIC (interrupt controller)
75 * and SysTick (timer) modules; those can mostly be treated as peripherals.
76 *
77 * The ARMv6-M profile is almost identical in this respect, except that it
78 * doesn't include basepri or faultmask registers.
79 */
80 static const struct {
81 unsigned id;
82 const char *name;
83 unsigned bits;
84 enum reg_type type;
85 const char *group;
86 const char *feature;
87 } armv7m_regs[] = {
88 { ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
89 { ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
90 { ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
91 { ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
92 { ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
93 { ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
101 { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
103 { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" },
104 { ARMV7M_xPSR, "xPSR", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
105
106 { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
107 { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
108
109 { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
110 { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
111 { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
112 { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
113 };
114
115 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
116
117 /**
118 * Restores target context using the cache of core registers set up
119 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
120 */
121 int armv7m_restore_context(struct target *target)
122 {
123 int i;
124 struct armv7m_common *armv7m = target_to_armv7m(target);
125 struct reg_cache *cache = armv7m->arm.core_cache;
126
127 LOG_DEBUG(" ");
128
129 if (armv7m->pre_restore_context)
130 armv7m->pre_restore_context(target);
131
132 for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
133 if (cache->reg_list[i].dirty) {
134 uint32_t value = buf_get_u32(cache->reg_list[i].value, 0, 32);
135 armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, ARM_MODE_ANY, value);
136 }
137 }
138
139 return ERROR_OK;
140 }
141
142 /* Core state functions */
143
144 /**
145 * Maps ISR number (from xPSR) to name.
146 * Note that while names and meanings for the first sixteen are standardized
147 * (with zero not a true exception), external interrupts are only numbered.
148 * They are assigned by vendors, which generally assign different numbers to
149 * peripherals (such as UART0 or a USB peripheral controller).
150 */
151 char *armv7m_exception_string(int number)
152 {
153 static char enamebuf[32];
154
155 if ((number < 0) | (number > 511))
156 return "Invalid exception";
157 if (number < 16)
158 return armv7m_exception_strings[number];
159 sprintf(enamebuf, "External Interrupt(%i)", number - 16);
160 return enamebuf;
161 }
162
163 static int armv7m_get_core_reg(struct reg *reg)
164 {
165 int retval;
166 struct arm_reg *armv7m_reg = reg->arch_info;
167 struct target *target = armv7m_reg->target;
168 struct arm *arm = target_to_arm(target);
169
170 if (target->state != TARGET_HALTED)
171 return ERROR_TARGET_NOT_HALTED;
172
173 retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode);
174
175 return retval;
176 }
177
178 static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
179 {
180 struct arm_reg *armv7m_reg = reg->arch_info;
181 struct target *target = armv7m_reg->target;
182 uint32_t value = buf_get_u32(buf, 0, 32);
183
184 if (target->state != TARGET_HALTED)
185 return ERROR_TARGET_NOT_HALTED;
186
187 buf_set_u32(reg->value, 0, 32, value);
188 reg->dirty = 1;
189 reg->valid = 1;
190
191 return ERROR_OK;
192 }
193
194 static int armv7m_read_core_reg(struct target *target, struct reg *r,
195 int num, enum arm_mode mode)
196 {
197 uint32_t reg_value;
198 int retval;
199 struct arm_reg *armv7m_core_reg;
200 struct armv7m_common *armv7m = target_to_armv7m(target);
201
202 assert(num < (int)armv7m->arm.core_cache->num_regs);
203
204 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
205 retval = armv7m->load_core_reg_u32(target,
206 armv7m_core_reg->num, &reg_value);
207
208 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
209 armv7m->arm.core_cache->reg_list[num].valid = 1;
210 armv7m->arm.core_cache->reg_list[num].dirty = 0;
211
212 return retval;
213 }
214
215 static int armv7m_write_core_reg(struct target *target, struct reg *r,
216 int num, enum arm_mode mode, uint32_t value)
217 {
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 retval = armv7m->store_core_reg_u32(target,
226 armv7m_core_reg->num,
227 value);
228 if (retval != ERROR_OK) {
229 LOG_ERROR("JTAG failure");
230 armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
231 return ERROR_JTAG_DEVICE_ERROR;
232 }
233
234 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, value);
235 armv7m->arm.core_cache->reg_list[num].valid = 1;
236 armv7m->arm.core_cache->reg_list[num].dirty = 0;
237
238 return ERROR_OK;
239 }
240
241 /**
242 * Returns generic ARM userspace registers to GDB.
243 */
244 int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
245 int *reg_list_size, enum target_register_class reg_class)
246 {
247 struct armv7m_common *armv7m = target_to_armv7m(target);
248 int i;
249
250 if (reg_class == REG_CLASS_ALL)
251 *reg_list_size = ARMV7M_NUM_REGS;
252 else
253 *reg_list_size = ARMV7M_NUM_CORE_REGS;
254
255 *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
256 if (*reg_list == NULL)
257 return ERROR_FAIL;
258
259 for (i = 0; i < *reg_list_size; i++)
260 (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
261
262 return ERROR_OK;
263 }
264
265 /** Runs a Thumb algorithm in the target. */
266 int armv7m_run_algorithm(struct target *target,
267 int num_mem_params, struct mem_param *mem_params,
268 int num_reg_params, struct reg_param *reg_params,
269 uint32_t entry_point, uint32_t exit_point,
270 int timeout_ms, void *arch_info)
271 {
272 int retval;
273
274 retval = armv7m_start_algorithm(target,
275 num_mem_params, mem_params,
276 num_reg_params, reg_params,
277 entry_point, exit_point,
278 arch_info);
279
280 if (retval == ERROR_OK)
281 retval = armv7m_wait_algorithm(target,
282 num_mem_params, mem_params,
283 num_reg_params, reg_params,
284 exit_point, timeout_ms,
285 arch_info);
286
287 return retval;
288 }
289
290 /** Starts a Thumb algorithm in the target. */
291 int armv7m_start_algorithm(struct target *target,
292 int num_mem_params, struct mem_param *mem_params,
293 int num_reg_params, struct reg_param *reg_params,
294 uint32_t entry_point, uint32_t exit_point,
295 void *arch_info)
296 {
297 struct armv7m_common *armv7m = target_to_armv7m(target);
298 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
299 enum arm_mode core_mode = armv7m->arm.core_mode;
300 int retval = ERROR_OK;
301
302 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
303 * at the exit point */
304
305 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
306 LOG_ERROR("current target isn't an ARMV7M target");
307 return ERROR_TARGET_INVALID;
308 }
309
310 if (target->state != TARGET_HALTED) {
311 LOG_WARNING("target not halted");
312 return ERROR_TARGET_NOT_HALTED;
313 }
314
315 /* refresh core register cache
316 * Not needed if core register cache is always consistent with target process state */
317 for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) {
318
319 armv7m_algorithm_info->context[i] = buf_get_u32(
320 armv7m->arm.core_cache->reg_list[i].value,
321 0,
322 32);
323 }
324
325 for (int i = 0; i < num_mem_params; i++) {
326 /* TODO: Write only out params */
327 retval = target_write_buffer(target, mem_params[i].address,
328 mem_params[i].size,
329 mem_params[i].value);
330 if (retval != ERROR_OK)
331 return retval;
332 }
333
334 for (int i = 0; i < num_reg_params; i++) {
335 struct reg *reg =
336 register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
337 /* uint32_t regvalue; */
338
339 if (!reg) {
340 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
341 return ERROR_COMMAND_SYNTAX_ERROR;
342 }
343
344 if (reg->size != reg_params[i].size) {
345 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
346 reg_params[i].reg_name);
347 return ERROR_COMMAND_SYNTAX_ERROR;
348 }
349
350 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
351 armv7m_set_core_reg(reg, reg_params[i].value);
352 }
353
354 if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
355 armv7m_algorithm_info->core_mode != core_mode) {
356
357 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
358 if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
359 armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
360 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
361 }
362
363 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
364 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
365 0, 1, armv7m_algorithm_info->core_mode);
366 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
367 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
368 }
369
370 /* save previous core mode */
371 armv7m_algorithm_info->core_mode = core_mode;
372
373 retval = target_resume(target, 0, entry_point, 1, 1);
374
375 return retval;
376 }
377
378 /** Waits for an algorithm in the target. */
379 int armv7m_wait_algorithm(struct target *target,
380 int num_mem_params, struct mem_param *mem_params,
381 int num_reg_params, struct reg_param *reg_params,
382 uint32_t exit_point, int timeout_ms,
383 void *arch_info)
384 {
385 struct armv7m_common *armv7m = target_to_armv7m(target);
386 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
387 int retval = ERROR_OK;
388 uint32_t pc;
389
390 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
391 * at the exit point */
392
393 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
394 LOG_ERROR("current target isn't an ARMV7M target");
395 return ERROR_TARGET_INVALID;
396 }
397
398 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
399 /* If the target fails to halt due to the breakpoint, force a halt */
400 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
401 retval = target_halt(target);
402 if (retval != ERROR_OK)
403 return retval;
404 retval = target_wait_state(target, TARGET_HALTED, 500);
405 if (retval != ERROR_OK)
406 return retval;
407 return ERROR_TARGET_TIMEOUT;
408 }
409
410 armv7m->load_core_reg_u32(target, 15, &pc);
411 if (exit_point && (pc != exit_point)) {
412 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
413 pc,
414 exit_point);
415 return ERROR_TARGET_TIMEOUT;
416 }
417
418 /* Read memory values to mem_params[] */
419 for (int i = 0; i < num_mem_params; i++) {
420 if (mem_params[i].direction != PARAM_OUT) {
421 retval = target_read_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
429 /* Copy core register values to reg_params[] */
430 for (int i = 0; i < num_reg_params; i++) {
431 if (reg_params[i].direction != PARAM_OUT) {
432 struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
433 reg_params[i].reg_name,
434 0);
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(
443 "BUG: register '%s' size doesn't match reg_params[i].size",
444 reg_params[i].reg_name);
445 return ERROR_COMMAND_SYNTAX_ERROR;
446 }
447
448 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
449 }
450 }
451
452 for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
453 uint32_t regvalue;
454 regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
455 if (regvalue != armv7m_algorithm_info->context[i]) {
456 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
457 armv7m->arm.core_cache->reg_list[i].name,
458 armv7m_algorithm_info->context[i]);
459 buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
460 0, 32, armv7m_algorithm_info->context[i]);
461 armv7m->arm.core_cache->reg_list[i].valid = 1;
462 armv7m->arm.core_cache->reg_list[i].dirty = 1;
463 }
464 }
465
466 /* restore previous core mode */
467 if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
468 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
469 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
470 0, 1, armv7m_algorithm_info->core_mode);
471 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
472 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
473 }
474
475 armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
476
477 return retval;
478 }
479
480 /** Logs summary of ARMv7-M state for a halted target. */
481 int armv7m_arch_state(struct target *target)
482 {
483 struct armv7m_common *armv7m = target_to_armv7m(target);
484 struct arm *arm = &armv7m->arm;
485 uint32_t ctrl, sp;
486
487 ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
488 sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
489
490 LOG_USER("target halted due to %s, current mode: %s %s\n"
491 "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
492 debug_reason_name(target),
493 arm_mode_name(arm->core_mode),
494 armv7m_exception_string(armv7m->exception_number),
495 buf_get_u32(arm->cpsr->value, 0, 32),
496 buf_get_u32(arm->pc->value, 0, 32),
497 (ctrl & 0x02) ? 'p' : 'm',
498 sp,
499 arm->is_semihosting ? ", semihosting" : "");
500
501 return ERROR_OK;
502 }
503
504 static const struct reg_arch_type armv7m_reg_type = {
505 .get = armv7m_get_core_reg,
506 .set = armv7m_set_core_reg,
507 };
508
509 /** Builds cache of architecturally defined registers. */
510 struct reg_cache *armv7m_build_reg_cache(struct target *target)
511 {
512 struct armv7m_common *armv7m = target_to_armv7m(target);
513 struct arm *arm = &armv7m->arm;
514 int num_regs = ARMV7M_NUM_REGS;
515 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
516 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
517 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
518 struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
519 struct reg_feature *feature;
520 int i;
521
522 /* Build the process context cache */
523 cache->name = "arm v7m registers";
524 cache->next = NULL;
525 cache->reg_list = reg_list;
526 cache->num_regs = num_regs;
527 (*cache_p) = cache;
528
529 for (i = 0; i < num_regs; i++) {
530 arch_info[i].num = armv7m_regs[i].id;
531 arch_info[i].target = target;
532 arch_info[i].arm = arm;
533
534 reg_list[i].name = armv7m_regs[i].name;
535 reg_list[i].size = armv7m_regs[i].bits;
536 reg_list[i].value = calloc(1, 4);
537 reg_list[i].dirty = 0;
538 reg_list[i].valid = 0;
539 reg_list[i].type = &armv7m_reg_type;
540 reg_list[i].arch_info = &arch_info[i];
541
542 reg_list[i].group = armv7m_regs[i].group;
543 reg_list[i].number = i;
544 reg_list[i].exist = true;
545 reg_list[i].caller_save = true; /* gdb defaults to true */
546
547 feature = calloc(1, sizeof(struct reg_feature));
548 if (feature) {
549 feature->name = armv7m_regs[i].feature;
550 reg_list[i].feature = feature;
551 } else
552 LOG_ERROR("unable to allocate feature list");
553
554 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
555 if (reg_list[i].reg_data_type)
556 reg_list[i].reg_data_type->type = armv7m_regs[i].type;
557 else
558 LOG_ERROR("unable to allocate reg type list");
559 }
560
561 arm->cpsr = reg_list + ARMV7M_xPSR;
562 arm->pc = reg_list + ARMV7M_PC;
563 arm->core_cache = cache;
564
565 return cache;
566 }
567
568 static int armv7m_setup_semihosting(struct target *target, int enable)
569 {
570 /* nothing todo for armv7m */
571 return ERROR_OK;
572 }
573
574 /** Sets up target as a generic ARMv7-M core */
575 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
576 {
577 struct arm *arm = &armv7m->arm;
578
579 armv7m->common_magic = ARMV7M_COMMON_MAGIC;
580 armv7m->fp_feature = FP_NONE;
581
582 arm->core_type = ARM_MODE_THREAD;
583 arm->arch_info = armv7m;
584 arm->setup_semihosting = armv7m_setup_semihosting;
585
586 arm->read_core_reg = armv7m_read_core_reg;
587 arm->write_core_reg = armv7m_write_core_reg;
588
589 return arm_init_arch_info(target, arm);
590 }
591
592 /** Generates a CRC32 checksum of a memory region. */
593 int armv7m_checksum_memory(struct target *target,
594 uint32_t address, uint32_t count, uint32_t *checksum)
595 {
596 struct working_area *crc_algorithm;
597 struct armv7m_algorithm armv7m_info;
598 struct reg_param reg_params[2];
599 int retval;
600
601 /* see contrib/loaders/checksum/armv7m_crc.s for src */
602
603 static const uint8_t cortex_m_crc_code[] = {
604 /* main: */
605 0x02, 0x46, /* mov r2, r0 */
606 0x00, 0x20, /* movs r0, #0 */
607 0xC0, 0x43, /* mvns r0, r0 */
608 0x0A, 0x4E, /* ldr r6, CRC32XOR */
609 0x0B, 0x46, /* mov r3, r1 */
610 0x00, 0x24, /* movs r4, #0 */
611 0x0D, 0xE0, /* b ncomp */
612 /* nbyte: */
613 0x11, 0x5D, /* ldrb r1, [r2, r4] */
614 0x09, 0x06, /* lsls r1, r1, #24 */
615 0x48, 0x40, /* eors r0, r0, r1 */
616 0x00, 0x25, /* movs r5, #0 */
617 /* loop: */
618 0x00, 0x28, /* cmp r0, #0 */
619 0x02, 0xDA, /* bge notset */
620 0x40, 0x00, /* lsls r0, r0, #1 */
621 0x70, 0x40, /* eors r0, r0, r6 */
622 0x00, 0xE0, /* b cont */
623 /* notset: */
624 0x40, 0x00, /* lsls r0, r0, #1 */
625 /* cont: */
626 0x01, 0x35, /* adds r5, r5, #1 */
627 0x08, 0x2D, /* cmp r5, #8 */
628 0xF6, 0xD1, /* bne loop */
629 0x01, 0x34, /* adds r4, r4, #1 */
630 /* ncomp: */
631 0x9C, 0x42, /* cmp r4, r3 */
632 0xEF, 0xD1, /* bne nbyte */
633 0x00, 0xBE, /* bkpt #0 */
634 0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */
635 };
636
637 retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
638 if (retval != ERROR_OK)
639 return retval;
640
641 retval = target_write_buffer(target, crc_algorithm->address,
642 sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code);
643 if (retval != ERROR_OK)
644 goto cleanup;
645
646 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
647 armv7m_info.core_mode = ARM_MODE_THREAD;
648
649 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
650 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
651
652 buf_set_u32(reg_params[0].value, 0, 32, address);
653 buf_set_u32(reg_params[1].value, 0, 32, count);
654
655 int timeout = 20000 * (1 + (count / (1024 * 1024)));
656
657 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
658 crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
659 timeout, &armv7m_info);
660
661 if (retval == ERROR_OK)
662 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
663 else
664 LOG_ERROR("error executing cortex_m crc algorithm");
665
666 destroy_reg_param(&reg_params[0]);
667 destroy_reg_param(&reg_params[1]);
668
669 cleanup:
670 target_free_working_area(target, crc_algorithm);
671
672 return retval;
673 }
674
675 /** Checks whether a memory region is zeroed. */
676 int armv7m_blank_check_memory(struct target *target,
677 uint32_t address, uint32_t count, uint32_t *blank)
678 {
679 struct working_area *erase_check_algorithm;
680 struct reg_param reg_params[3];
681 struct armv7m_algorithm armv7m_info;
682 int retval;
683
684 /* see contrib/loaders/erase_check/armv7m_erase_check.s for src */
685
686 static const uint8_t erase_check_code[] = {
687 /* loop: */
688 0x03, 0x78, /* ldrb r3, [r0] */
689 0x01, 0x30, /* adds r0, #1 */
690 0x1A, 0x40, /* ands r2, r2, r3 */
691 0x01, 0x39, /* subs r1, r1, #1 */
692 0xFA, 0xD1, /* bne loop */
693 0x00, 0xBE /* bkpt #0 */
694 };
695
696 /* make sure we have a working area */
697 if (target_alloc_working_area(target, sizeof(erase_check_code),
698 &erase_check_algorithm) != ERROR_OK)
699 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
700
701 retval = target_write_buffer(target, erase_check_algorithm->address,
702 sizeof(erase_check_code), (uint8_t *)erase_check_code);
703 if (retval != ERROR_OK)
704 return retval;
705
706 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
707 armv7m_info.core_mode = ARM_MODE_THREAD;
708
709 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
710 buf_set_u32(reg_params[0].value, 0, 32, address);
711
712 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
713 buf_set_u32(reg_params[1].value, 0, 32, count);
714
715 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
716 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
717
718 retval = target_run_algorithm(target,
719 0,
720 NULL,
721 3,
722 reg_params,
723 erase_check_algorithm->address,
724 erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
725 10000,
726 &armv7m_info);
727
728 if (retval == ERROR_OK)
729 *blank = buf_get_u32(reg_params[2].value, 0, 32);
730
731 destroy_reg_param(&reg_params[0]);
732 destroy_reg_param(&reg_params[1]);
733 destroy_reg_param(&reg_params[2]);
734
735 target_free_working_area(target, erase_check_algorithm);
736
737 return retval;
738 }
739
740 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
741 {
742 struct armv7m_common *armv7m = target_to_armv7m(target);
743 struct reg *r = armv7m->arm.pc;
744 bool result = false;
745
746
747 /* if we halted last time due to a bkpt instruction
748 * then we have to manually step over it, otherwise
749 * the core will break again */
750
751 if (target->debug_reason == DBG_REASON_BREAKPOINT) {
752 uint16_t op;
753 uint32_t pc = buf_get_u32(r->value, 0, 32);
754
755 pc &= ~1;
756 if (target_read_u16(target, pc, &op) == ERROR_OK) {
757 if ((op & 0xFF00) == 0xBE00) {
758 pc = buf_get_u32(r->value, 0, 32) + 2;
759 buf_set_u32(r->value, 0, 32, pc);
760 r->dirty = true;
761 r->valid = true;
762 result = true;
763 LOG_DEBUG("Skipping over BKPT instruction");
764 }
765 }
766 }
767
768 if (inst_found)
769 *inst_found = result;
770
771 return ERROR_OK;
772 }
773
774 const struct command_registration armv7m_command_handlers[] = {
775 {
776 .chain = arm_command_handlers,
777 },
778 {
779 .chain = dap_command_handlers,
780 },
781 COMMAND_REGISTRATION_DONE
782 };

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)