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

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)