1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2006 by Magnus Lundin *
8 * Copyright (C) 2008 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
11 * Copyright (C) 2007,2008 Øyvind Harboe *
12 * oyvind.harboe@zylin.com *
14 * Copyright (C) 2018 by Liviu Ionescu *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
22 * This program is distributed in the hope that it will be useful, *
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
25 * GNU General Public License for more details. *
27 * You should have received a copy of the GNU General Public License *
28 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
30 * ARMv7-M Architecture, Application Level Reference Manual *
31 * ARM DDI 0405C (September 2008) *
33 ***************************************************************************/
39 #include "breakpoints.h"
41 #include "algorithm.h"
43 #include "semihosting_common.h"
46 #define _DEBUG_INSTRUCTION_EXECUTION_
49 static const char * const armv7m_exception_strings
[] = {
50 "", "Reset", "NMI", "HardFault",
51 "MemManage", "BusFault", "UsageFault", "SecureFault",
52 "RESERVED", "RESERVED", "RESERVED", "SVCall",
53 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
56 /* PSP is used in some thread modes */
57 const int armv7m_psp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
58 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
59 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
60 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
61 ARMV7M_R12
, ARMV7M_PSP
, ARMV7M_R14
, ARMV7M_PC
,
65 /* MSP is used in handler and some thread modes */
66 const int armv7m_msp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
67 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
68 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
69 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
70 ARMV7M_R12
, ARMV7M_MSP
, ARMV7M_R14
, ARMV7M_PC
,
75 * These registers are not memory-mapped. The ARMv7-M profile includes
76 * memory mapped registers too, such as for the NVIC (interrupt controller)
77 * and SysTick (timer) modules; those can mostly be treated as peripherals.
79 * The ARMv6-M profile is almost identical in this respect, except that it
80 * doesn't include basepri or faultmask registers.
90 { ARMV7M_R0
, "r0", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
91 { ARMV7M_R1
, "r1", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
92 { ARMV7M_R2
, "r2", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
93 { ARMV7M_R3
, "r3", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R4
, "r4", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R5
, "r5", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R6
, "r6", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R7
, "r7", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R8
, "r8", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_R9
, "r9", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_R10
, "r10", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
101 { ARMV7M_R11
, "r11", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_R12
, "r12", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
103 { ARMV7M_R13
, "sp", 32, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
104 { ARMV7M_R14
, "lr", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
105 { ARMV7M_PC
, "pc", 32, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
106 { ARMV7M_xPSR
, "xPSR", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
108 { ARMV7M_MSP
, "msp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
109 { ARMV7M_PSP
, "psp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
111 { ARMV7M_PRIMASK
, "primask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
112 { ARMV7M_BASEPRI
, "basepri", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
113 { ARMV7M_FAULTMASK
, "faultmask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
114 { ARMV7M_CONTROL
, "control", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
116 { ARMV7M_D0
, "d0", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
117 { ARMV7M_D1
, "d1", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
118 { ARMV7M_D2
, "d2", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
119 { ARMV7M_D3
, "d3", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
120 { ARMV7M_D4
, "d4", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
121 { ARMV7M_D5
, "d5", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
122 { ARMV7M_D6
, "d6", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
123 { ARMV7M_D7
, "d7", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
124 { ARMV7M_D8
, "d8", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
125 { ARMV7M_D9
, "d9", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
126 { ARMV7M_D10
, "d10", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
127 { ARMV7M_D11
, "d11", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
128 { ARMV7M_D12
, "d12", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
129 { ARMV7M_D13
, "d13", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
130 { ARMV7M_D14
, "d14", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
131 { ARMV7M_D15
, "d15", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
133 { ARMV7M_FPSCR
, "fpscr", 32, REG_TYPE_INT
, "float", "org.gnu.gdb.arm.vfp" },
136 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
139 * Restores target context using the cache of core registers set up
140 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
142 int armv7m_restore_context(struct target
*target
)
145 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
146 struct reg_cache
*cache
= armv7m
->arm
.core_cache
;
150 if (armv7m
->pre_restore_context
)
151 armv7m
->pre_restore_context(target
);
153 for (i
= cache
->num_regs
- 1; i
>= 0; i
--) {
154 if (cache
->reg_list
[i
].dirty
) {
155 armv7m
->arm
.write_core_reg(target
, &cache
->reg_list
[i
], i
,
156 ARM_MODE_ANY
, cache
->reg_list
[i
].value
);
163 /* Core state functions */
166 * Maps ISR number (from xPSR) to name.
167 * Note that while names and meanings for the first sixteen are standardized
168 * (with zero not a true exception), external interrupts are only numbered.
169 * They are assigned by vendors, which generally assign different numbers to
170 * peripherals (such as UART0 or a USB peripheral controller).
172 const char *armv7m_exception_string(int number
)
174 static char enamebuf
[32];
176 if ((number
< 0) | (number
> 511))
177 return "Invalid exception";
179 return armv7m_exception_strings
[number
];
180 sprintf(enamebuf
, "External Interrupt(%i)", number
- 16);
184 static int armv7m_get_core_reg(struct reg
*reg
)
187 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
188 struct target
*target
= armv7m_reg
->target
;
189 struct arm
*arm
= target_to_arm(target
);
191 if (target
->state
!= TARGET_HALTED
)
192 return ERROR_TARGET_NOT_HALTED
;
194 retval
= arm
->read_core_reg(target
, reg
, reg
->number
, arm
->core_mode
);
199 static int armv7m_set_core_reg(struct reg
*reg
, uint8_t *buf
)
201 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
202 struct target
*target
= armv7m_reg
->target
;
204 if (target
->state
!= TARGET_HALTED
)
205 return ERROR_TARGET_NOT_HALTED
;
207 buf_cpy(buf
, reg
->value
, reg
->size
);
214 static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id
)
216 switch (arm_reg_id
) {
217 case ARMV7M_R0
... ARMV7M_R14
:
222 /* NOTE: we "know" here that the register identifiers
223 * match the Cortex-M DCRSR.REGSEL selectors values
224 * for R0..R14, PC, xPSR, MSP, and PSP.
229 return ARMV7M_REGSEL_FPSCR
;
231 case ARMV7M_D0
... ARMV7M_D15
:
232 return ARMV7M_REGSEL_S0
+ 2 * (arm_reg_id
- ARMV7M_D0
);
234 /* TODO: remove. This is temporary hack until packing/unpacking
235 * of special regs is moved to armv7m.c */
238 case ARMV7M_FAULTMASK
:
243 LOG_ERROR("Bad register ID %u", arm_reg_id
);
248 static int armv7m_read_core_reg(struct target
*target
, struct reg
*r
,
249 int num
, enum arm_mode mode
)
253 struct arm_reg
*armv7m_core_reg
;
254 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
256 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
257 assert(num
== (int)r
->number
);
259 armv7m_core_reg
= armv7m
->arm
.core_cache
->reg_list
[num
].arch_info
;
261 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
263 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
264 /* map D0..D15 to S0..S31 */
265 retval
= armv7m
->load_core_reg_u32(target
, regsel
, ®_value
);
266 if (retval
!= ERROR_OK
)
268 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
,
270 retval
= armv7m
->load_core_reg_u32(target
, regsel
+ 1, ®_value
);
271 if (retval
!= ERROR_OK
)
273 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
+ 4,
276 retval
= armv7m
->load_core_reg_u32(target
,
278 if (retval
!= ERROR_OK
)
280 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
, 0, 32, reg_value
);
283 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= true;
284 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= false;
289 static int armv7m_write_core_reg(struct target
*target
, struct reg
*r
,
290 int num
, enum arm_mode mode
, uint8_t *value
)
293 struct arm_reg
*armv7m_core_reg
;
294 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
296 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
297 assert(num
== (int)r
->number
);
299 armv7m_core_reg
= armv7m
->arm
.core_cache
->reg_list
[num
].arch_info
;
301 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
303 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
304 /* map D0..D15 to S0..S31 */
305 uint32_t t
= buf_get_u32(value
, 0, 32);
306 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
307 if (retval
!= ERROR_OK
)
310 t
= buf_get_u32(value
+ 4, 0, 32);
311 retval
= armv7m
->store_core_reg_u32(target
, regsel
+ 1, t
);
312 if (retval
!= ERROR_OK
)
315 uint32_t t
= buf_get_u32(value
, 0, 32);
317 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", num
, t
);
318 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
319 if (retval
!= ERROR_OK
)
323 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= true;
324 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= false;
329 LOG_ERROR("Error setting register");
330 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= armv7m
->arm
.core_cache
->reg_list
[num
].valid
;
331 return ERROR_JTAG_DEVICE_ERROR
;
335 * Returns generic ARM userspace registers to GDB.
337 int armv7m_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
338 int *reg_list_size
, enum target_register_class reg_class
)
340 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
343 if (reg_class
== REG_CLASS_ALL
)
344 size
= armv7m
->arm
.core_cache
->num_regs
;
346 size
= ARMV7M_NUM_CORE_REGS
;
348 *reg_list
= malloc(sizeof(struct reg
*) * size
);
349 if (*reg_list
== NULL
)
352 for (i
= 0; i
< size
; i
++)
353 (*reg_list
)[i
] = &armv7m
->arm
.core_cache
->reg_list
[i
];
355 *reg_list_size
= size
;
360 /** Runs a Thumb algorithm in the target. */
361 int armv7m_run_algorithm(struct target
*target
,
362 int num_mem_params
, struct mem_param
*mem_params
,
363 int num_reg_params
, struct reg_param
*reg_params
,
364 target_addr_t entry_point
, target_addr_t exit_point
,
365 int timeout_ms
, void *arch_info
)
369 retval
= armv7m_start_algorithm(target
,
370 num_mem_params
, mem_params
,
371 num_reg_params
, reg_params
,
372 entry_point
, exit_point
,
375 if (retval
== ERROR_OK
)
376 retval
= armv7m_wait_algorithm(target
,
377 num_mem_params
, mem_params
,
378 num_reg_params
, reg_params
,
379 exit_point
, timeout_ms
,
385 /** Starts a Thumb algorithm in the target. */
386 int armv7m_start_algorithm(struct target
*target
,
387 int num_mem_params
, struct mem_param
*mem_params
,
388 int num_reg_params
, struct reg_param
*reg_params
,
389 target_addr_t entry_point
, target_addr_t exit_point
,
392 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
393 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
394 enum arm_mode core_mode
= armv7m
->arm
.core_mode
;
395 int retval
= ERROR_OK
;
397 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
398 * at the exit point */
400 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
401 LOG_ERROR("current target isn't an ARMV7M target");
402 return ERROR_TARGET_INVALID
;
405 if (target
->state
!= TARGET_HALTED
) {
406 LOG_WARNING("target not halted");
407 return ERROR_TARGET_NOT_HALTED
;
410 /* refresh core register cache
411 * Not needed if core register cache is always consistent with target process state */
412 for (unsigned i
= 0; i
< armv7m
->arm
.core_cache
->num_regs
; i
++) {
414 armv7m_algorithm_info
->context
[i
] = buf_get_u32(
415 armv7m
->arm
.core_cache
->reg_list
[i
].value
,
420 for (int i
= 0; i
< num_mem_params
; i
++) {
421 if (mem_params
[i
].direction
== PARAM_IN
)
423 retval
= target_write_buffer(target
, mem_params
[i
].address
,
425 mem_params
[i
].value
);
426 if (retval
!= ERROR_OK
)
430 for (int i
= 0; i
< num_reg_params
; i
++) {
431 if (reg_params
[i
].direction
== PARAM_IN
)
435 register_get_by_name(armv7m
->arm
.core_cache
, reg_params
[i
].reg_name
, 0);
436 /* uint32_t regvalue; */
439 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
440 return ERROR_COMMAND_SYNTAX_ERROR
;
443 if (reg
->size
!= reg_params
[i
].size
) {
444 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
445 reg_params
[i
].reg_name
);
446 return ERROR_COMMAND_SYNTAX_ERROR
;
449 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
450 armv7m_set_core_reg(reg
, reg_params
[i
].value
);
455 * Ensure xPSR.T is set to avoid trying to run things in arm
456 * (non-thumb) mode, which armv7m does not support.
458 * We do this by setting the entirety of xPSR, which should
459 * remove all the unknowns about xPSR state.
461 * Because xPSR.T is populated on reset from the vector table,
462 * it might be 0 if the vector table has "bad" data in it.
464 struct reg
*reg
= &armv7m
->arm
.core_cache
->reg_list
[ARMV7M_xPSR
];
465 buf_set_u32(reg
->value
, 0, 32, 0x01000000);
470 if (armv7m_algorithm_info
->core_mode
!= ARM_MODE_ANY
&&
471 armv7m_algorithm_info
->core_mode
!= core_mode
) {
473 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
474 if (armv7m_algorithm_info
->core_mode
== ARM_MODE_HANDLER
) {
475 armv7m_algorithm_info
->core_mode
= ARM_MODE_THREAD
;
476 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
479 LOG_DEBUG("setting 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
= true;
483 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
486 /* save previous core mode */
487 armv7m_algorithm_info
->core_mode
= core_mode
;
489 retval
= target_resume(target
, 0, entry_point
, 1, 1);
494 /** Waits for an algorithm in the target. */
495 int armv7m_wait_algorithm(struct target
*target
,
496 int num_mem_params
, struct mem_param
*mem_params
,
497 int num_reg_params
, struct reg_param
*reg_params
,
498 target_addr_t exit_point
, int timeout_ms
,
501 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
502 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
503 int retval
= ERROR_OK
;
505 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
506 * at the exit point */
508 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
509 LOG_ERROR("current target isn't an ARMV7M target");
510 return ERROR_TARGET_INVALID
;
513 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
514 /* If the target fails to halt due to the breakpoint, force a halt */
515 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
516 retval
= target_halt(target
);
517 if (retval
!= ERROR_OK
)
519 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
520 if (retval
!= ERROR_OK
)
522 return ERROR_TARGET_TIMEOUT
;
526 /* PC value has been cached in cortex_m_debug_entry() */
527 uint32_t pc
= buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32);
528 if (pc
!= exit_point
) {
529 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
", expected 0x%" TARGET_PRIxADDR
,
531 return ERROR_TARGET_ALGO_EXIT
;
535 /* Read memory values to mem_params[] */
536 for (int i
= 0; i
< num_mem_params
; i
++) {
537 if (mem_params
[i
].direction
!= PARAM_OUT
) {
538 retval
= target_read_buffer(target
, mem_params
[i
].address
,
540 mem_params
[i
].value
);
541 if (retval
!= ERROR_OK
)
546 /* Copy core register values to reg_params[] */
547 for (int i
= 0; i
< num_reg_params
; i
++) {
548 if (reg_params
[i
].direction
!= PARAM_OUT
) {
549 struct reg
*reg
= register_get_by_name(armv7m
->arm
.core_cache
,
550 reg_params
[i
].reg_name
,
554 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
555 return ERROR_COMMAND_SYNTAX_ERROR
;
558 if (reg
->size
!= reg_params
[i
].size
) {
560 "BUG: register '%s' size doesn't match reg_params[i].size",
561 reg_params
[i
].reg_name
);
562 return ERROR_COMMAND_SYNTAX_ERROR
;
565 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
569 for (int i
= armv7m
->arm
.core_cache
->num_regs
- 1; i
>= 0; i
--) {
571 regvalue
= buf_get_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
, 0, 32);
572 if (regvalue
!= armv7m_algorithm_info
->context
[i
]) {
573 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
574 armv7m
->arm
.core_cache
->reg_list
[i
].name
,
575 armv7m_algorithm_info
->context
[i
]);
576 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
,
577 0, 32, armv7m_algorithm_info
->context
[i
]);
578 armv7m
->arm
.core_cache
->reg_list
[i
].valid
= true;
579 armv7m
->arm
.core_cache
->reg_list
[i
].dirty
= true;
583 /* restore previous core mode */
584 if (armv7m_algorithm_info
->core_mode
!= armv7m
->arm
.core_mode
) {
585 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
586 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
587 0, 1, armv7m_algorithm_info
->core_mode
);
588 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
589 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
592 armv7m
->arm
.core_mode
= armv7m_algorithm_info
->core_mode
;
597 /** Logs summary of ARMv7-M state for a halted target. */
598 int armv7m_arch_state(struct target
*target
)
600 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
601 struct arm
*arm
= &armv7m
->arm
;
604 /* avoid filling log waiting for fileio reply */
605 if (target
->semihosting
&& target
->semihosting
->hit_fileio
)
608 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
609 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
611 LOG_USER("target halted due to %s, current mode: %s %s\n"
612 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s%s",
613 debug_reason_name(target
),
614 arm_mode_name(arm
->core_mode
),
615 armv7m_exception_string(armv7m
->exception_number
),
616 buf_get_u32(arm
->cpsr
->value
, 0, 32),
617 buf_get_u32(arm
->pc
->value
, 0, 32),
618 (ctrl
& 0x02) ? 'p' : 'm',
620 (target
->semihosting
&& target
->semihosting
->is_active
) ? ", semihosting" : "",
621 (target
->semihosting
&& target
->semihosting
->is_fileio
) ? " fileio" : "");
626 static const struct reg_arch_type armv7m_reg_type
= {
627 .get
= armv7m_get_core_reg
,
628 .set
= armv7m_set_core_reg
,
631 /** Builds cache of architecturally defined registers. */
632 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
634 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
635 struct arm
*arm
= &armv7m
->arm
;
636 int num_regs
= ARMV7M_NUM_REGS
;
637 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
638 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
639 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
640 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
641 struct reg_feature
*feature
;
644 /* Build the process context cache */
645 cache
->name
= "arm v7m registers";
647 cache
->reg_list
= reg_list
;
648 cache
->num_regs
= num_regs
;
651 for (i
= 0; i
< num_regs
; i
++) {
652 arch_info
[i
].num
= armv7m_regs
[i
].id
;
653 arch_info
[i
].target
= target
;
654 arch_info
[i
].arm
= arm
;
656 reg_list
[i
].name
= armv7m_regs
[i
].name
;
657 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
658 size_t storage_size
= DIV_ROUND_UP(armv7m_regs
[i
].bits
, 8);
659 if (storage_size
< 4)
661 reg_list
[i
].value
= calloc(1, storage_size
);
662 reg_list
[i
].dirty
= false;
663 reg_list
[i
].valid
= false;
664 reg_list
[i
].type
= &armv7m_reg_type
;
665 reg_list
[i
].arch_info
= &arch_info
[i
];
667 reg_list
[i
].group
= armv7m_regs
[i
].group
;
668 reg_list
[i
].number
= i
;
669 reg_list
[i
].exist
= true;
670 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
672 feature
= calloc(1, sizeof(struct reg_feature
));
674 feature
->name
= armv7m_regs
[i
].feature
;
675 reg_list
[i
].feature
= feature
;
677 LOG_ERROR("unable to allocate feature list");
679 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
680 if (reg_list
[i
].reg_data_type
)
681 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
683 LOG_ERROR("unable to allocate reg type list");
686 arm
->cpsr
= reg_list
+ ARMV7M_xPSR
;
687 arm
->pc
= reg_list
+ ARMV7M_PC
;
688 arm
->core_cache
= cache
;
693 void armv7m_free_reg_cache(struct target
*target
)
695 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
696 struct arm
*arm
= &armv7m
->arm
;
697 struct reg_cache
*cache
;
701 cache
= arm
->core_cache
;
706 for (i
= 0; i
< cache
->num_regs
; i
++) {
707 reg
= &cache
->reg_list
[i
];
710 free(reg
->reg_data_type
);
714 free(cache
->reg_list
[0].arch_info
);
715 free(cache
->reg_list
);
718 arm
->core_cache
= NULL
;
721 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
723 /* nothing todo for armv7m */
727 /** Sets up target as a generic ARMv7-M core */
728 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
730 struct arm
*arm
= &armv7m
->arm
;
732 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
733 armv7m
->fp_feature
= FP_NONE
;
734 armv7m
->trace_config
.trace_bus_id
= 1;
735 /* Enable stimulus port #0 by default */
736 armv7m
->trace_config
.itm_ter
[0] = 1;
738 arm
->core_type
= ARM_CORE_TYPE_M_PROFILE
;
739 arm
->arch_info
= armv7m
;
740 arm
->setup_semihosting
= armv7m_setup_semihosting
;
742 arm
->read_core_reg
= armv7m_read_core_reg
;
743 arm
->write_core_reg
= armv7m_write_core_reg
;
745 return arm_init_arch_info(target
, arm
);
748 /** Generates a CRC32 checksum of a memory region. */
749 int armv7m_checksum_memory(struct target
*target
,
750 target_addr_t address
, uint32_t count
, uint32_t *checksum
)
752 struct working_area
*crc_algorithm
;
753 struct armv7m_algorithm armv7m_info
;
754 struct reg_param reg_params
[2];
757 static const uint8_t cortex_m_crc_code
[] = {
758 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
761 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
762 if (retval
!= ERROR_OK
)
765 retval
= target_write_buffer(target
, crc_algorithm
->address
,
766 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
767 if (retval
!= ERROR_OK
)
770 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
771 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
773 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
774 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
776 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
777 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
779 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
781 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
782 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
783 timeout
, &armv7m_info
);
785 if (retval
== ERROR_OK
)
786 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
788 LOG_ERROR("error executing cortex_m crc algorithm");
790 destroy_reg_param(®_params
[0]);
791 destroy_reg_param(®_params
[1]);
794 target_free_working_area(target
, crc_algorithm
);
799 /** Checks an array of memory regions whether they are erased. */
800 int armv7m_blank_check_memory(struct target
*target
,
801 struct target_memory_check_block
*blocks
, int num_blocks
, uint8_t erased_value
)
803 struct working_area
*erase_check_algorithm
;
804 struct working_area
*erase_check_params
;
805 struct reg_param reg_params
[2];
806 struct armv7m_algorithm armv7m_info
;
809 static bool timed_out
;
811 static const uint8_t erase_check_code
[] = {
812 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
815 const uint32_t code_size
= sizeof(erase_check_code
);
817 /* make sure we have a working area */
818 if (target_alloc_working_area(target
, code_size
,
819 &erase_check_algorithm
) != ERROR_OK
)
820 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
822 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
823 code_size
, erase_check_code
);
824 if (retval
!= ERROR_OK
)
827 /* prepare blocks array for algo */
836 uint32_t avail
= target_get_working_area_avail(target
);
837 int blocks_to_check
= avail
/ sizeof(struct algo_block
) - 1;
838 if (num_blocks
< blocks_to_check
)
839 blocks_to_check
= num_blocks
;
841 struct algo_block
*params
= malloc((blocks_to_check
+1)*sizeof(struct algo_block
));
842 if (params
== NULL
) {
848 uint32_t total_size
= 0;
849 for (i
= 0; i
< blocks_to_check
; i
++) {
850 total_size
+= blocks
[i
].size
;
851 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].size
),
852 blocks
[i
].size
/ sizeof(uint32_t));
853 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].address
),
856 target_buffer_set_u32(target
, (uint8_t *)&(params
[blocks_to_check
].size
), 0);
858 uint32_t param_size
= (blocks_to_check
+ 1) * sizeof(struct algo_block
);
859 if (target_alloc_working_area(target
, param_size
,
860 &erase_check_params
) != ERROR_OK
) {
861 retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
865 retval
= target_write_buffer(target
, erase_check_params
->address
,
866 param_size
, (uint8_t *)params
);
867 if (retval
!= ERROR_OK
)
870 uint32_t erased_word
= erased_value
| (erased_value
<< 8)
871 | (erased_value
<< 16) | (erased_value
<< 24);
873 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
874 TARGET_ADDR_FMT
, blocks_to_check
, erase_check_params
->address
);
876 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
877 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
879 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
880 buf_set_u32(reg_params
[0].value
, 0, 32, erase_check_params
->address
);
882 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
883 buf_set_u32(reg_params
[1].value
, 0, 32, erased_word
);
885 /* assume CPU clk at least 1 MHz */
886 int timeout
= (timed_out
? 30000 : 2000) + total_size
* 3 / 1000;
888 retval
= target_run_algorithm(target
,
890 ARRAY_SIZE(reg_params
), reg_params
,
891 erase_check_algorithm
->address
,
892 erase_check_algorithm
->address
+ (code_size
- 2),
896 timed_out
= retval
== ERROR_TARGET_TIMEOUT
;
897 if (retval
!= ERROR_OK
&& !timed_out
)
900 retval
= target_read_buffer(target
, erase_check_params
->address
,
901 param_size
, (uint8_t *)params
);
902 if (retval
!= ERROR_OK
)
905 for (i
= 0; i
< blocks_to_check
; i
++) {
906 uint32_t result
= target_buffer_get_u32(target
,
907 (uint8_t *)&(params
[i
].result
));
908 if (result
!= 0 && result
!= 1)
911 blocks
[i
].result
= result
;
914 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i
, num_blocks
-i
);
916 retval
= i
; /* return number of blocks really checked */
919 destroy_reg_param(®_params
[0]);
920 destroy_reg_param(®_params
[1]);
923 target_free_working_area(target
, erase_check_params
);
927 target_free_working_area(target
, erase_check_algorithm
);
932 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
934 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
935 struct reg
*r
= armv7m
->arm
.pc
;
939 /* if we halted last time due to a bkpt instruction
940 * then we have to manually step over it, otherwise
941 * the core will break again */
943 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
945 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
948 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
949 if ((op
& 0xFF00) == 0xBE00) {
950 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
951 buf_set_u32(r
->value
, 0, 32, pc
);
955 LOG_DEBUG("Skipping over BKPT instruction");
961 *inst_found
= result
;
966 const struct command_registration armv7m_command_handlers
[] = {
968 .chain
= arm_command_handlers
,
970 COMMAND_REGISTRATION_DONE
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)