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

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)