armv7m: Integrate build of erase check code
[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 const char * const 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 { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
115 { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
116 { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
117 { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
118 { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
119 { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
120 { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
121 { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
122 { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
123 { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
124 { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
125 { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
126 { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
127 { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
128 { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
129 { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
130
131 { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" },
132 };
133
134 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
135
136 /**
137 * Restores target context using the cache of core registers set up
138 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
139 */
140 int armv7m_restore_context(struct target *target)
141 {
142 int i;
143 struct armv7m_common *armv7m = target_to_armv7m(target);
144 struct reg_cache *cache = armv7m->arm.core_cache;
145
146 LOG_DEBUG(" ");
147
148 if (armv7m->pre_restore_context)
149 armv7m->pre_restore_context(target);
150
151 for (i = cache->num_regs - 1; i >= 0; i--) {
152 if (cache->reg_list[i].dirty) {
153 armv7m->arm.write_core_reg(target, &cache->reg_list[i], i,
154 ARM_MODE_ANY, cache->reg_list[i].value);
155 }
156 }
157
158 return ERROR_OK;
159 }
160
161 /* Core state functions */
162
163 /**
164 * Maps ISR number (from xPSR) to name.
165 * Note that while names and meanings for the first sixteen are standardized
166 * (with zero not a true exception), external interrupts are only numbered.
167 * They are assigned by vendors, which generally assign different numbers to
168 * peripherals (such as UART0 or a USB peripheral controller).
169 */
170 const char *armv7m_exception_string(int number)
171 {
172 static char enamebuf[32];
173
174 if ((number < 0) | (number > 511))
175 return "Invalid exception";
176 if (number < 16)
177 return armv7m_exception_strings[number];
178 sprintf(enamebuf, "External Interrupt(%i)", number - 16);
179 return enamebuf;
180 }
181
182 static int armv7m_get_core_reg(struct reg *reg)
183 {
184 int retval;
185 struct arm_reg *armv7m_reg = reg->arch_info;
186 struct target *target = armv7m_reg->target;
187 struct arm *arm = target_to_arm(target);
188
189 if (target->state != TARGET_HALTED)
190 return ERROR_TARGET_NOT_HALTED;
191
192 retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode);
193
194 return retval;
195 }
196
197 static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
198 {
199 struct arm_reg *armv7m_reg = reg->arch_info;
200 struct target *target = armv7m_reg->target;
201
202 if (target->state != TARGET_HALTED)
203 return ERROR_TARGET_NOT_HALTED;
204
205 buf_cpy(buf, reg->value, reg->size);
206 reg->dirty = 1;
207 reg->valid = 1;
208
209 return ERROR_OK;
210 }
211
212 static int armv7m_read_core_reg(struct target *target, struct reg *r,
213 int num, enum arm_mode mode)
214 {
215 uint32_t reg_value;
216 int retval;
217 struct arm_reg *armv7m_core_reg;
218 struct armv7m_common *armv7m = target_to_armv7m(target);
219
220 assert(num < (int)armv7m->arm.core_cache->num_regs);
221
222 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
223
224 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
225 /* map D0..D15 to S0..S31 */
226 size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
227 retval = armv7m->load_core_reg_u32(target, regidx, &reg_value);
228 if (retval != ERROR_OK)
229 return retval;
230 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value,
231 0, 32, reg_value);
232 retval = armv7m->load_core_reg_u32(target, regidx + 1, &reg_value);
233 if (retval != ERROR_OK)
234 return retval;
235 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4,
236 0, 32, reg_value);
237 } else {
238 retval = armv7m->load_core_reg_u32(target,
239 armv7m_core_reg->num, &reg_value);
240 if (retval != ERROR_OK)
241 return retval;
242 buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
243 }
244
245 armv7m->arm.core_cache->reg_list[num].valid = 1;
246 armv7m->arm.core_cache->reg_list[num].dirty = 0;
247
248 return retval;
249 }
250
251 static int armv7m_write_core_reg(struct target *target, struct reg *r,
252 int num, enum arm_mode mode, uint8_t *value)
253 {
254 int retval;
255 struct arm_reg *armv7m_core_reg;
256 struct armv7m_common *armv7m = target_to_armv7m(target);
257
258 assert(num < (int)armv7m->arm.core_cache->num_regs);
259
260 armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
261
262 if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
263 /* map D0..D15 to S0..S31 */
264 size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
265
266 uint32_t t = buf_get_u32(value, 0, 32);
267 retval = armv7m->store_core_reg_u32(target, regidx, t);
268 if (retval != ERROR_OK)
269 goto out_error;
270
271 t = buf_get_u32(value + 4, 0, 32);
272 retval = armv7m->store_core_reg_u32(target, regidx + 1, t);
273 if (retval != ERROR_OK)
274 goto out_error;
275 } else {
276 uint32_t t = buf_get_u32(value, 0, 32);
277
278 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t);
279 retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t);
280 if (retval != ERROR_OK)
281 goto out_error;
282 }
283
284 armv7m->arm.core_cache->reg_list[num].valid = 1;
285 armv7m->arm.core_cache->reg_list[num].dirty = 0;
286
287 return ERROR_OK;
288
289 out_error:
290 LOG_ERROR("Error setting register");
291 armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
292 return ERROR_JTAG_DEVICE_ERROR;
293 }
294
295 /**
296 * Returns generic ARM userspace registers to GDB.
297 */
298 int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
299 int *reg_list_size, enum target_register_class reg_class)
300 {
301 struct armv7m_common *armv7m = target_to_armv7m(target);
302 int i;
303
304 if (reg_class == REG_CLASS_ALL)
305 *reg_list_size = armv7m->arm.core_cache->num_regs;
306 else
307 *reg_list_size = ARMV7M_NUM_CORE_REGS;
308
309 *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
310 if (*reg_list == NULL)
311 return ERROR_FAIL;
312
313 for (i = 0; i < *reg_list_size; i++)
314 (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
315
316 return ERROR_OK;
317 }
318
319 /** Runs a Thumb algorithm in the target. */
320 int armv7m_run_algorithm(struct target *target,
321 int num_mem_params, struct mem_param *mem_params,
322 int num_reg_params, struct reg_param *reg_params,
323 uint32_t entry_point, uint32_t exit_point,
324 int timeout_ms, void *arch_info)
325 {
326 int retval;
327
328 retval = armv7m_start_algorithm(target,
329 num_mem_params, mem_params,
330 num_reg_params, reg_params,
331 entry_point, exit_point,
332 arch_info);
333
334 if (retval == ERROR_OK)
335 retval = armv7m_wait_algorithm(target,
336 num_mem_params, mem_params,
337 num_reg_params, reg_params,
338 exit_point, timeout_ms,
339 arch_info);
340
341 return retval;
342 }
343
344 /** Starts a Thumb algorithm in the target. */
345 int armv7m_start_algorithm(struct target *target,
346 int num_mem_params, struct mem_param *mem_params,
347 int num_reg_params, struct reg_param *reg_params,
348 uint32_t entry_point, uint32_t exit_point,
349 void *arch_info)
350 {
351 struct armv7m_common *armv7m = target_to_armv7m(target);
352 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
353 enum arm_mode core_mode = armv7m->arm.core_mode;
354 int retval = ERROR_OK;
355
356 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
357 * at the exit point */
358
359 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
360 LOG_ERROR("current target isn't an ARMV7M target");
361 return ERROR_TARGET_INVALID;
362 }
363
364 if (target->state != TARGET_HALTED) {
365 LOG_WARNING("target not halted");
366 return ERROR_TARGET_NOT_HALTED;
367 }
368
369 /* refresh core register cache
370 * Not needed if core register cache is always consistent with target process state */
371 for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
372
373 armv7m_algorithm_info->context[i] = buf_get_u32(
374 armv7m->arm.core_cache->reg_list[i].value,
375 0,
376 32);
377 }
378
379 for (int i = 0; i < num_mem_params; i++) {
380 /* TODO: Write only out params */
381 retval = target_write_buffer(target, mem_params[i].address,
382 mem_params[i].size,
383 mem_params[i].value);
384 if (retval != ERROR_OK)
385 return retval;
386 }
387
388 for (int i = 0; i < num_reg_params; i++) {
389 struct reg *reg =
390 register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
391 /* uint32_t regvalue; */
392
393 if (!reg) {
394 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
395 return ERROR_COMMAND_SYNTAX_ERROR;
396 }
397
398 if (reg->size != reg_params[i].size) {
399 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
400 reg_params[i].reg_name);
401 return ERROR_COMMAND_SYNTAX_ERROR;
402 }
403
404 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
405 armv7m_set_core_reg(reg, reg_params[i].value);
406 }
407
408 if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
409 armv7m_algorithm_info->core_mode != core_mode) {
410
411 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
412 if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
413 armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
414 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
415 }
416
417 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
418 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
419 0, 1, armv7m_algorithm_info->core_mode);
420 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
421 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
422 }
423
424 /* save previous core mode */
425 armv7m_algorithm_info->core_mode = core_mode;
426
427 retval = target_resume(target, 0, entry_point, 1, 1);
428
429 return retval;
430 }
431
432 /** Waits for an algorithm in the target. */
433 int armv7m_wait_algorithm(struct target *target,
434 int num_mem_params, struct mem_param *mem_params,
435 int num_reg_params, struct reg_param *reg_params,
436 uint32_t exit_point, int timeout_ms,
437 void *arch_info)
438 {
439 struct armv7m_common *armv7m = target_to_armv7m(target);
440 struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
441 int retval = ERROR_OK;
442 uint32_t pc;
443
444 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
445 * at the exit point */
446
447 if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
448 LOG_ERROR("current target isn't an ARMV7M target");
449 return ERROR_TARGET_INVALID;
450 }
451
452 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
453 /* If the target fails to halt due to the breakpoint, force a halt */
454 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
455 retval = target_halt(target);
456 if (retval != ERROR_OK)
457 return retval;
458 retval = target_wait_state(target, TARGET_HALTED, 500);
459 if (retval != ERROR_OK)
460 return retval;
461 return ERROR_TARGET_TIMEOUT;
462 }
463
464 armv7m->load_core_reg_u32(target, 15, &pc);
465 if (exit_point && (pc != exit_point)) {
466 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
467 pc,
468 exit_point);
469 return ERROR_TARGET_TIMEOUT;
470 }
471
472 /* Read memory values to mem_params[] */
473 for (int i = 0; i < num_mem_params; i++) {
474 if (mem_params[i].direction != PARAM_OUT) {
475 retval = target_read_buffer(target, mem_params[i].address,
476 mem_params[i].size,
477 mem_params[i].value);
478 if (retval != ERROR_OK)
479 return retval;
480 }
481 }
482
483 /* Copy core register values to reg_params[] */
484 for (int i = 0; i < num_reg_params; i++) {
485 if (reg_params[i].direction != PARAM_OUT) {
486 struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
487 reg_params[i].reg_name,
488 0);
489
490 if (!reg) {
491 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
492 return ERROR_COMMAND_SYNTAX_ERROR;
493 }
494
495 if (reg->size != reg_params[i].size) {
496 LOG_ERROR(
497 "BUG: register '%s' size doesn't match reg_params[i].size",
498 reg_params[i].reg_name);
499 return ERROR_COMMAND_SYNTAX_ERROR;
500 }
501
502 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
503 }
504 }
505
506 for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
507 uint32_t regvalue;
508 regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
509 if (regvalue != armv7m_algorithm_info->context[i]) {
510 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
511 armv7m->arm.core_cache->reg_list[i].name,
512 armv7m_algorithm_info->context[i]);
513 buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
514 0, 32, armv7m_algorithm_info->context[i]);
515 armv7m->arm.core_cache->reg_list[i].valid = 1;
516 armv7m->arm.core_cache->reg_list[i].dirty = 1;
517 }
518 }
519
520 /* restore previous core mode */
521 if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
522 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
523 buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
524 0, 1, armv7m_algorithm_info->core_mode);
525 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
526 armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
527 }
528
529 armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
530
531 return retval;
532 }
533
534 /** Logs summary of ARMv7-M state for a halted target. */
535 int armv7m_arch_state(struct target *target)
536 {
537 struct armv7m_common *armv7m = target_to_armv7m(target);
538 struct arm *arm = &armv7m->arm;
539 uint32_t ctrl, sp;
540
541 ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
542 sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
543
544 LOG_USER("target halted due to %s, current mode: %s %s\n"
545 "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
546 debug_reason_name(target),
547 arm_mode_name(arm->core_mode),
548 armv7m_exception_string(armv7m->exception_number),
549 buf_get_u32(arm->cpsr->value, 0, 32),
550 buf_get_u32(arm->pc->value, 0, 32),
551 (ctrl & 0x02) ? 'p' : 'm',
552 sp,
553 arm->is_semihosting ? ", semihosting" : "");
554
555 return ERROR_OK;
556 }
557
558 static const struct reg_arch_type armv7m_reg_type = {
559 .get = armv7m_get_core_reg,
560 .set = armv7m_set_core_reg,
561 };
562
563 /** Builds cache of architecturally defined registers. */
564 struct reg_cache *armv7m_build_reg_cache(struct target *target)
565 {
566 struct armv7m_common *armv7m = target_to_armv7m(target);
567 struct arm *arm = &armv7m->arm;
568 int num_regs = ARMV7M_NUM_REGS;
569 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
570 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
571 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
572 struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
573 struct reg_feature *feature;
574 int i;
575
576 /* Build the process context cache */
577 cache->name = "arm v7m registers";
578 cache->next = NULL;
579 cache->reg_list = reg_list;
580 cache->num_regs = num_regs;
581 (*cache_p) = cache;
582
583 for (i = 0; i < num_regs; i++) {
584 arch_info[i].num = armv7m_regs[i].id;
585 arch_info[i].target = target;
586 arch_info[i].arm = arm;
587
588 reg_list[i].name = armv7m_regs[i].name;
589 reg_list[i].size = armv7m_regs[i].bits;
590 size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8);
591 if (storage_size < 4)
592 storage_size = 4;
593 reg_list[i].value = calloc(1, storage_size);
594 reg_list[i].dirty = 0;
595 reg_list[i].valid = 0;
596 reg_list[i].type = &armv7m_reg_type;
597 reg_list[i].arch_info = &arch_info[i];
598
599 reg_list[i].group = armv7m_regs[i].group;
600 reg_list[i].number = i;
601 reg_list[i].exist = true;
602 reg_list[i].caller_save = true; /* gdb defaults to true */
603
604 feature = calloc(1, sizeof(struct reg_feature));
605 if (feature) {
606 feature->name = armv7m_regs[i].feature;
607 reg_list[i].feature = feature;
608 } else
609 LOG_ERROR("unable to allocate feature list");
610
611 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
612 if (reg_list[i].reg_data_type)
613 reg_list[i].reg_data_type->type = armv7m_regs[i].type;
614 else
615 LOG_ERROR("unable to allocate reg type list");
616 }
617
618 arm->cpsr = reg_list + ARMV7M_xPSR;
619 arm->pc = reg_list + ARMV7M_PC;
620 arm->core_cache = cache;
621
622 return cache;
623 }
624
625 void armv7m_free_reg_cache(struct target *target)
626 {
627 struct armv7m_common *armv7m = target_to_armv7m(target);
628 struct arm *arm = &armv7m->arm;
629 struct reg_cache *cache;
630 struct reg *reg;
631 unsigned int i;
632
633 cache = arm->core_cache;
634
635 if (!cache)
636 return;
637
638 for (i = 0; i < cache->num_regs; i++) {
639 reg = &cache->reg_list[i];
640
641 free(reg->feature);
642 free(reg->reg_data_type);
643 free(reg->value);
644 }
645
646 free(cache->reg_list[0].arch_info);
647 free(cache->reg_list);
648 free(cache);
649
650 arm->core_cache = NULL;
651 }
652
653 static int armv7m_setup_semihosting(struct target *target, int enable)
654 {
655 /* nothing todo for armv7m */
656 return ERROR_OK;
657 }
658
659 /** Sets up target as a generic ARMv7-M core */
660 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
661 {
662 struct arm *arm = &armv7m->arm;
663
664 armv7m->common_magic = ARMV7M_COMMON_MAGIC;
665 armv7m->fp_feature = FP_NONE;
666 armv7m->trace_config.trace_bus_id = 1;
667 /* Enable stimulus port #0 by default */
668 armv7m->trace_config.itm_ter[0] = 1;
669
670 arm->core_type = ARM_MODE_THREAD;
671 arm->arch_info = armv7m;
672 arm->setup_semihosting = armv7m_setup_semihosting;
673
674 arm->read_core_reg = armv7m_read_core_reg;
675 arm->write_core_reg = armv7m_write_core_reg;
676
677 return arm_init_arch_info(target, arm);
678 }
679
680 /** Generates a CRC32 checksum of a memory region. */
681 int armv7m_checksum_memory(struct target *target,
682 uint32_t address, uint32_t count, uint32_t *checksum)
683 {
684 struct working_area *crc_algorithm;
685 struct armv7m_algorithm armv7m_info;
686 struct reg_param reg_params[2];
687 int retval;
688
689 /* see contrib/loaders/checksum/armv7m_crc.s for src */
690
691 static const uint8_t cortex_m_crc_code[] = {
692 /* main: */
693 0x02, 0x46, /* mov r2, r0 */
694 0x00, 0x20, /* movs r0, #0 */
695 0xC0, 0x43, /* mvns r0, r0 */
696 0x0A, 0x4E, /* ldr r6, CRC32XOR */
697 0x0B, 0x46, /* mov r3, r1 */
698 0x00, 0x24, /* movs r4, #0 */
699 0x0D, 0xE0, /* b ncomp */
700 /* nbyte: */
701 0x11, 0x5D, /* ldrb r1, [r2, r4] */
702 0x09, 0x06, /* lsls r1, r1, #24 */
703 0x48, 0x40, /* eors r0, r0, r1 */
704 0x00, 0x25, /* movs r5, #0 */
705 /* loop: */
706 0x00, 0x28, /* cmp r0, #0 */
707 0x02, 0xDA, /* bge notset */
708 0x40, 0x00, /* lsls r0, r0, #1 */
709 0x70, 0x40, /* eors r0, r0, r6 */
710 0x00, 0xE0, /* b cont */
711 /* notset: */
712 0x40, 0x00, /* lsls r0, r0, #1 */
713 /* cont: */
714 0x01, 0x35, /* adds r5, r5, #1 */
715 0x08, 0x2D, /* cmp r5, #8 */
716 0xF6, 0xD1, /* bne loop */
717 0x01, 0x34, /* adds r4, r4, #1 */
718 /* ncomp: */
719 0x9C, 0x42, /* cmp r4, r3 */
720 0xEF, 0xD1, /* bne nbyte */
721 0x00, 0xBE, /* bkpt #0 */
722 0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */
723 };
724
725 retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
726 if (retval != ERROR_OK)
727 return retval;
728
729 retval = target_write_buffer(target, crc_algorithm->address,
730 sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code);
731 if (retval != ERROR_OK)
732 goto cleanup;
733
734 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
735 armv7m_info.core_mode = ARM_MODE_THREAD;
736
737 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
738 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
739
740 buf_set_u32(reg_params[0].value, 0, 32, address);
741 buf_set_u32(reg_params[1].value, 0, 32, count);
742
743 int timeout = 20000 * (1 + (count / (1024 * 1024)));
744
745 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
746 crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
747 timeout, &armv7m_info);
748
749 if (retval == ERROR_OK)
750 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
751 else
752 LOG_ERROR("error executing cortex_m crc algorithm");
753
754 destroy_reg_param(&reg_params[0]);
755 destroy_reg_param(&reg_params[1]);
756
757 cleanup:
758 target_free_working_area(target, crc_algorithm);
759
760 return retval;
761 }
762
763 /** Checks whether a memory region is zeroed. */
764 int armv7m_blank_check_memory(struct target *target,
765 uint32_t address, uint32_t count, uint32_t *blank)
766 {
767 struct working_area *erase_check_algorithm;
768 struct reg_param reg_params[3];
769 struct armv7m_algorithm armv7m_info;
770 int retval;
771
772 static const uint8_t erase_check_code[] = {
773 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
774 };
775
776 /* make sure we have a working area */
777 if (target_alloc_working_area(target, sizeof(erase_check_code),
778 &erase_check_algorithm) != ERROR_OK)
779 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
780
781 retval = target_write_buffer(target, erase_check_algorithm->address,
782 sizeof(erase_check_code), (uint8_t *)erase_check_code);
783 if (retval != ERROR_OK)
784 return retval;
785
786 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
787 armv7m_info.core_mode = ARM_MODE_THREAD;
788
789 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
790 buf_set_u32(reg_params[0].value, 0, 32, address);
791
792 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
793 buf_set_u32(reg_params[1].value, 0, 32, count);
794
795 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
796 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
797
798 retval = target_run_algorithm(target,
799 0,
800 NULL,
801 3,
802 reg_params,
803 erase_check_algorithm->address,
804 erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
805 10000,
806 &armv7m_info);
807
808 if (retval == ERROR_OK)
809 *blank = buf_get_u32(reg_params[2].value, 0, 32);
810
811 destroy_reg_param(&reg_params[0]);
812 destroy_reg_param(&reg_params[1]);
813 destroy_reg_param(&reg_params[2]);
814
815 target_free_working_area(target, erase_check_algorithm);
816
817 return retval;
818 }
819
820 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
821 {
822 struct armv7m_common *armv7m = target_to_armv7m(target);
823 struct reg *r = armv7m->arm.pc;
824 bool result = false;
825
826
827 /* if we halted last time due to a bkpt instruction
828 * then we have to manually step over it, otherwise
829 * the core will break again */
830
831 if (target->debug_reason == DBG_REASON_BREAKPOINT) {
832 uint16_t op;
833 uint32_t pc = buf_get_u32(r->value, 0, 32);
834
835 pc &= ~1;
836 if (target_read_u16(target, pc, &op) == ERROR_OK) {
837 if ((op & 0xFF00) == 0xBE00) {
838 pc = buf_get_u32(r->value, 0, 32) + 2;
839 buf_set_u32(r->value, 0, 32, pc);
840 r->dirty = true;
841 r->valid = true;
842 result = true;
843 LOG_DEBUG("Skipping over BKPT instruction");
844 }
845 }
846 }
847
848 if (inst_found)
849 *inst_found = result;
850
851 return ERROR_OK;
852 }
853
854 const struct command_registration armv7m_command_handlers[] = {
855 {
856 .chain = arm_command_handlers,
857 },
858 {
859 .chain = dap_command_handlers,
860 },
861 COMMAND_REGISTRATION_DONE
862 };

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)