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

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)