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

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)