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
);
258 armv7m_core_reg
= armv7m
->arm
.core_cache
->reg_list
[num
].arch_info
;
260 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
262 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
263 /* map D0..D15 to S0..S31 */
264 retval
= armv7m
->load_core_reg_u32(target
, regsel
, ®_value
);
265 if (retval
!= ERROR_OK
)
267 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
,
269 retval
= armv7m
->load_core_reg_u32(target
, regsel
+ 1, ®_value
);
270 if (retval
!= ERROR_OK
)
272 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
+ 4,
275 retval
= armv7m
->load_core_reg_u32(target
,
277 if (retval
!= ERROR_OK
)
279 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
, 0, 32, reg_value
);
282 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= true;
283 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= false;
288 static int armv7m_write_core_reg(struct target
*target
, struct reg
*r
,
289 int num
, enum arm_mode mode
, uint8_t *value
)
292 struct arm_reg
*armv7m_core_reg
;
293 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
295 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
297 armv7m_core_reg
= armv7m
->arm
.core_cache
->reg_list
[num
].arch_info
;
299 uint32_t regsel
= armv7m_map_id_to_regsel(armv7m_core_reg
->num
);
301 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
302 /* map D0..D15 to S0..S31 */
303 uint32_t t
= buf_get_u32(value
, 0, 32);
304 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
305 if (retval
!= ERROR_OK
)
308 t
= buf_get_u32(value
+ 4, 0, 32);
309 retval
= armv7m
->store_core_reg_u32(target
, regsel
+ 1, t
);
310 if (retval
!= ERROR_OK
)
313 uint32_t t
= buf_get_u32(value
, 0, 32);
315 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", num
, t
);
316 retval
= armv7m
->store_core_reg_u32(target
, regsel
, t
);
317 if (retval
!= ERROR_OK
)
321 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= true;
322 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= false;
327 LOG_ERROR("Error setting register");
328 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= armv7m
->arm
.core_cache
->reg_list
[num
].valid
;
329 return ERROR_JTAG_DEVICE_ERROR
;
333 * Returns generic ARM userspace registers to GDB.
335 int armv7m_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
336 int *reg_list_size
, enum target_register_class reg_class
)
338 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
341 if (reg_class
== REG_CLASS_ALL
)
342 size
= armv7m
->arm
.core_cache
->num_regs
;
344 size
= ARMV7M_NUM_CORE_REGS
;
346 *reg_list
= malloc(sizeof(struct reg
*) * size
);
347 if (*reg_list
== NULL
)
350 for (i
= 0; i
< size
; i
++)
351 (*reg_list
)[i
] = &armv7m
->arm
.core_cache
->reg_list
[i
];
353 *reg_list_size
= size
;
358 /** Runs a Thumb algorithm in the target. */
359 int armv7m_run_algorithm(struct target
*target
,
360 int num_mem_params
, struct mem_param
*mem_params
,
361 int num_reg_params
, struct reg_param
*reg_params
,
362 target_addr_t entry_point
, target_addr_t exit_point
,
363 int timeout_ms
, void *arch_info
)
367 retval
= armv7m_start_algorithm(target
,
368 num_mem_params
, mem_params
,
369 num_reg_params
, reg_params
,
370 entry_point
, exit_point
,
373 if (retval
== ERROR_OK
)
374 retval
= armv7m_wait_algorithm(target
,
375 num_mem_params
, mem_params
,
376 num_reg_params
, reg_params
,
377 exit_point
, timeout_ms
,
383 /** Starts a Thumb algorithm in the target. */
384 int armv7m_start_algorithm(struct target
*target
,
385 int num_mem_params
, struct mem_param
*mem_params
,
386 int num_reg_params
, struct reg_param
*reg_params
,
387 target_addr_t entry_point
, target_addr_t exit_point
,
390 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
391 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
392 enum arm_mode core_mode
= armv7m
->arm
.core_mode
;
393 int retval
= ERROR_OK
;
395 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
396 * at the exit point */
398 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
399 LOG_ERROR("current target isn't an ARMV7M target");
400 return ERROR_TARGET_INVALID
;
403 if (target
->state
!= TARGET_HALTED
) {
404 LOG_WARNING("target not halted");
405 return ERROR_TARGET_NOT_HALTED
;
408 /* refresh core register cache
409 * Not needed if core register cache is always consistent with target process state */
410 for (unsigned i
= 0; i
< armv7m
->arm
.core_cache
->num_regs
; i
++) {
412 armv7m_algorithm_info
->context
[i
] = buf_get_u32(
413 armv7m
->arm
.core_cache
->reg_list
[i
].value
,
418 for (int i
= 0; i
< num_mem_params
; i
++) {
419 if (mem_params
[i
].direction
== PARAM_IN
)
421 retval
= target_write_buffer(target
, mem_params
[i
].address
,
423 mem_params
[i
].value
);
424 if (retval
!= ERROR_OK
)
428 for (int i
= 0; i
< num_reg_params
; i
++) {
429 if (reg_params
[i
].direction
== PARAM_IN
)
433 register_get_by_name(armv7m
->arm
.core_cache
, reg_params
[i
].reg_name
, 0);
434 /* uint32_t regvalue; */
437 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
438 return ERROR_COMMAND_SYNTAX_ERROR
;
441 if (reg
->size
!= reg_params
[i
].size
) {
442 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
443 reg_params
[i
].reg_name
);
444 return ERROR_COMMAND_SYNTAX_ERROR
;
447 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
448 armv7m_set_core_reg(reg
, reg_params
[i
].value
);
453 * Ensure xPSR.T is set to avoid trying to run things in arm
454 * (non-thumb) mode, which armv7m does not support.
456 * We do this by setting the entirety of xPSR, which should
457 * remove all the unknowns about xPSR state.
459 * Because xPSR.T is populated on reset from the vector table,
460 * it might be 0 if the vector table has "bad" data in it.
462 struct reg
*reg
= &armv7m
->arm
.core_cache
->reg_list
[ARMV7M_xPSR
];
463 buf_set_u32(reg
->value
, 0, 32, 0x01000000);
468 if (armv7m_algorithm_info
->core_mode
!= ARM_MODE_ANY
&&
469 armv7m_algorithm_info
->core_mode
!= core_mode
) {
471 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
472 if (armv7m_algorithm_info
->core_mode
== ARM_MODE_HANDLER
) {
473 armv7m_algorithm_info
->core_mode
= ARM_MODE_THREAD
;
474 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
477 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
478 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
479 0, 1, armv7m_algorithm_info
->core_mode
);
480 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
481 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
484 /* save previous core mode */
485 armv7m_algorithm_info
->core_mode
= core_mode
;
487 retval
= target_resume(target
, 0, entry_point
, 1, 1);
492 /** Waits for an algorithm in the target. */
493 int armv7m_wait_algorithm(struct target
*target
,
494 int num_mem_params
, struct mem_param
*mem_params
,
495 int num_reg_params
, struct reg_param
*reg_params
,
496 target_addr_t exit_point
, int timeout_ms
,
499 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
500 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
501 int retval
= ERROR_OK
;
503 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
504 * at the exit point */
506 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
507 LOG_ERROR("current target isn't an ARMV7M target");
508 return ERROR_TARGET_INVALID
;
511 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
512 /* If the target fails to halt due to the breakpoint, force a halt */
513 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
514 retval
= target_halt(target
);
515 if (retval
!= ERROR_OK
)
517 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
518 if (retval
!= ERROR_OK
)
520 return ERROR_TARGET_TIMEOUT
;
524 /* PC value has been cached in cortex_m_debug_entry() */
525 uint32_t pc
= buf_get_u32(armv7m
->arm
.pc
->value
, 0, 32);
526 if (pc
!= exit_point
) {
527 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
", expected 0x%" TARGET_PRIxADDR
,
529 return ERROR_TARGET_ALGO_EXIT
;
533 /* Read memory values to mem_params[] */
534 for (int i
= 0; i
< num_mem_params
; i
++) {
535 if (mem_params
[i
].direction
!= PARAM_OUT
) {
536 retval
= target_read_buffer(target
, mem_params
[i
].address
,
538 mem_params
[i
].value
);
539 if (retval
!= ERROR_OK
)
544 /* Copy core register values to reg_params[] */
545 for (int i
= 0; i
< num_reg_params
; i
++) {
546 if (reg_params
[i
].direction
!= PARAM_OUT
) {
547 struct reg
*reg
= register_get_by_name(armv7m
->arm
.core_cache
,
548 reg_params
[i
].reg_name
,
552 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
553 return ERROR_COMMAND_SYNTAX_ERROR
;
556 if (reg
->size
!= reg_params
[i
].size
) {
558 "BUG: register '%s' size doesn't match reg_params[i].size",
559 reg_params
[i
].reg_name
);
560 return ERROR_COMMAND_SYNTAX_ERROR
;
563 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
567 for (int i
= armv7m
->arm
.core_cache
->num_regs
- 1; i
>= 0; i
--) {
569 regvalue
= buf_get_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
, 0, 32);
570 if (regvalue
!= armv7m_algorithm_info
->context
[i
]) {
571 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
572 armv7m
->arm
.core_cache
->reg_list
[i
].name
,
573 armv7m_algorithm_info
->context
[i
]);
574 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
,
575 0, 32, armv7m_algorithm_info
->context
[i
]);
576 armv7m
->arm
.core_cache
->reg_list
[i
].valid
= true;
577 armv7m
->arm
.core_cache
->reg_list
[i
].dirty
= true;
581 /* restore previous core mode */
582 if (armv7m_algorithm_info
->core_mode
!= armv7m
->arm
.core_mode
) {
583 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
584 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
585 0, 1, armv7m_algorithm_info
->core_mode
);
586 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= true;
587 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= true;
590 armv7m
->arm
.core_mode
= armv7m_algorithm_info
->core_mode
;
595 /** Logs summary of ARMv7-M state for a halted target. */
596 int armv7m_arch_state(struct target
*target
)
598 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
599 struct arm
*arm
= &armv7m
->arm
;
602 /* avoid filling log waiting for fileio reply */
603 if (target
->semihosting
&& target
->semihosting
->hit_fileio
)
606 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
607 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
609 LOG_USER("target halted due to %s, current mode: %s %s\n"
610 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s%s",
611 debug_reason_name(target
),
612 arm_mode_name(arm
->core_mode
),
613 armv7m_exception_string(armv7m
->exception_number
),
614 buf_get_u32(arm
->cpsr
->value
, 0, 32),
615 buf_get_u32(arm
->pc
->value
, 0, 32),
616 (ctrl
& 0x02) ? 'p' : 'm',
618 (target
->semihosting
&& target
->semihosting
->is_active
) ? ", semihosting" : "",
619 (target
->semihosting
&& target
->semihosting
->is_fileio
) ? " fileio" : "");
624 static const struct reg_arch_type armv7m_reg_type
= {
625 .get
= armv7m_get_core_reg
,
626 .set
= armv7m_set_core_reg
,
629 /** Builds cache of architecturally defined registers. */
630 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
632 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
633 struct arm
*arm
= &armv7m
->arm
;
634 int num_regs
= ARMV7M_NUM_REGS
;
635 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
636 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
637 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
638 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
639 struct reg_feature
*feature
;
642 /* Build the process context cache */
643 cache
->name
= "arm v7m registers";
645 cache
->reg_list
= reg_list
;
646 cache
->num_regs
= num_regs
;
649 for (i
= 0; i
< num_regs
; i
++) {
650 arch_info
[i
].num
= armv7m_regs
[i
].id
;
651 arch_info
[i
].target
= target
;
652 arch_info
[i
].arm
= arm
;
654 reg_list
[i
].name
= armv7m_regs
[i
].name
;
655 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
656 size_t storage_size
= DIV_ROUND_UP(armv7m_regs
[i
].bits
, 8);
657 if (storage_size
< 4)
659 reg_list
[i
].value
= calloc(1, storage_size
);
660 reg_list
[i
].dirty
= false;
661 reg_list
[i
].valid
= false;
662 reg_list
[i
].type
= &armv7m_reg_type
;
663 reg_list
[i
].arch_info
= &arch_info
[i
];
665 reg_list
[i
].group
= armv7m_regs
[i
].group
;
666 reg_list
[i
].number
= i
;
667 reg_list
[i
].exist
= true;
668 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
670 feature
= calloc(1, sizeof(struct reg_feature
));
672 feature
->name
= armv7m_regs
[i
].feature
;
673 reg_list
[i
].feature
= feature
;
675 LOG_ERROR("unable to allocate feature list");
677 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
678 if (reg_list
[i
].reg_data_type
)
679 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
681 LOG_ERROR("unable to allocate reg type list");
684 arm
->cpsr
= reg_list
+ ARMV7M_xPSR
;
685 arm
->pc
= reg_list
+ ARMV7M_PC
;
686 arm
->core_cache
= cache
;
691 void armv7m_free_reg_cache(struct target
*target
)
693 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
694 struct arm
*arm
= &armv7m
->arm
;
695 struct reg_cache
*cache
;
699 cache
= arm
->core_cache
;
704 for (i
= 0; i
< cache
->num_regs
; i
++) {
705 reg
= &cache
->reg_list
[i
];
708 free(reg
->reg_data_type
);
712 free(cache
->reg_list
[0].arch_info
);
713 free(cache
->reg_list
);
716 arm
->core_cache
= NULL
;
719 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
721 /* nothing todo for armv7m */
725 /** Sets up target as a generic ARMv7-M core */
726 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
728 struct arm
*arm
= &armv7m
->arm
;
730 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
731 armv7m
->fp_feature
= FP_NONE
;
732 armv7m
->trace_config
.trace_bus_id
= 1;
733 /* Enable stimulus port #0 by default */
734 armv7m
->trace_config
.itm_ter
[0] = 1;
736 arm
->core_type
= ARM_CORE_TYPE_M_PROFILE
;
737 arm
->arch_info
= armv7m
;
738 arm
->setup_semihosting
= armv7m_setup_semihosting
;
740 arm
->read_core_reg
= armv7m_read_core_reg
;
741 arm
->write_core_reg
= armv7m_write_core_reg
;
743 return arm_init_arch_info(target
, arm
);
746 /** Generates a CRC32 checksum of a memory region. */
747 int armv7m_checksum_memory(struct target
*target
,
748 target_addr_t address
, uint32_t count
, uint32_t *checksum
)
750 struct working_area
*crc_algorithm
;
751 struct armv7m_algorithm armv7m_info
;
752 struct reg_param reg_params
[2];
755 static const uint8_t cortex_m_crc_code
[] = {
756 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
759 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
760 if (retval
!= ERROR_OK
)
763 retval
= target_write_buffer(target
, crc_algorithm
->address
,
764 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
765 if (retval
!= ERROR_OK
)
768 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
769 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
771 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
772 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
774 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
775 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
777 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
779 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
780 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
781 timeout
, &armv7m_info
);
783 if (retval
== ERROR_OK
)
784 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
786 LOG_ERROR("error executing cortex_m crc algorithm");
788 destroy_reg_param(®_params
[0]);
789 destroy_reg_param(®_params
[1]);
792 target_free_working_area(target
, crc_algorithm
);
797 /** Checks an array of memory regions whether they are erased. */
798 int armv7m_blank_check_memory(struct target
*target
,
799 struct target_memory_check_block
*blocks
, int num_blocks
, uint8_t erased_value
)
801 struct working_area
*erase_check_algorithm
;
802 struct working_area
*erase_check_params
;
803 struct reg_param reg_params
[2];
804 struct armv7m_algorithm armv7m_info
;
807 static bool timed_out
;
809 static const uint8_t erase_check_code
[] = {
810 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
813 const uint32_t code_size
= sizeof(erase_check_code
);
815 /* make sure we have a working area */
816 if (target_alloc_working_area(target
, code_size
,
817 &erase_check_algorithm
) != ERROR_OK
)
818 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
820 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
821 code_size
, erase_check_code
);
822 if (retval
!= ERROR_OK
)
825 /* prepare blocks array for algo */
834 uint32_t avail
= target_get_working_area_avail(target
);
835 int blocks_to_check
= avail
/ sizeof(struct algo_block
) - 1;
836 if (num_blocks
< blocks_to_check
)
837 blocks_to_check
= num_blocks
;
839 struct algo_block
*params
= malloc((blocks_to_check
+1)*sizeof(struct algo_block
));
840 if (params
== NULL
) {
846 uint32_t total_size
= 0;
847 for (i
= 0; i
< blocks_to_check
; i
++) {
848 total_size
+= blocks
[i
].size
;
849 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].size
),
850 blocks
[i
].size
/ sizeof(uint32_t));
851 target_buffer_set_u32(target
, (uint8_t *)&(params
[i
].address
),
854 target_buffer_set_u32(target
, (uint8_t *)&(params
[blocks_to_check
].size
), 0);
856 uint32_t param_size
= (blocks_to_check
+ 1) * sizeof(struct algo_block
);
857 if (target_alloc_working_area(target
, param_size
,
858 &erase_check_params
) != ERROR_OK
) {
859 retval
= ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
863 retval
= target_write_buffer(target
, erase_check_params
->address
,
864 param_size
, (uint8_t *)params
);
865 if (retval
!= ERROR_OK
)
868 uint32_t erased_word
= erased_value
| (erased_value
<< 8)
869 | (erased_value
<< 16) | (erased_value
<< 24);
871 LOG_DEBUG("Starting erase check of %d blocks, parameters@"
872 TARGET_ADDR_FMT
, blocks_to_check
, erase_check_params
->address
);
874 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
875 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
877 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
878 buf_set_u32(reg_params
[0].value
, 0, 32, erase_check_params
->address
);
880 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
881 buf_set_u32(reg_params
[1].value
, 0, 32, erased_word
);
883 /* assume CPU clk at least 1 MHz */
884 int timeout
= (timed_out
? 30000 : 2000) + total_size
* 3 / 1000;
886 retval
= target_run_algorithm(target
,
888 ARRAY_SIZE(reg_params
), reg_params
,
889 erase_check_algorithm
->address
,
890 erase_check_algorithm
->address
+ (code_size
- 2),
894 timed_out
= retval
== ERROR_TARGET_TIMEOUT
;
895 if (retval
!= ERROR_OK
&& !timed_out
)
898 retval
= target_read_buffer(target
, erase_check_params
->address
,
899 param_size
, (uint8_t *)params
);
900 if (retval
!= ERROR_OK
)
903 for (i
= 0; i
< blocks_to_check
; i
++) {
904 uint32_t result
= target_buffer_get_u32(target
,
905 (uint8_t *)&(params
[i
].result
));
906 if (result
!= 0 && result
!= 1)
909 blocks
[i
].result
= result
;
912 LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i
, num_blocks
-i
);
914 retval
= i
; /* return number of blocks really checked */
917 destroy_reg_param(®_params
[0]);
918 destroy_reg_param(®_params
[1]);
921 target_free_working_area(target
, erase_check_params
);
925 target_free_working_area(target
, erase_check_algorithm
);
930 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
932 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
933 struct reg
*r
= armv7m
->arm
.pc
;
937 /* if we halted last time due to a bkpt instruction
938 * then we have to manually step over it, otherwise
939 * the core will break again */
941 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
943 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
946 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
947 if ((op
& 0xFF00) == 0xBE00) {
948 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
949 buf_set_u32(r
->value
, 0, 32, pc
);
953 LOG_DEBUG("Skipping over BKPT instruction");
959 *inst_found
= result
;
964 const struct command_registration armv7m_command_handlers
[] = {
966 .chain
= arm_command_handlers
,
968 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)