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

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)