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

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)