1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) 2006 by Magnus Lundin *
10 * Copyright (C) 2008 by Spencer Oliver *
11 * spen@spen-soft.co.uk *
13 * Copyright (C) 2007,2008 Øyvind Harboe *
14 * oyvind.harboe@zylin.com *
16 * Copyright (C) 2018 by Liviu Ionescu *
19 * Copyright (C) 2019 by Tomas Vanek *
22 * ARMv7-M Architecture, Application Level Reference Manual *
23 * ARM DDI 0405C (September 2008) *
25 ***************************************************************************/
31 #include "breakpoints.h"
33 #include "algorithm.h"
35 #include "semihosting_common.h"
36 #include <helper/log.h>
37 #include <helper/binarybuffer.h>
40 #define _DEBUG_INSTRUCTION_EXECUTION_
43 static const char * const armv7m_exception_strings
[] = {
44 "", "Reset", "NMI", "HardFault",
45 "MemManage", "BusFault", "UsageFault", "SecureFault",
46 "RESERVED", "RESERVED", "RESERVED", "SVCall",
47 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
50 /* PSP is used in some thread modes */
51 const int armv7m_psp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
52 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
53 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
54 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
55 ARMV7M_R12
, ARMV7M_PSP
, ARMV7M_R14
, ARMV7M_PC
,
59 /* MSP is used in handler and some thread modes */
60 const int armv7m_msp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
61 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
62 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
63 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
64 ARMV7M_R12
, ARMV7M_MSP
, ARMV7M_R14
, ARMV7M_PC
,
69 * These registers are not memory-mapped. The ARMv7-M profile includes
70 * memory mapped registers too, such as for the NVIC (interrupt controller)
71 * and SysTick (timer) modules; those can mostly be treated as peripherals.
73 * The ARMv6-M profile is almost identical in this respect, except that it
74 * doesn't include basepri or faultmask registers.
84 { ARMV7M_R0
, "r0", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
85 { ARMV7M_R1
, "r1", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
86 { ARMV7M_R2
, "r2", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
87 { ARMV7M_R3
, "r3", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
88 { ARMV7M_R4
, "r4", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
89 { ARMV7M_R5
, "r5", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
90 { ARMV7M_R6
, "r6", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
91 { ARMV7M_R7
, "r7", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
92 { ARMV7M_R8
, "r8", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
93 { ARMV7M_R9
, "r9", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R10
, "r10", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R11
, "r11", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R12
, "r12", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R13
, "sp", 32, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R14
, "lr", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_PC
, "pc", 32, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_XPSR
, "xPSR", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_MSP
, "msp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
103 { ARMV7M_PSP
, "psp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
105 /* A working register for packing/unpacking special regs, hidden from gdb */
106 { ARMV7M_PMSK_BPRI_FLTMSK_CTRL
, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT
, NULL
, NULL
},
108 /* WARNING: If you use armv7m_write_core_reg() on one of 4 following
109 * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL
110 * cache only and are not flushed to CPU HW register.
111 * To trigger write to CPU HW register, add
112 * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,);
114 { ARMV7M_PRIMASK
, "primask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
115 { ARMV7M_BASEPRI
, "basepri", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
116 { ARMV7M_FAULTMASK
, "faultmask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
117 { ARMV7M_CONTROL
, "control", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
119 /* ARMv8-M specific registers */
120 { ARMV8M_MSP_NS
, "msp_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
121 { ARMV8M_PSP_NS
, "psp_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
122 { ARMV8M_MSP_S
, "msp_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
123 { ARMV8M_PSP_S
, "psp_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
124 { ARMV8M_MSPLIM_S
, "msplim_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
125 { ARMV8M_PSPLIM_S
, "psplim_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
126 { ARMV8M_MSPLIM_NS
, "msplim_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
127 { ARMV8M_PSPLIM_NS
, "psplim_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
129 { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT
, NULL
, NULL
},
130 { ARMV8M_PRIMASK_S
, "primask_s", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
131 { ARMV8M_BASEPRI_S
, "basepri_s", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
132 { ARMV8M_FAULTMASK_S
, "faultmask_s", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
133 { ARMV8M_CONTROL_S
, "control_s", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
135 { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT
, NULL
, NULL
},
136 { ARMV8M_PRIMASK_NS
, "primask_ns", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
137 { ARMV8M_BASEPRI_NS
, "basepri_ns", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
138 { ARMV8M_FAULTMASK_NS
, "faultmask_ns", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
139 { ARMV8M_CONTROL_NS
, "control_ns", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
142 { ARMV7M_D0
, "d0", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
143 { ARMV7M_D1
, "d1", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
144 { ARMV7M_D2
, "d2", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
145 { ARMV7M_D3
, "d3", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
146 { ARMV7M_D4
, "d4", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
147 { ARMV7M_D5
, "d5", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
148 { ARMV7M_D6
, "d6", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
149 { ARMV7M_D7
, "d7", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
150 { ARMV7M_D8
, "d8", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
151 { ARMV7M_D9
, "d9", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
152 { ARMV7M_D10
, "d10", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
153 { ARMV7M_D11
, "d11", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
154 { ARMV7M_D12
, "d12", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
155 { ARMV7M_D13
, "d13", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
156 { ARMV7M_D14
, "d14", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
157 { ARMV7M_D15
, "d15", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
159 { ARMV7M_FPSCR
, "fpscr", 32, REG_TYPE_INT
, "float", "org.gnu.gdb.arm.vfp" },
162 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
165 * Restores target context using the cache of core registers set up
166 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
168 int armv7m_restore_context(struct target
*target
)
171 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
172 struct reg_cache
*cache
= armv7m
->arm
.core_cache
;
176 if (armv7m
->pre_restore_context
)
177 armv7m
->pre_restore_context(target
);
179 /* The descending order of register writes is crucial for correct
180 * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL!
181 * See also comments in the register table above */
182 for (i
= cache
->num_regs
- 1; i
>= 0; i
--) {
183 struct reg
*r
= &cache
->reg_list
[i
];
185 if (r
->exist
&& r
->dirty
)
186 armv7m
->arm
.write_core_reg(target
, r
, i
, ARM_MODE_ANY
, r
->value
);
192 /* Core state functions */
195 * Maps ISR number (from xPSR) to name.
196 * Note that while names and meanings for the first sixteen are standardized
197 * (with zero not a true exception), external interrupts are only numbered.
198 * They are assigned by vendors, which generally assign different numbers to
199 * peripherals (such as UART0 or a USB peripheral controller).
201 const char *armv7m_exception_string(int number
)
203 static char enamebuf
[32];
205 if ((number
< 0) | (number
> 511))
206 return "Invalid exception";
208 return armv7m_exception_strings
[number
];
209 sprintf(enamebuf
, "External Interrupt(%i)", number
- 16);
213 static int armv7m_get_core_reg(struct reg
*reg
)
216 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
217 struct target
*target
= armv7m_reg
->target
;
218 struct arm
*arm
= target_to_arm(target
);
220 if (target
->state
!= TARGET_HALTED
)
221 return ERROR_TARGET_NOT_HALTED
;
223 retval
= arm
->read_core_reg(target
, reg
, reg
->number
, arm
->core_mode
);
228 static int armv7m_set_core_reg(struct reg
*reg
, uint8_t *buf
)
230 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
231 struct target
*target
= armv7m_reg
->target
;
233 if (target
->state
!= TARGET_HALTED
)
234 return ERROR_TARGET_NOT_HALTED
;
236 buf_cpy(buf
, reg
->value
, reg
->size
);
243 uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id
)
245 switch (arm_reg_id
) {
246 case ARMV7M_R0
... ARMV7M_R14
:
251 /* NOTE: we "know" here that the register identifiers
252 * match the Cortex-M DCRSR.REGSEL selectors values
253 * for R0..R14, PC, xPSR, MSP, and PSP.
257 case ARMV7M_PMSK_BPRI_FLTMSK_CTRL
:
258 return ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL
;
260 case ARMV8M_MSP_NS
...ARMV8M_PSPLIM_NS
:
261 return arm_reg_id
- ARMV8M_MSP_NS
+ ARMV8M_REGSEL_MSP_NS
;
263 case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
:
264 return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S
;
266 case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
:
267 return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS
;
270 return ARMV7M_REGSEL_FPSCR
;
272 case ARMV7M_D0
... ARMV7M_D15
:
273 return ARMV7M_REGSEL_S0
+ 2 * (arm_reg_id
- ARMV7M_D0
);
276 LOG_ERROR("Bad register ID %u", arm_reg_id
);
281 bool armv7m_map_reg_packing(unsigned int arm_reg_id
,
282 unsigned int *reg32_id
, uint32_t *offset
)
285 switch (arm_reg_id
) {
287 case ARMV7M_PRIMASK
...ARMV7M_CONTROL
:
288 *reg32_id
= ARMV7M_PMSK_BPRI_FLTMSK_CTRL
;
289 *offset
= arm_reg_id
- ARMV7M_PRIMASK
;
291 case ARMV8M_PRIMASK_S
...ARMV8M_CONTROL_S
:
292 *reg32_id
= ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
;
293 *offset
= arm_reg_id
- ARMV8M_PRIMASK_S
;
295 case ARMV8M_PRIMASK_NS
...ARMV8M_CONTROL_NS
:
296 *reg32_id
= ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
;
297 *offset
= arm_reg_id
- ARMV8M_PRIMASK_NS
;
306 static int armv7m_read_core_reg(struct target
*target
, struct reg
*r
,
307 int num
, enum arm_mode mode
)
311 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
313 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
314 assert(num
== (int)r
->number
);
316 /* If a code calls read_reg, it expects the cache is no more dirty.
317 * Clear the dirty flag regardless of the later read succeeds or not
318 * to prevent unwanted cache flush after a read error */
322 /* any 8-bit or shorter register is packed */
324 unsigned int reg32_id
;
326 bool is_packed
= armv7m_map_reg_packing(num
, ®32_id
, &offset
);
328 /* We should not get here as all 8-bit or shorter registers
331 /* assert() does nothing if NDEBUG is defined */
334 struct reg
*r32
= &armv7m
->arm
.core_cache
->reg_list
[reg32_id
];
336 /* Read 32-bit container register if not cached */
338 retval
= armv7m_read_core_reg(target
, r32
, reg32_id
, mode
);
339 if (retval
!= ERROR_OK
)
343 /* Copy required bits of 32-bit container register */
344 buf_cpy(r32
->value
+ offset
, r
->value
, r
->size
);
347 assert(r
->size
== 32 || r
->size
== 64);
349 struct arm_reg
*armv7m_core_reg
= r
->arch_info
;
350 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
352 retval
= armv7m
->load_core_reg_u32(target
, regsel
, ®_value
);
353 if (retval
!= ERROR_OK
)
355 buf_set_u32(r
->value
, 0, 32, reg_value
);
358 retval
= armv7m
->load_core_reg_u32(target
, regsel
+ 1, ®_value
);
359 if (retval
!= ERROR_OK
) {
363 buf_set_u32(r
->value
+ 4, 0, 32, reg_value
);
365 uint64_t q
= buf_get_u64(r
->value
, 0, 64);
366 LOG_DEBUG("read %s value 0x%016" PRIx64
, r
->name
, q
);
368 LOG_DEBUG("read %s value 0x%08" PRIx32
, r
->name
, reg_value
);
377 static int armv7m_write_core_reg(struct target
*target
, struct reg
*r
,
378 int num
, enum arm_mode mode
, uint8_t *value
)
382 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
384 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
385 assert(num
== (int)r
->number
);
387 if (value
!= r
->value
) {
388 /* If we are not flushing the cache, store the new value to the cache */
389 buf_cpy(value
, r
->value
, r
->size
);
393 /* any 8-bit or shorter register is packed */
395 unsigned int reg32_id
;
397 bool is_packed
= armv7m_map_reg_packing(num
, ®32_id
, &offset
);
399 /* We should not get here as all 8-bit or shorter registers
402 /* assert() does nothing if NDEBUG is defined */
405 struct reg
*r32
= &armv7m
->arm
.core_cache
->reg_list
[reg32_id
];
408 /* Before merging with other parts ensure the 32-bit register is valid */
409 retval
= armv7m_read_core_reg(target
, r32
, reg32_id
, mode
);
410 if (retval
!= ERROR_OK
)
414 /* Write a part to the 32-bit container register */
415 buf_cpy(value
, r32
->value
+ offset
, r
->size
);
419 assert(r
->size
== 32 || r
->size
== 64);
421 struct arm_reg
*armv7m_core_reg
= r
->arch_info
;
422 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
424 t
= buf_get_u32(value
, 0, 32);
425 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
426 if (retval
!= ERROR_OK
)
430 t
= buf_get_u32(value
+ 4, 0, 32);
431 retval
= armv7m
->store_core_reg_u32(target
, regsel
+ 1, t
);
432 if (retval
!= ERROR_OK
)
435 uint64_t q
= buf_get_u64(value
, 0, 64);
436 LOG_DEBUG("write %s value 0x%016" PRIx64
, r
->name
, q
);
438 LOG_DEBUG("write %s value 0x%08" PRIx32
, r
->name
, t
);
449 LOG_ERROR("Error setting register %s", r
->name
);
454 * Returns generic ARM userspace registers to GDB.
456 int armv7m_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
457 int *reg_list_size
, enum target_register_class reg_class
)
459 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
462 if (reg_class
== REG_CLASS_ALL
)
463 size
= armv7m
->arm
.core_cache
->num_regs
;
465 size
= ARMV7M_NUM_CORE_REGS
;
467 *reg_list
= malloc(sizeof(struct reg
*) * size
);
471 for (i
= 0; i
< size
; i
++)
472 (*reg_list
)[i
] = &armv7m
->arm
.core_cache
->reg_list
[i
];
474 *reg_list_size
= size
;
479 /** Runs a Thumb algorithm in the target. */
480 int armv7m_run_algorithm(struct target
*target
,
481 int num_mem_params
, struct mem_param
*mem_params
,
482 int num_reg_params
, struct reg_param
*reg_params
,
483 target_addr_t entry_point
, target_addr_t exit_point
,
484 int timeout_ms
, void *arch_info
)
488 retval
= armv7m_start_algorithm(target
,
489 num_mem_params
, mem_params
,
490 num_reg_params
, reg_params
,
491 entry_point
, exit_point
,
494 if (retval
== ERROR_OK
)
495 retval
= armv7m_wait_algorithm(target
,
496 num_mem_params
, mem_params
,
497 num_reg_params
, reg_params
,
498 exit_point
, timeout_ms
,
504 /** Starts a Thumb algorithm in the target. */
505 int armv7m_start_algorithm(struct target
*target
,
506 int num_mem_params
, struct mem_param
*mem_params
,
507 int num_reg_params
, struct reg_param
*reg_params
,
508 target_addr_t entry_point
, target_addr_t exit_point
,
511 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
512 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
513 enum arm_mode core_mode
= armv7m
->arm
.core_mode
;
514 int retval
= ERROR_OK
;
516 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
517 * at the exit point */
519 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
520 LOG_ERROR("current target isn't an ARMV7M target");
521 return ERROR_TARGET_INVALID
;
524 if (target
->state
!= TARGET_HALTED
) {
525 LOG_WARNING("target not halted");
526 return ERROR_TARGET_NOT_HALTED
;
529 /* Store all non-debug execution registers to armv7m_algorithm_info context */
530 for (unsigned i
= 0; i
< armv7m
->arm
.core_cache
->num_regs
; i
++) {
531 struct reg
*reg
= &armv7m
->arm
.core_cache
->reg_list
[i
];
533 armv7m_get_core_reg(reg
);
536 LOG_TARGET_WARNING(target
, "Storing invalid register %s", reg
->name
);
538 armv7m_algorithm_info
->context
[i
] = buf_get_u32(reg
->value
, 0, 32);
541 for (int i
= 0; i
< num_mem_params
; i
++) {
542 if (mem_params
[i
].direction
== PARAM_IN
)
544 retval
= target_write_buffer(target
, mem_params
[i
].address
,
546 mem_params
[i
].value
);
547 if (retval
!= ERROR_OK
)
551 for (int i
= 0; i
< num_reg_params
; i
++) {
552 if (reg_params
[i
].direction
== PARAM_IN
)
556 register_get_by_name(armv7m
->arm
.core_cache
, reg_params
[i
].reg_name
, false);
557 /* uint32_t regvalue; */
560 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
561 return ERROR_COMMAND_SYNTAX_ERROR
;
564 if (reg
->size
!= reg_params
[i
].size
) {
565 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
566 reg_params
[i
].reg_name
);
567 return ERROR_COMMAND_SYNTAX_ERROR
;
570 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
571 armv7m_set_core_reg(reg
, reg_params
[i
].value
);
576 * Ensure xPSR.T is set to avoid trying to run things in arm
577 * (non-thumb) mode, which armv7m does not support.
579 * We do this by setting the entirety of xPSR, which should
580 * remove all the unknowns about xPSR state.
582 * Because xPSR.T is populated on reset from the vector table,
583 * it might be 0 if the vector table has "bad" data in it.
585 struct reg
*reg
= &armv7m
->arm
.core_cache
->reg_list
[ARMV7M_XPSR
];
586 buf_set_u32(reg
->value
, 0, 32, 0x01000000);
591 if (armv7m_algorithm_info
->core_mode
!= ARM_MODE_ANY
&&
592 armv7m_algorithm_info
->core_mode
!= core_mode
) {
594 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
595 if (armv7m_algorithm_info
->core_mode
== ARM_MODE_HANDLER
) {
596 armv7m_algorithm_info
->core_mode
= ARM_MODE_THREAD
;
597 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
600 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
601 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
602 0, 1, armv7m_algorithm_info
->core_mode
);
603 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
604 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
607 /* save previous core mode */
608 armv7m_algorithm_info
->core_mode
= core_mode
;
610 retval
= target_resume(target
, 0, entry_point
, 1, 1);
615 /** Waits for an algorithm in the target. */
616 int armv7m_wait_algorithm(struct target
*target
,
617 int num_mem_params
, struct mem_param
*mem_params
,
618 int num_reg_params
, struct reg_param
*reg_params
,
619 target_addr_t exit_point
, int timeout_ms
,
622 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
623 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
624 int retval
= ERROR_OK
;
626 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
627 * at the exit point */
629 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
630 LOG_ERROR("current target isn't an ARMV7M target");
631 return ERROR_TARGET_INVALID
;
634 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
635 /* If the target fails to halt due to the breakpoint, force a halt */
636 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
637 retval
= target_halt(target
);
638 if (retval
!= ERROR_OK
)
640 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
641 if (retval
!= ERROR_OK
)
643 return ERROR_TARGET_TIMEOUT
;
647 /* PC value has been cached in cortex_m_debug_entry() */
648 uint32_t pc
= buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32);
649 if (pc
!= exit_point
) {
650 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
", expected 0x%" TARGET_PRIxADDR
,
652 return ERROR_TARGET_ALGO_EXIT
;
656 /* Read memory values to mem_params[] */
657 for (int i
= 0; i
< num_mem_params
; i
++) {
658 if (mem_params
[i
].direction
!= PARAM_OUT
) {
659 retval
= target_read_buffer(target
, mem_params
[i
].address
,
661 mem_params
[i
].value
);
662 if (retval
!= ERROR_OK
)
667 /* Copy core register values to reg_params[] */
668 for (int i
= 0; i
< num_reg_params
; i
++) {
669 if (reg_params
[i
].direction
!= PARAM_OUT
) {
670 struct reg
*reg
= register_get_by_name(armv7m
->arm
.core_cache
,
671 reg_params
[i
].reg_name
,
675 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
676 return ERROR_COMMAND_SYNTAX_ERROR
;
679 if (reg
->size
!= reg_params
[i
].size
) {
681 "BUG: register '%s' size doesn't match reg_params[i].size",
682 reg_params
[i
].reg_name
);
683 return ERROR_COMMAND_SYNTAX_ERROR
;
686 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
690 for (int i
= armv7m
->arm
.core_cache
->num_regs
- 1; i
>= 0; i
--) {
692 regvalue
= buf_get_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
, 0, 32);
693 if (regvalue
!= armv7m_algorithm_info
->context
[i
]) {
694 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
695 armv7m
->arm
.core_cache
->reg_list
[i
].name
,
696 armv7m_algorithm_info
->context
[i
]);
697 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
,
698 0, 32, armv7m_algorithm_info
->context
[i
]);
699 armv7m
->arm
.core_cache
->reg_list
[i
].valid
= true;
700 armv7m
->arm
.core_cache
->reg_list
[i
].dirty
= true;
704 /* restore previous core mode */
705 if (armv7m_algorithm_info
->core_mode
!= armv7m
->arm
.core_mode
) {
706 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
707 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
708 0, 1, armv7m_algorithm_info
->core_mode
);
709 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
710 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
713 armv7m
->arm
.core_mode
= armv7m_algorithm_info
->core_mode
;
718 /** Logs summary of ARMv7-M state for a halted target. */
719 int armv7m_arch_state(struct target
*target
)
721 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
722 struct arm
*arm
= &armv7m
->arm
;
725 /* avoid filling log waiting for fileio reply */
726 if (target
->semihosting
&& target
->semihosting
->hit_fileio
)
729 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
730 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
732 LOG_USER("target halted due to %s, current mode: %s %s\n"
733 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s%s",
734 debug_reason_name(target
),
735 arm_mode_name(arm
->core_mode
),
736 armv7m_exception_string(armv7m
->exception_number
),
737 buf_get_u32(arm
->cpsr
->value
, 0, 32),
738 buf_get_u32(arm
->pc
->value
, 0, 32),
739 (ctrl
& 0x02) ? 'p' : 'm',
741 (target
->semihosting
&& target
->semihosting
->is_active
) ? ", semihosting" : "",
742 (target
->semihosting
&& target
->semihosting
->is_fileio
) ? " fileio" : "");
747 static const struct reg_arch_type armv7m_reg_type
= {
748 .get
= armv7m_get_core_reg
,
749 .set
= armv7m_set_core_reg
,
752 /** Builds cache of architecturally defined registers. */
753 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
755 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
756 struct arm
*arm
= &armv7m
->arm
;
757 int num_regs
= ARMV7M_NUM_REGS
;
758 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
759 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
760 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
761 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
762 struct reg_feature
*feature
;
765 /* Build the process context cache */
766 cache
->name
= "arm v7m registers";
768 cache
->reg_list
= reg_list
;
769 cache
->num_regs
= num_regs
;
772 for (i
= 0; i
< num_regs
; i
++) {
773 arch_info
[i
].num
= armv7m_regs
[i
].id
;
774 arch_info
[i
].target
= target
;
775 arch_info
[i
].arm
= arm
;
777 reg_list
[i
].name
= armv7m_regs
[i
].name
;
778 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
779 reg_list
[i
].value
= arch_info
[i
].value
;
780 reg_list
[i
].dirty
= false;
781 reg_list
[i
].valid
= false;
782 reg_list
[i
].hidden
= (i
== ARMV7M_PMSK_BPRI_FLTMSK_CTRL
||
783 i
== ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
|| i
== ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
);
784 reg_list
[i
].type
= &armv7m_reg_type
;
785 reg_list
[i
].arch_info
= &arch_info
[i
];
787 reg_list
[i
].group
= armv7m_regs
[i
].group
;
788 reg_list
[i
].number
= i
;
789 reg_list
[i
].exist
= true;
790 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
792 if (reg_list
[i
].hidden
)
795 feature
= calloc(1, sizeof(struct reg_feature
));
797 feature
->name
= armv7m_regs
[i
].feature
;
798 reg_list
[i
].feature
= feature
;
800 LOG_ERROR("unable to allocate feature list");
802 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
803 if (reg_list
[i
].reg_data_type
)
804 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
806 LOG_ERROR("unable to allocate reg type list");
809 arm
->cpsr
= reg_list
+ ARMV7M_XPSR
;
810 arm
->pc
= reg_list
+ ARMV7M_PC
;
811 arm
->core_cache
= cache
;
816 void armv7m_free_reg_cache(struct target
*target
)
818 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
819 struct arm
*arm
= &armv7m
->arm
;
820 struct reg_cache
*cache
;
824 cache
= arm
->core_cache
;
829 for (i
= 0; i
< cache
->num_regs
; i
++) {
830 reg
= &cache
->reg_list
[i
];
833 free(reg
->reg_data_type
);
836 free(cache
->reg_list
[0].arch_info
);
837 free(cache
->reg_list
);
840 arm
->core_cache
= NULL
;
843 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
845 /* nothing todo for armv7m */
849 /** Sets up target as a generic ARMv7-M core */
850 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
852 struct arm
*arm
= &armv7m
->arm
;
854 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
855 armv7m
->fp_feature
= FP_NONE
;
856 armv7m
->trace_config
.trace_bus_id
= 1;
857 /* Enable stimulus port #0 by default */
858 armv7m
->trace_config
.itm_ter
[0] = 1;
860 arm
->core_state
= ARM_STATE_THUMB
;
861 arm
->core_type
= ARM_CORE_TYPE_M_PROFILE
;
862 arm
->arch_info
= armv7m
;
863 arm
->setup_semihosting
= armv7m_setup_semihosting
;
865 arm
->read_core_reg
= armv7m_read_core_reg
;
866 arm
->write_core_reg
= armv7m_write_core_reg
;
868 return arm_init_arch_info(target
, arm
);
871 /** Generates a CRC32 checksum of a memory region. */
872 int armv7m_checksum_memory(struct target
*target
,
873 target_addr_t address
, uint32_t count
, uint32_t *checksum
)
875 struct working_area
*crc_algorithm
;
876 struct armv7m_algorithm armv7m_info
;
877 struct reg_param reg_params
[2];
880 static const uint8_t cortex_m_crc_code
[] = {
881 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
884 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
885 if (retval
!= ERROR_OK
)
888 retval
= target_write_buffer(target
, crc_algorithm
->address
,
889 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
890 if (retval
!= ERROR_OK
)
893 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
894 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
896 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
897 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
899 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
900 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
902 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
904 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
905 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
906 timeout
, &armv7m_info
);
908 if (retval
== ERROR_OK
)
909 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
911 LOG_ERROR("error executing cortex_m crc algorithm");
913 destroy_reg_param(®_params
[0]);
914 destroy_reg_param(®_params
[1]);
917 target_free_working_area(target
, crc_algorithm
);
922 /** Checks an array of memory regions whether they are erased. */
923 int armv7m_blank_check_memory(struct target
*target
,
924 struct target_memory_check_block
*blocks
, int num_blocks
, uint8_t erased_value
)
926 struct working_area
*erase_check_algorithm
;
927 struct working_area
*erase_check_params
;
928 struct reg_param reg_params
[2];
929 struct armv7m_algorithm armv7m_info
;
932 static bool timed_out
;
934 static const uint8_t erase_check_code
[] = {
935 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
938 const uint32_t code_size
= sizeof(erase_check_code
);
940 /* make sure we have a working area */
941 if (target_alloc_working_area(target
, code_size
,
942 &erase_check_algorithm
) != ERROR_OK
)
943 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
945 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
946 code_size
, erase_check_code
);
947 if (retval
!= ERROR_OK
)
950 /* prepare blocks array for algo */
959 uint32_t avail
= target_get_working_area_avail(target
);
960 int blocks_to_check
= avail
/ sizeof(struct algo_block
) - 1;
961 if (num_blocks
< blocks_to_check
)
962 blocks_to_check
= num_blocks
;
964 struct algo_block
*params
= malloc((blocks_to_check
+1)*sizeof(struct algo_block
));
971 uint32_t total_size
= 0;
972 for (i
= 0; i
< blocks_to_check
; i
++) {
973 total_size
+= blocks
[i
].size
;
974 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].size
),
975 blocks
[i
].size
/ sizeof(uint32_t));
976 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].address
),
979 target_buffer_set_u32(target
, (uint8_t *)&(params
[blocks_to_check
].size
), 0);
981 uint32_t param_size
= (blocks_to_check
+ 1) * sizeof(struct algo_block
);
982 if (target_alloc_working_area(target
, param_size
,
983 &erase_check_params
) != ERROR_OK
) {
984 retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
988 retval
= target_write_buffer(target
, erase_check_params
->address
,
989 param_size
, (uint8_t *)params
);
990 if (retval
!= ERROR_OK
)
993 uint32_t erased_word
= erased_value
| (erased_value
<< 8)
994 | (erased_value
<< 16) | (erased_value
<< 24);
996 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
997 TARGET_ADDR_FMT
, blocks_to_check
, erase_check_params
->address
);
999 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
1000 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
1002 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
1003 buf_set_u32(reg_params
[0].value
, 0, 32, erase_check_params
->address
);
1005 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
1006 buf_set_u32(reg_params
[1].value
, 0, 32, erased_word
);
1008 /* assume CPU clk at least 1 MHz */
1009 int timeout
= (timed_out
? 30000 : 2000) + total_size
* 3 / 1000;
1011 retval
= target_run_algorithm(target
,
1013 ARRAY_SIZE(reg_params
), reg_params
,
1014 erase_check_algorithm
->address
,
1015 erase_check_algorithm
->address
+ (code_size
- 2),
1019 timed_out
= retval
== ERROR_TARGET_TIMEOUT
;
1020 if (retval
!= ERROR_OK
&& !timed_out
)
1023 retval
= target_read_buffer(target
, erase_check_params
->address
,
1024 param_size
, (uint8_t *)params
);
1025 if (retval
!= ERROR_OK
)
1028 for (i
= 0; i
< blocks_to_check
; i
++) {
1029 uint32_t result
= target_buffer_get_u32(target
,
1030 (uint8_t *)&(params
[i
].result
));
1031 if (result
!= 0 && result
!= 1)
1034 blocks
[i
].result
= result
;
1037 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i
, num_blocks
-i
);
1039 retval
= i
; /* return number of blocks really checked */
1042 destroy_reg_param(®_params
[0]);
1043 destroy_reg_param(®_params
[1]);
1046 target_free_working_area(target
, erase_check_params
);
1050 target_free_working_area(target
, erase_check_algorithm
);
1055 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
1057 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
1058 struct reg
*r
= armv7m
->arm
.pc
;
1059 bool result
= false;
1062 /* if we halted last time due to a bkpt instruction
1063 * then we have to manually step over it, otherwise
1064 * the core will break again */
1066 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
1068 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
1071 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
1072 if ((op
& 0xFF00) == 0xBE00) {
1073 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
1074 buf_set_u32(r
->value
, 0, 32, pc
);
1078 LOG_DEBUG("Skipping over BKPT instruction");
1084 *inst_found
= result
;
1089 const struct command_registration armv7m_command_handlers
[] = {
1092 .mode
= COMMAND_ANY
,
1093 .help
= "ARM command group",
1095 .chain
= arm_all_profiles_command_handlers
,
1097 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)