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 * Copyright (C) 2019 by Tomas Vanek *
20 * This program is free software; you can redistribute it and/or modify *
21 * it under the terms of the GNU General Public License as published by *
22 * the Free Software Foundation; either version 2 of the License, or *
23 * (at your option) any later version. *
25 * This program is distributed in the hope that it will be useful, *
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
28 * GNU General Public License for more details. *
30 * You should have received a copy of the GNU General Public License *
31 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
33 * ARMv7-M Architecture, Application Level Reference Manual *
34 * ARM DDI 0405C (September 2008) *
36 ***************************************************************************/
42 #include "breakpoints.h"
44 #include "algorithm.h"
46 #include "semihosting_common.h"
49 #define _DEBUG_INSTRUCTION_EXECUTION_
52 static const char * const armv7m_exception_strings
[] = {
53 "", "Reset", "NMI", "HardFault",
54 "MemManage", "BusFault", "UsageFault", "SecureFault",
55 "RESERVED", "RESERVED", "RESERVED", "SVCall",
56 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
59 /* PSP is used in some thread modes */
60 const int armv7m_psp_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_PSP
, ARMV7M_R14
, ARMV7M_PC
,
68 /* MSP is used in handler and some thread modes */
69 const int armv7m_msp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
70 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
71 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
72 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
73 ARMV7M_R12
, ARMV7M_MSP
, ARMV7M_R14
, ARMV7M_PC
,
78 * These registers are not memory-mapped. The ARMv7-M profile includes
79 * memory mapped registers too, such as for the NVIC (interrupt controller)
80 * and SysTick (timer) modules; those can mostly be treated as peripherals.
82 * The ARMv6-M profile is almost identical in this respect, except that it
83 * doesn't include basepri or faultmask registers.
93 { ARMV7M_R0
, "r0", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R1
, "r1", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R2
, "r2", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R3
, "r3", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R4
, "r4", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R5
, "r5", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_R6
, "r6", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_R7
, "r7", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
101 { ARMV7M_R8
, "r8", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_R9
, "r9", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
103 { ARMV7M_R10
, "r10", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
104 { ARMV7M_R11
, "r11", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
105 { ARMV7M_R12
, "r12", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
106 { ARMV7M_R13
, "sp", 32, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
107 { ARMV7M_R14
, "lr", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
108 { ARMV7M_PC
, "pc", 32, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
109 { ARMV7M_xPSR
, "xPSR", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
111 { ARMV7M_MSP
, "msp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
112 { ARMV7M_PSP
, "psp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
114 /* A working register for packing/unpacking special regs, hidden from gdb */
115 { ARMV7M_PMSK_BPRI_FLTMSK_CTRL
, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT
, NULL
, NULL
},
117 /* WARNING: If you use armv7m_write_core_reg() on one of 4 following
118 * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL
119 * cache only and are not flushed to CPU HW register.
120 * To trigger write to CPU HW register, add
121 * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,);
123 { ARMV7M_PRIMASK
, "primask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
124 { ARMV7M_BASEPRI
, "basepri", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
125 { ARMV7M_FAULTMASK
, "faultmask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
126 { ARMV7M_CONTROL
, "control", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
128 /* ARMv8-M specific registers */
129 { ARMV8M_MSP_NS
, "msp_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
130 { ARMV8M_PSP_NS
, "psp_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
131 { ARMV8M_MSP_S
, "msp_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
132 { ARMV8M_PSP_S
, "psp_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
133 { ARMV8M_MSPLIM_S
, "msplim_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
134 { ARMV8M_PSPLIM_S
, "psplim_s", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
135 { ARMV8M_MSPLIM_NS
, "msplim_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
136 { ARMV8M_PSPLIM_NS
, "psplim_ns", 32, REG_TYPE_DATA_PTR
, "stack", "v8-m.sp" },
138 { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT
, NULL
, NULL
},
139 { ARMV8M_PRIMASK_S
, "primask_s", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
140 { ARMV8M_BASEPRI_S
, "basepri_s", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
141 { ARMV8M_FAULTMASK_S
, "faultmask_s", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
142 { ARMV8M_CONTROL_S
, "control_s", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
144 { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT
, NULL
, NULL
},
145 { ARMV8M_PRIMASK_NS
, "primask_ns", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
146 { ARMV8M_BASEPRI_NS
, "basepri_ns", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
147 { ARMV8M_FAULTMASK_NS
, "faultmask_ns", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
148 { ARMV8M_CONTROL_NS
, "control_ns", 3, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
151 { ARMV7M_D0
, "d0", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
152 { ARMV7M_D1
, "d1", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
153 { ARMV7M_D2
, "d2", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
154 { ARMV7M_D3
, "d3", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
155 { ARMV7M_D4
, "d4", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
156 { ARMV7M_D5
, "d5", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
157 { ARMV7M_D6
, "d6", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
158 { ARMV7M_D7
, "d7", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
159 { ARMV7M_D8
, "d8", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
160 { ARMV7M_D9
, "d9", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
161 { ARMV7M_D10
, "d10", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
162 { ARMV7M_D11
, "d11", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
163 { ARMV7M_D12
, "d12", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
164 { ARMV7M_D13
, "d13", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
165 { ARMV7M_D14
, "d14", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
166 { ARMV7M_D15
, "d15", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
168 { ARMV7M_FPSCR
, "fpscr", 32, REG_TYPE_INT
, "float", "org.gnu.gdb.arm.vfp" },
171 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
174 * Restores target context using the cache of core registers set up
175 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
177 int armv7m_restore_context(struct target
*target
)
180 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
181 struct reg_cache
*cache
= armv7m
->arm
.core_cache
;
185 if (armv7m
->pre_restore_context
)
186 armv7m
->pre_restore_context(target
);
188 /* The descending order of register writes is crucial for correct
189 * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL!
190 * See also comments in the register table above */
191 for (i
= cache
->num_regs
- 1; i
>= 0; i
--) {
192 struct reg
*r
= &cache
->reg_list
[i
];
194 if (r
->exist
&& r
->dirty
)
195 armv7m
->arm
.write_core_reg(target
, r
, i
, ARM_MODE_ANY
, r
->value
);
201 /* Core state functions */
204 * Maps ISR number (from xPSR) to name.
205 * Note that while names and meanings for the first sixteen are standardized
206 * (with zero not a true exception), external interrupts are only numbered.
207 * They are assigned by vendors, which generally assign different numbers to
208 * peripherals (such as UART0 or a USB peripheral controller).
210 const char *armv7m_exception_string(int number
)
212 static char enamebuf
[32];
214 if ((number
< 0) | (number
> 511))
215 return "Invalid exception";
217 return armv7m_exception_strings
[number
];
218 sprintf(enamebuf
, "External Interrupt(%i)", number
- 16);
222 static int armv7m_get_core_reg(struct reg
*reg
)
225 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
226 struct target
*target
= armv7m_reg
->target
;
227 struct arm
*arm
= target_to_arm(target
);
229 if (target
->state
!= TARGET_HALTED
)
230 return ERROR_TARGET_NOT_HALTED
;
232 retval
= arm
->read_core_reg(target
, reg
, reg
->number
, arm
->core_mode
);
237 static int armv7m_set_core_reg(struct reg
*reg
, uint8_t *buf
)
239 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
240 struct target
*target
= armv7m_reg
->target
;
242 if (target
->state
!= TARGET_HALTED
)
243 return ERROR_TARGET_NOT_HALTED
;
245 buf_cpy(buf
, reg
->value
, reg
->size
);
252 static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id
)
254 switch (arm_reg_id
) {
255 case ARMV7M_R0
... ARMV7M_R14
:
260 /* NOTE: we "know" here that the register identifiers
261 * match the Cortex-M DCRSR.REGSEL selectors values
262 * for R0..R14, PC, xPSR, MSP, and PSP.
266 case ARMV7M_PMSK_BPRI_FLTMSK_CTRL
:
267 return ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL
;
269 case ARMV8M_MSP_NS
...ARMV8M_PSPLIM_NS
:
270 return arm_reg_id
- ARMV8M_MSP_NS
+ ARMV8M_REGSEL_MSP_NS
;
272 case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
:
273 return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S
;
275 case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
:
276 return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS
;
279 return ARMV7M_REGSEL_FPSCR
;
281 case ARMV7M_D0
... ARMV7M_D15
:
282 return ARMV7M_REGSEL_S0
+ 2 * (arm_reg_id
- ARMV7M_D0
);
285 LOG_ERROR("Bad register ID %u", arm_reg_id
);
290 static bool armv7m_map_reg_packing(unsigned int arm_reg_id
,
291 unsigned int *reg32_id
, uint32_t *offset
)
294 switch (arm_reg_id
) {
296 case ARMV7M_PRIMASK
...ARMV7M_CONTROL
:
297 *reg32_id
= ARMV7M_PMSK_BPRI_FLTMSK_CTRL
;
298 *offset
= arm_reg_id
- ARMV7M_PRIMASK
;
300 case ARMV8M_PRIMASK_S
...ARMV8M_CONTROL_S
:
301 *reg32_id
= ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
;
302 *offset
= arm_reg_id
- ARMV8M_PRIMASK_S
;
304 case ARMV8M_PRIMASK_NS
...ARMV8M_CONTROL_NS
:
305 *reg32_id
= ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
;
306 *offset
= arm_reg_id
- ARMV8M_PRIMASK_NS
;
315 static int armv7m_read_core_reg(struct target
*target
, struct reg
*r
,
316 int num
, enum arm_mode mode
)
320 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
322 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
323 assert(num
== (int)r
->number
);
325 /* If a code calls read_reg, it expects the cache is no more dirty.
326 * Clear the dirty flag regardless of the later read succeeds or not
327 * to prevent unwanted cache flush after a read error */
331 /* any 8-bit or shorter register is packed */
332 uint32_t offset
= 0; /* silence false gcc warning */
333 unsigned int reg32_id
;
335 bool is_packed
= armv7m_map_reg_packing(num
, ®32_id
, &offset
);
337 struct reg
*r32
= &armv7m
->arm
.core_cache
->reg_list
[reg32_id
];
339 /* Read 32-bit container register if not cached */
341 retval
= armv7m_read_core_reg(target
, r32
, reg32_id
, mode
);
342 if (retval
!= ERROR_OK
)
346 /* Copy required bits of 32-bit container register */
347 buf_cpy(r32
->value
+ offset
, r
->value
, r
->size
);
350 assert(r
->size
== 32 || r
->size
== 64);
352 struct arm_reg
*armv7m_core_reg
= r
->arch_info
;
353 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
355 retval
= armv7m
->load_core_reg_u32(target
, regsel
, ®_value
);
356 if (retval
!= ERROR_OK
)
358 buf_set_u32(r
->value
, 0, 32, reg_value
);
361 retval
= armv7m
->load_core_reg_u32(target
, regsel
+ 1, ®_value
);
362 if (retval
!= ERROR_OK
) {
366 buf_set_u32(r
->value
+ 4, 0, 32, reg_value
);
368 uint64_t q
= buf_get_u64(r
->value
, 0, 64);
369 LOG_DEBUG("read %s value 0x%016" PRIx64
, r
->name
, q
);
371 LOG_DEBUG("read %s value 0x%08" PRIx32
, r
->name
, reg_value
);
380 static int armv7m_write_core_reg(struct target
*target
, struct reg
*r
,
381 int num
, enum arm_mode mode
, uint8_t *value
)
385 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
387 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
388 assert(num
== (int)r
->number
);
390 if (value
!= r
->value
) {
391 /* If we are not flushing the cache, store the new value to the cache */
392 buf_cpy(value
, r
->value
, r
->size
);
396 /* any 8-bit or shorter register is packed */
397 uint32_t offset
= 0; /* silence false gcc warning */
398 unsigned int reg32_id
;
400 bool is_packed
= armv7m_map_reg_packing(num
, ®32_id
, &offset
);
402 struct reg
*r32
= &armv7m
->arm
.core_cache
->reg_list
[reg32_id
];
405 /* Before merging with other parts ensure the 32-bit register is valid */
406 retval
= armv7m_read_core_reg(target
, r32
, reg32_id
, mode
);
407 if (retval
!= ERROR_OK
)
411 /* Write a part to the 32-bit container register */
412 buf_cpy(value
, r32
->value
+ offset
, r
->size
);
416 assert(r
->size
== 32 || r
->size
== 64);
418 struct arm_reg
*armv7m_core_reg
= r
->arch_info
;
419 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
421 t
= buf_get_u32(value
, 0, 32);
422 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
423 if (retval
!= ERROR_OK
)
427 t
= buf_get_u32(value
+ 4, 0, 32);
428 retval
= armv7m
->store_core_reg_u32(target
, regsel
+ 1, t
);
429 if (retval
!= ERROR_OK
)
432 uint64_t q
= buf_get_u64(value
, 0, 64);
433 LOG_DEBUG("write %s value 0x%016" PRIx64
, r
->name
, q
);
435 LOG_DEBUG("write %s value 0x%08" PRIx32
, r
->name
, t
);
446 LOG_ERROR("Error setting register %s", r
->name
);
451 * Returns generic ARM userspace registers to GDB.
453 int armv7m_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
454 int *reg_list_size
, enum target_register_class reg_class
)
456 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
459 if (reg_class
== REG_CLASS_ALL
)
460 size
= armv7m
->arm
.core_cache
->num_regs
;
462 size
= ARMV7M_NUM_CORE_REGS
;
464 *reg_list
= malloc(sizeof(struct reg
*) * size
);
465 if (*reg_list
== NULL
)
468 for (i
= 0; i
< size
; i
++)
469 (*reg_list
)[i
] = &armv7m
->arm
.core_cache
->reg_list
[i
];
471 *reg_list_size
= size
;
476 /** Runs a Thumb algorithm in the target. */
477 int armv7m_run_algorithm(struct target
*target
,
478 int num_mem_params
, struct mem_param
*mem_params
,
479 int num_reg_params
, struct reg_param
*reg_params
,
480 target_addr_t entry_point
, target_addr_t exit_point
,
481 int timeout_ms
, void *arch_info
)
485 retval
= armv7m_start_algorithm(target
,
486 num_mem_params
, mem_params
,
487 num_reg_params
, reg_params
,
488 entry_point
, exit_point
,
491 if (retval
== ERROR_OK
)
492 retval
= armv7m_wait_algorithm(target
,
493 num_mem_params
, mem_params
,
494 num_reg_params
, reg_params
,
495 exit_point
, timeout_ms
,
501 /** Starts a Thumb algorithm in the target. */
502 int armv7m_start_algorithm(struct target
*target
,
503 int num_mem_params
, struct mem_param
*mem_params
,
504 int num_reg_params
, struct reg_param
*reg_params
,
505 target_addr_t entry_point
, target_addr_t exit_point
,
508 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
509 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
510 enum arm_mode core_mode
= armv7m
->arm
.core_mode
;
511 int retval
= ERROR_OK
;
513 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
514 * at the exit point */
516 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
517 LOG_ERROR("current target isn't an ARMV7M target");
518 return ERROR_TARGET_INVALID
;
521 if (target
->state
!= TARGET_HALTED
) {
522 LOG_WARNING("target not halted");
523 return ERROR_TARGET_NOT_HALTED
;
526 /* Store all non-debug execution registers to armv7m_algorithm_info context */
527 for (unsigned i
= 0; i
< armv7m
->arm
.core_cache
->num_regs
; i
++) {
529 armv7m_algorithm_info
->context
[i
] = buf_get_u32(
530 armv7m
->arm
.core_cache
->reg_list
[i
].value
,
535 for (int i
= 0; i
< num_mem_params
; i
++) {
536 if (mem_params
[i
].direction
== PARAM_IN
)
538 retval
= target_write_buffer(target
, mem_params
[i
].address
,
540 mem_params
[i
].value
);
541 if (retval
!= ERROR_OK
)
545 for (int i
= 0; i
< num_reg_params
; i
++) {
546 if (reg_params
[i
].direction
== PARAM_IN
)
550 register_get_by_name(armv7m
->arm
.core_cache
, reg_params
[i
].reg_name
, 0);
551 /* uint32_t regvalue; */
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
) {
559 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
560 reg_params
[i
].reg_name
);
561 return ERROR_COMMAND_SYNTAX_ERROR
;
564 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
565 armv7m_set_core_reg(reg
, reg_params
[i
].value
);
570 * Ensure xPSR.T is set to avoid trying to run things in arm
571 * (non-thumb) mode, which armv7m does not support.
573 * We do this by setting the entirety of xPSR, which should
574 * remove all the unknowns about xPSR state.
576 * Because xPSR.T is populated on reset from the vector table,
577 * it might be 0 if the vector table has "bad" data in it.
579 struct reg
*reg
= &armv7m
->arm
.core_cache
->reg_list
[ARMV7M_xPSR
];
580 buf_set_u32(reg
->value
, 0, 32, 0x01000000);
585 if (armv7m_algorithm_info
->core_mode
!= ARM_MODE_ANY
&&
586 armv7m_algorithm_info
->core_mode
!= core_mode
) {
588 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
589 if (armv7m_algorithm_info
->core_mode
== ARM_MODE_HANDLER
) {
590 armv7m_algorithm_info
->core_mode
= ARM_MODE_THREAD
;
591 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
594 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
595 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
596 0, 1, armv7m_algorithm_info
->core_mode
);
597 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
598 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
601 /* save previous core mode */
602 armv7m_algorithm_info
->core_mode
= core_mode
;
604 retval
= target_resume(target
, 0, entry_point
, 1, 1);
609 /** Waits for an algorithm in the target. */
610 int armv7m_wait_algorithm(struct target
*target
,
611 int num_mem_params
, struct mem_param
*mem_params
,
612 int num_reg_params
, struct reg_param
*reg_params
,
613 target_addr_t exit_point
, int timeout_ms
,
616 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
617 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
618 int retval
= ERROR_OK
;
620 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
621 * at the exit point */
623 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
624 LOG_ERROR("current target isn't an ARMV7M target");
625 return ERROR_TARGET_INVALID
;
628 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
629 /* If the target fails to halt due to the breakpoint, force a halt */
630 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
631 retval
= target_halt(target
);
632 if (retval
!= ERROR_OK
)
634 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
635 if (retval
!= ERROR_OK
)
637 return ERROR_TARGET_TIMEOUT
;
641 /* PC value has been cached in cortex_m_debug_entry() */
642 uint32_t pc
= buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32);
643 if (pc
!= exit_point
) {
644 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
", expected 0x%" TARGET_PRIxADDR
,
646 return ERROR_TARGET_ALGO_EXIT
;
650 /* Read memory values to mem_params[] */
651 for (int i
= 0; i
< num_mem_params
; i
++) {
652 if (mem_params
[i
].direction
!= PARAM_OUT
) {
653 retval
= target_read_buffer(target
, mem_params
[i
].address
,
655 mem_params
[i
].value
);
656 if (retval
!= ERROR_OK
)
661 /* Copy core register values to reg_params[] */
662 for (int i
= 0; i
< num_reg_params
; i
++) {
663 if (reg_params
[i
].direction
!= PARAM_OUT
) {
664 struct reg
*reg
= register_get_by_name(armv7m
->arm
.core_cache
,
665 reg_params
[i
].reg_name
,
669 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
670 return ERROR_COMMAND_SYNTAX_ERROR
;
673 if (reg
->size
!= reg_params
[i
].size
) {
675 "BUG: register '%s' size doesn't match reg_params[i].size",
676 reg_params
[i
].reg_name
);
677 return ERROR_COMMAND_SYNTAX_ERROR
;
680 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
684 for (int i
= armv7m
->arm
.core_cache
->num_regs
- 1; i
>= 0; i
--) {
686 regvalue
= buf_get_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
, 0, 32);
687 if (regvalue
!= armv7m_algorithm_info
->context
[i
]) {
688 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
689 armv7m
->arm
.core_cache
->reg_list
[i
].name
,
690 armv7m_algorithm_info
->context
[i
]);
691 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
,
692 0, 32, armv7m_algorithm_info
->context
[i
]);
693 armv7m
->arm
.core_cache
->reg_list
[i
].valid
= true;
694 armv7m
->arm
.core_cache
->reg_list
[i
].dirty
= true;
698 /* restore previous core mode */
699 if (armv7m_algorithm_info
->core_mode
!= armv7m
->arm
.core_mode
) {
700 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
701 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
702 0, 1, armv7m_algorithm_info
->core_mode
);
703 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
704 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
707 armv7m
->arm
.core_mode
= armv7m_algorithm_info
->core_mode
;
712 /** Logs summary of ARMv7-M state for a halted target. */
713 int armv7m_arch_state(struct target
*target
)
715 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
716 struct arm
*arm
= &armv7m
->arm
;
719 /* avoid filling log waiting for fileio reply */
720 if (target
->semihosting
&& target
->semihosting
->hit_fileio
)
723 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
724 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
726 LOG_USER("target halted due to %s, current mode: %s %s\n"
727 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s%s",
728 debug_reason_name(target
),
729 arm_mode_name(arm
->core_mode
),
730 armv7m_exception_string(armv7m
->exception_number
),
731 buf_get_u32(arm
->cpsr
->value
, 0, 32),
732 buf_get_u32(arm
->pc
->value
, 0, 32),
733 (ctrl
& 0x02) ? 'p' : 'm',
735 (target
->semihosting
&& target
->semihosting
->is_active
) ? ", semihosting" : "",
736 (target
->semihosting
&& target
->semihosting
->is_fileio
) ? " fileio" : "");
741 static const struct reg_arch_type armv7m_reg_type
= {
742 .get
= armv7m_get_core_reg
,
743 .set
= armv7m_set_core_reg
,
746 /** Builds cache of architecturally defined registers. */
747 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
749 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
750 struct arm
*arm
= &armv7m
->arm
;
751 int num_regs
= ARMV7M_NUM_REGS
;
752 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
753 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
754 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
755 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
756 struct reg_feature
*feature
;
759 /* Build the process context cache */
760 cache
->name
= "arm v7m registers";
762 cache
->reg_list
= reg_list
;
763 cache
->num_regs
= num_regs
;
766 for (i
= 0; i
< num_regs
; i
++) {
767 arch_info
[i
].num
= armv7m_regs
[i
].id
;
768 arch_info
[i
].target
= target
;
769 arch_info
[i
].arm
= arm
;
771 reg_list
[i
].name
= armv7m_regs
[i
].name
;
772 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
773 reg_list
[i
].value
= arch_info
[i
].value
;
774 reg_list
[i
].dirty
= false;
775 reg_list
[i
].valid
= false;
776 reg_list
[i
].hidden
= (i
== ARMV7M_PMSK_BPRI_FLTMSK_CTRL
||
777 i
== ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS
|| i
== ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S
);
778 reg_list
[i
].type
= &armv7m_reg_type
;
779 reg_list
[i
].arch_info
= &arch_info
[i
];
781 reg_list
[i
].group
= armv7m_regs
[i
].group
;
782 reg_list
[i
].number
= i
;
783 reg_list
[i
].exist
= true;
784 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
786 if (reg_list
[i
].hidden
)
789 feature
= calloc(1, sizeof(struct reg_feature
));
791 feature
->name
= armv7m_regs
[i
].feature
;
792 reg_list
[i
].feature
= feature
;
794 LOG_ERROR("unable to allocate feature list");
796 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
797 if (reg_list
[i
].reg_data_type
)
798 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
800 LOG_ERROR("unable to allocate reg type list");
803 arm
->cpsr
= reg_list
+ ARMV7M_xPSR
;
804 arm
->pc
= reg_list
+ ARMV7M_PC
;
805 arm
->core_cache
= cache
;
810 void armv7m_free_reg_cache(struct target
*target
)
812 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
813 struct arm
*arm
= &armv7m
->arm
;
814 struct reg_cache
*cache
;
818 cache
= arm
->core_cache
;
823 for (i
= 0; i
< cache
->num_regs
; i
++) {
824 reg
= &cache
->reg_list
[i
];
827 free(reg
->reg_data_type
);
830 free(cache
->reg_list
[0].arch_info
);
831 free(cache
->reg_list
);
834 arm
->core_cache
= NULL
;
837 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
839 /* nothing todo for armv7m */
843 /** Sets up target as a generic ARMv7-M core */
844 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
846 struct arm
*arm
= &armv7m
->arm
;
848 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
849 armv7m
->fp_feature
= FP_NONE
;
850 armv7m
->trace_config
.trace_bus_id
= 1;
851 /* Enable stimulus port #0 by default */
852 armv7m
->trace_config
.itm_ter
[0] = 1;
854 arm
->core_type
= ARM_CORE_TYPE_M_PROFILE
;
855 arm
->arch_info
= armv7m
;
856 arm
->setup_semihosting
= armv7m_setup_semihosting
;
858 arm
->read_core_reg
= armv7m_read_core_reg
;
859 arm
->write_core_reg
= armv7m_write_core_reg
;
861 return arm_init_arch_info(target
, arm
);
864 /** Generates a CRC32 checksum of a memory region. */
865 int armv7m_checksum_memory(struct target
*target
,
866 target_addr_t address
, uint32_t count
, uint32_t *checksum
)
868 struct working_area
*crc_algorithm
;
869 struct armv7m_algorithm armv7m_info
;
870 struct reg_param reg_params
[2];
873 static const uint8_t cortex_m_crc_code
[] = {
874 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
877 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
878 if (retval
!= ERROR_OK
)
881 retval
= target_write_buffer(target
, crc_algorithm
->address
,
882 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
883 if (retval
!= ERROR_OK
)
886 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
887 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
889 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
890 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
892 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
893 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
895 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
897 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
898 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
899 timeout
, &armv7m_info
);
901 if (retval
== ERROR_OK
)
902 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
904 LOG_ERROR("error executing cortex_m crc algorithm");
906 destroy_reg_param(®_params
[0]);
907 destroy_reg_param(®_params
[1]);
910 target_free_working_area(target
, crc_algorithm
);
915 /** Checks an array of memory regions whether they are erased. */
916 int armv7m_blank_check_memory(struct target
*target
,
917 struct target_memory_check_block
*blocks
, int num_blocks
, uint8_t erased_value
)
919 struct working_area
*erase_check_algorithm
;
920 struct working_area
*erase_check_params
;
921 struct reg_param reg_params
[2];
922 struct armv7m_algorithm armv7m_info
;
925 static bool timed_out
;
927 static const uint8_t erase_check_code
[] = {
928 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
931 const uint32_t code_size
= sizeof(erase_check_code
);
933 /* make sure we have a working area */
934 if (target_alloc_working_area(target
, code_size
,
935 &erase_check_algorithm
) != ERROR_OK
)
936 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
938 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
939 code_size
, erase_check_code
);
940 if (retval
!= ERROR_OK
)
943 /* prepare blocks array for algo */
952 uint32_t avail
= target_get_working_area_avail(target
);
953 int blocks_to_check
= avail
/ sizeof(struct algo_block
) - 1;
954 if (num_blocks
< blocks_to_check
)
955 blocks_to_check
= num_blocks
;
957 struct algo_block
*params
= malloc((blocks_to_check
+1)*sizeof(struct algo_block
));
958 if (params
== NULL
) {
964 uint32_t total_size
= 0;
965 for (i
= 0; i
< blocks_to_check
; i
++) {
966 total_size
+= blocks
[i
].size
;
967 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].size
),
968 blocks
[i
].size
/ sizeof(uint32_t));
969 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].address
),
972 target_buffer_set_u32(target
, (uint8_t *)&(params
[blocks_to_check
].size
), 0);
974 uint32_t param_size
= (blocks_to_check
+ 1) * sizeof(struct algo_block
);
975 if (target_alloc_working_area(target
, param_size
,
976 &erase_check_params
) != ERROR_OK
) {
977 retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
981 retval
= target_write_buffer(target
, erase_check_params
->address
,
982 param_size
, (uint8_t *)params
);
983 if (retval
!= ERROR_OK
)
986 uint32_t erased_word
= erased_value
| (erased_value
<< 8)
987 | (erased_value
<< 16) | (erased_value
<< 24);
989 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
990 TARGET_ADDR_FMT
, blocks_to_check
, erase_check_params
->address
);
992 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
993 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
995 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
996 buf_set_u32(reg_params
[0].value
, 0, 32, erase_check_params
->address
);
998 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
999 buf_set_u32(reg_params
[1].value
, 0, 32, erased_word
);
1001 /* assume CPU clk at least 1 MHz */
1002 int timeout
= (timed_out
? 30000 : 2000) + total_size
* 3 / 1000;
1004 retval
= target_run_algorithm(target
,
1006 ARRAY_SIZE(reg_params
), reg_params
,
1007 erase_check_algorithm
->address
,
1008 erase_check_algorithm
->address
+ (code_size
- 2),
1012 timed_out
= retval
== ERROR_TARGET_TIMEOUT
;
1013 if (retval
!= ERROR_OK
&& !timed_out
)
1016 retval
= target_read_buffer(target
, erase_check_params
->address
,
1017 param_size
, (uint8_t *)params
);
1018 if (retval
!= ERROR_OK
)
1021 for (i
= 0; i
< blocks_to_check
; i
++) {
1022 uint32_t result
= target_buffer_get_u32(target
,
1023 (uint8_t *)&(params
[i
].result
));
1024 if (result
!= 0 && result
!= 1)
1027 blocks
[i
].result
= result
;
1030 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i
, num_blocks
-i
);
1032 retval
= i
; /* return number of blocks really checked */
1035 destroy_reg_param(®_params
[0]);
1036 destroy_reg_param(®_params
[1]);
1039 target_free_working_area(target
, erase_check_params
);
1043 target_free_working_area(target
, erase_check_algorithm
);
1048 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
1050 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
1051 struct reg
*r
= armv7m
->arm
.pc
;
1052 bool result
= false;
1055 /* if we halted last time due to a bkpt instruction
1056 * then we have to manually step over it, otherwise
1057 * the core will break again */
1059 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
1061 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
1064 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
1065 if ((op
& 0xFF00) == 0xBE00) {
1066 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
1067 buf_set_u32(r
->value
, 0, 32, pc
);
1071 LOG_DEBUG("Skipping over BKPT instruction");
1077 *inst_found
= result
;
1082 const struct command_registration armv7m_command_handlers
[] = {
1084 .chain
= arm_command_handlers
,
1086 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)