armv7m: add gdb target description support
[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[17] = {
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[17] = {
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 uint32_t reg_value;
220 struct arm_reg *armv7m_core_reg;
221 struct armv7m_common *armv7m = target_to_armv7m(target);
222
223 assert(num < (int)armv7m->arm.core_cache->num_regs);
224
225 reg_value = buf_get_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32);
226 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
227 retval = armv7m->store_core_reg_u32(target,
228 armv7m_core_reg->num,
229 reg_value);
230 if (retval != ERROR_OK) {
231 LOG_ERROR("JTAG failure");
232 armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
233 return ERROR_JTAG_DEVICE_ERROR;
234 }
235
236 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
237 armv7m->arm.core_cache->reg_list[num].valid = 1;
238 armv7m->arm.core_cache->reg_list[num].dirty = 0;
239
240 return ERROR_OK;
241 }
242
243 /**
244 * Returns generic ARM userspace registers to GDB.
245 */
246 int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
247 int *reg_list_size, enum target_register_class reg_class)
248 {
249 struct armv7m_common *armv7m = target_to_armv7m(target);
250 int i;
251
252 if (reg_class == REG_CLASS_ALL)
253 *reg_list_size = ARMV7M_NUM_REGS;
254 else
255 *reg_list_size = 17;
256
257 *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
258 if (*reg_list == NULL)
259 return ERROR_FAIL;
260
261 for (i = 0; i < *reg_list_size; i++)
262 (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
263
264 return ERROR_OK;
265 }
266
267 /** Runs a Thumb algorithm in the target. */
268 int armv7m_run_algorithm(struct target *target,
269 int num_mem_params, struct mem_param *mem_params,
270 int num_reg_params, struct reg_param *reg_params,
271 uint32_t entry_point, uint32_t exit_point,
272 int timeout_ms, void *arch_info)
273 {
274 int retval;
275
276 retval = armv7m_start_algorithm(target,
277 num_mem_params, mem_params,
278 num_reg_params, reg_params,
279 entry_point, exit_point,
280 arch_info);
281
282 if (retval == ERROR_OK)
283 retval = armv7m_wait_algorithm(target,
284 num_mem_params, mem_params,
285 num_reg_params, reg_params,
286 exit_point, timeout_ms,
287 arch_info);
288
289 return retval;
290 }
291
292 /** Starts a Thumb algorithm in the target. */
293 int armv7m_start_algorithm(struct target *target,
294 int num_mem_params, struct mem_param *mem_params,
295 int num_reg_params, struct reg_param *reg_params,
296 uint32_t entry_point, uint32_t exit_point,
297 void *arch_info)
298 {
299 struct armv7m_common *armv7m = target_to_armv7m(target);
300 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
301 enum arm_mode core_mode = armv7m->arm.core_mode;
302 int retval = ERROR_OK;
303
304 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
305 * at the exit point */
306
307 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
308 LOG_ERROR("current target isn't an ARMV7M target");
309 return ERROR_TARGET_INVALID;
310 }
311
312 if (target->state != TARGET_HALTED) {
313 LOG_WARNING("target not halted");
314 return ERROR_TARGET_NOT_HALTED;
315 }
316
317 /* refresh core register cache
318 * Not needed if core register cache is always consistent with target process state */
319 for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) {
320
321 armv7m_algorithm_info->context[i] = buf_get_u32(
322 armv7m->arm.core_cache->reg_list[i].value,
323 0,
324 32);
325 }
326
327 for (int i = 0; i < num_mem_params; i++) {
328 /* TODO: Write only out params */
329 retval = target_write_buffer(target, mem_params[i].address,
330 mem_params[i].size,
331 mem_params[i].value);
332 if (retval != ERROR_OK)
333 return retval;
334 }
335
336 for (int i = 0; i < num_reg_params; i++) {
337 struct reg *reg =
338 register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
339 /* uint32_t regvalue; */
340
341 if (!reg) {
342 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
343 return ERROR_COMMAND_SYNTAX_ERROR;
344 }
345
346 if (reg->size != reg_params[i].size) {
347 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
348 reg_params[i].reg_name);
349 return ERROR_COMMAND_SYNTAX_ERROR;
350 }
351
352 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
353 armv7m_set_core_reg(reg, reg_params[i].value);
354 }
355
356 if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
357 armv7m_algorithm_info->core_mode != core_mode) {
358
359 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
360 if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
361 armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
362 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
363 }
364
365 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
366 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
367 0, 1, armv7m_algorithm_info->core_mode);
368 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
369 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
370 }
371
372 /* save previous core mode */
373 armv7m_algorithm_info->core_mode = core_mode;
374
375 retval = target_resume(target, 0, entry_point, 1, 1);
376
377 return retval;
378 }
379
380 /** Waits for an algorithm in the target. */
381 int armv7m_wait_algorithm(struct target *target,
382 int num_mem_params, struct mem_param *mem_params,
383 int num_reg_params, struct reg_param *reg_params,
384 uint32_t exit_point, int timeout_ms,
385 void *arch_info)
386 {
387 struct armv7m_common *armv7m = target_to_armv7m(target);
388 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
389 int retval = ERROR_OK;
390 uint32_t pc;
391
392 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
393 * at the exit point */
394
395 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
396 LOG_ERROR("current target isn't an ARMV7M target");
397 return ERROR_TARGET_INVALID;
398 }
399
400 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
401 /* If the target fails to halt due to the breakpoint, force a halt */
402 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
403 retval = target_halt(target);
404 if (retval != ERROR_OK)
405 return retval;
406 retval = target_wait_state(target, TARGET_HALTED, 500);
407 if (retval != ERROR_OK)
408 return retval;
409 return ERROR_TARGET_TIMEOUT;
410 }
411
412 armv7m->load_core_reg_u32(target, 15, &pc);
413 if (exit_point && (pc != exit_point)) {
414 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
415 pc,
416 exit_point);
417 return ERROR_TARGET_TIMEOUT;
418 }
419
420 /* Read memory values to mem_params[] */
421 for (int i = 0; i < num_mem_params; i++) {
422 if (mem_params[i].direction != PARAM_OUT) {
423 retval = target_read_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
431 /* Copy core register values to reg_params[] */
432 for (int i = 0; i < num_reg_params; i++) {
433 if (reg_params[i].direction != PARAM_OUT) {
434 struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
435 reg_params[i].reg_name,
436 0);
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(
445 "BUG: register '%s' size doesn't match reg_params[i].size",
446 reg_params[i].reg_name);
447 return ERROR_COMMAND_SYNTAX_ERROR;
448 }
449
450 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
451 }
452 }
453
454 for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
455 uint32_t regvalue;
456 regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
457 if (regvalue != armv7m_algorithm_info->context[i]) {
458 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
459 armv7m->arm.core_cache->reg_list[i].name,
460 armv7m_algorithm_info->context[i]);
461 buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
462 0, 32, armv7m_algorithm_info->context[i]);
463 armv7m->arm.core_cache->reg_list[i].valid = 1;
464 armv7m->arm.core_cache->reg_list[i].dirty = 1;
465 }
466 }
467
468 /* restore previous core mode */
469 if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
470 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
471 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
472 0, 1, armv7m_algorithm_info->core_mode);
473 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
474 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
475 }
476
477 armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
478
479 return retval;
480 }
481
482 /** Logs summary of ARMv7-M state for a halted target. */
483 int armv7m_arch_state(struct target *target)
484 {
485 struct armv7m_common *armv7m = target_to_armv7m(target);
486 struct arm *arm = &armv7m->arm;
487 uint32_t ctrl, sp;
488
489 ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
490 sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
491
492 LOG_USER("target halted due to %s, current mode: %s %s\n"
493 "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
494 debug_reason_name(target),
495 arm_mode_name(arm->core_mode),
496 armv7m_exception_string(armv7m->exception_number),
497 buf_get_u32(arm->cpsr->value, 0, 32),
498 buf_get_u32(arm->pc->value, 0, 32),
499 (ctrl & 0x02) ? 'p' : 'm',
500 sp,
501 arm->is_semihosting ? ", semihosting" : "");
502
503 return ERROR_OK;
504 }
505
506 static const struct reg_arch_type armv7m_reg_type = {
507 .get = armv7m_get_core_reg,
508 .set = armv7m_set_core_reg,
509 };
510
511 /** Builds cache of architecturally defined registers. */
512 struct reg_cache *armv7m_build_reg_cache(struct target *target)
513 {
514 struct armv7m_common *armv7m = target_to_armv7m(target);
515 struct arm *arm = &armv7m->arm;
516 int num_regs = ARMV7M_NUM_REGS;
517 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
518 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
519 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
520 struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
521 struct reg_feature *feature;
522 int i;
523
524 /* Build the process context cache */
525 cache->name = "arm v7m registers";
526 cache->next = NULL;
527 cache->reg_list = reg_list;
528 cache->num_regs = num_regs;
529 (*cache_p) = cache;
530
531 for (i = 0; i < num_regs; i++) {
532 arch_info[i].num = armv7m_regs[i].id;
533 arch_info[i].target = target;
534 arch_info[i].arm = arm;
535
536 reg_list[i].name = armv7m_regs[i].name;
537 reg_list[i].size = armv7m_regs[i].bits;
538 reg_list[i].value = calloc(1, 4);
539 reg_list[i].dirty = 0;
540 reg_list[i].valid = 0;
541 reg_list[i].type = &armv7m_reg_type;
542 reg_list[i].arch_info = &arch_info[i];
543
544 reg_list[i].group = armv7m_regs[i].group;
545 reg_list[i].number = i;
546 reg_list[i].exist = true;
547 reg_list[i].caller_save = true; /* gdb defaults to true */
548
549 feature = calloc(1, sizeof(struct reg_feature));
550 if (feature) {
551 feature->name = armv7m_regs[i].feature;
552 reg_list[i].feature = feature;
553 } else
554 LOG_ERROR("unable to allocate feature list");
555
556 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
557 if (reg_list[i].reg_data_type)
558 reg_list[i].reg_data_type->type = armv7m_regs[i].type;
559 else
560 LOG_ERROR("unable to allocate reg type list");
561 }
562
563 arm->cpsr = reg_list + ARMV7M_xPSR;
564 arm->pc = reg_list + ARMV7M_PC;
565 arm->core_cache = cache;
566
567 return cache;
568 }
569
570 static int armv7m_setup_semihosting(struct target *target, int enable)
571 {
572 /* nothing todo for armv7m */
573 return ERROR_OK;
574 }
575
576 /** Sets up target as a generic ARMv7-M core */
577 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
578 {
579 struct arm *arm = &armv7m->arm;
580
581 armv7m->common_magic = ARMV7M_COMMON_MAGIC;
582 armv7m->fp_feature = FP_NONE;
583
584 arm->core_type = ARM_MODE_THREAD;
585 arm->arch_info = armv7m;
586 arm->setup_semihosting = armv7m_setup_semihosting;
587
588 arm->read_core_reg = armv7m_read_core_reg;
589 arm->write_core_reg = armv7m_write_core_reg;
590
591 return arm_init_arch_info(target, arm);
592 }
593
594 /** Generates a CRC32 checksum of a memory region. */
595 int armv7m_checksum_memory(struct target *target,
596 uint32_t address, uint32_t count, uint32_t *checksum)
597 {
598 struct working_area *crc_algorithm;
599 struct armv7m_algorithm armv7m_info;
600 struct reg_param reg_params[2];
601 int retval;
602
603 /* see contrib/loaders/checksum/armv7m_crc.s for src */
604
605 static const uint8_t cortex_m3_crc_code[] = {
606 /* main: */
607 0x02, 0x46, /* mov r2, r0 */
608 0x00, 0x20, /* movs r0, #0 */
609 0xC0, 0x43, /* mvns r0, r0 */
610 0x0A, 0x4E, /* ldr r6, CRC32XOR */
611 0x0B, 0x46, /* mov r3, r1 */
612 0x00, 0x24, /* movs r4, #0 */
613 0x0D, 0xE0, /* b ncomp */
614 /* nbyte: */
615 0x11, 0x5D, /* ldrb r1, [r2, r4] */
616 0x09, 0x06, /* lsls r1, r1, #24 */
617 0x48, 0x40, /* eors r0, r0, r1 */
618 0x00, 0x25, /* movs r5, #0 */
619 /* loop: */
620 0x00, 0x28, /* cmp r0, #0 */
621 0x02, 0xDA, /* bge notset */
622 0x40, 0x00, /* lsls r0, r0, #1 */
623 0x70, 0x40, /* eors r0, r0, r6 */
624 0x00, 0xE0, /* b cont */
625 /* notset: */
626 0x40, 0x00, /* lsls r0, r0, #1 */
627 /* cont: */
628 0x01, 0x35, /* adds r5, r5, #1 */
629 0x08, 0x2D, /* cmp r5, #8 */
630 0xF6, 0xD1, /* bne loop */
631 0x01, 0x34, /* adds r4, r4, #1 */
632 /* ncomp: */
633 0x9C, 0x42, /* cmp r4, r3 */
634 0xEF, 0xD1, /* bne nbyte */
635 0x00, 0xBE, /* bkpt #0 */
636 0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */
637 };
638
639 retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm);
640 if (retval != ERROR_OK)
641 return retval;
642
643 retval = target_write_buffer(target, crc_algorithm->address,
644 sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code);
645 if (retval != ERROR_OK)
646 goto cleanup;
647
648 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
649 armv7m_info.core_mode = ARM_MODE_THREAD;
650
651 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
652 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
653
654 buf_set_u32(reg_params[0].value, 0, 32, address);
655 buf_set_u32(reg_params[1].value, 0, 32, count);
656
657 int timeout = 20000 * (1 + (count / (1024 * 1024)));
658
659 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
660 crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6),
661 timeout, &armv7m_info);
662
663 if (retval == ERROR_OK)
664 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
665 else
666 LOG_ERROR("error executing cortex_m crc algorithm");
667
668 destroy_reg_param(&reg_params[0]);
669 destroy_reg_param(&reg_params[1]);
670
671 cleanup:
672 target_free_working_area(target, crc_algorithm);
673
674 return retval;
675 }
676
677 /** Checks whether a memory region is zeroed. */
678 int armv7m_blank_check_memory(struct target *target,
679 uint32_t address, uint32_t count, uint32_t *blank)
680 {
681 struct working_area *erase_check_algorithm;
682 struct reg_param reg_params[3];
683 struct armv7m_algorithm armv7m_info;
684 int retval;
685
686 /* see contrib/loaders/erase_check/armv7m_erase_check.s for src */
687
688 static const uint8_t erase_check_code[] = {
689 /* loop: */
690 0x03, 0x78, /* ldrb r3, [r0] */
691 0x01, 0x30, /* adds r0, #1 */
692 0x1A, 0x40, /* ands r2, r2, r3 */
693 0x01, 0x39, /* subs r1, r1, #1 */
694 0xFA, 0xD1, /* bne loop */
695 0x00, 0xBE /* bkpt #0 */
696 };
697
698 /* make sure we have a working area */
699 if (target_alloc_working_area(target, sizeof(erase_check_code),
700 &erase_check_algorithm) != ERROR_OK)
701 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
702
703 retval = target_write_buffer(target, erase_check_algorithm->address,
704 sizeof(erase_check_code), (uint8_t *)erase_check_code);
705 if (retval != ERROR_OK)
706 return retval;
707
708 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
709 armv7m_info.core_mode = ARM_MODE_THREAD;
710
711 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
712 buf_set_u32(reg_params[0].value, 0, 32, address);
713
714 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
715 buf_set_u32(reg_params[1].value, 0, 32, count);
716
717 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
718 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
719
720 retval = target_run_algorithm(target,
721 0,
722 NULL,
723 3,
724 reg_params,
725 erase_check_algorithm->address,
726 erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
727 10000,
728 &armv7m_info);
729
730 if (retval == ERROR_OK)
731 *blank = buf_get_u32(reg_params[2].value, 0, 32);
732
733 destroy_reg_param(&reg_params[0]);
734 destroy_reg_param(&reg_params[1]);
735 destroy_reg_param(&reg_params[2]);
736
737 target_free_working_area(target, erase_check_algorithm);
738
739 return retval;
740 }
741
742 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
743 {
744 struct armv7m_common *armv7m = target_to_armv7m(target);
745 struct reg *r = armv7m->arm.pc;
746 bool result = false;
747
748
749 /* if we halted last time due to a bkpt instruction
750 * then we have to manually step over it, otherwise
751 * the core will break again */
752
753 if (target->debug_reason == DBG_REASON_BREAKPOINT) {
754 uint16_t op;
755 uint32_t pc = buf_get_u32(r->value, 0, 32);
756
757 pc &= ~1;
758 if (target_read_u16(target, pc, &op) == ERROR_OK) {
759 if ((op & 0xFF00) == 0xBE00) {
760 pc = buf_get_u32(r->value, 0, 32) + 2;
761 buf_set_u32(r->value, 0, 32, pc);
762 r->dirty = true;
763 r->valid = true;
764 result = true;
765 LOG_DEBUG("Skipping over BKPT instruction");
766 }
767 }
768 }
769
770 if (inst_found)
771 *inst_found = result;
772
773 return ERROR_OK;
774 }
775
776 const struct command_registration armv7m_command_handlers[] = {
777 {
778 .chain = arm_command_handlers,
779 },
780 {
781 .chain = dap_command_handlers,
782 },
783 COMMAND_REGISTRATION_DONE
784 };

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)