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 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
27 * ARMv7-M Architecture, Application Level Reference Manual *
28 * ARM DDI 0405C (September 2008) *
30 ***************************************************************************/
36 #include "breakpoints.h"
38 #include "algorithm.h"
42 #define _DEBUG_INSTRUCTION_EXECUTION_
45 static const char * const armv7m_exception_strings
[] = {
46 "", "Reset", "NMI", "HardFault",
47 "MemManage", "BusFault", "UsageFault", "RESERVED",
48 "RESERVED", "RESERVED", "RESERVED", "SVCall",
49 "DebugMonitor", "RESERVED", "PendSV", "SysTick"
52 /* PSP is used in some thread modes */
53 const int armv7m_psp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
54 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
55 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
56 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
57 ARMV7M_R12
, ARMV7M_PSP
, ARMV7M_R14
, ARMV7M_PC
,
61 /* MSP is used in handler and some thread modes */
62 const int armv7m_msp_reg_map
[ARMV7M_NUM_CORE_REGS
] = {
63 ARMV7M_R0
, ARMV7M_R1
, ARMV7M_R2
, ARMV7M_R3
,
64 ARMV7M_R4
, ARMV7M_R5
, ARMV7M_R6
, ARMV7M_R7
,
65 ARMV7M_R8
, ARMV7M_R9
, ARMV7M_R10
, ARMV7M_R11
,
66 ARMV7M_R12
, ARMV7M_MSP
, ARMV7M_R14
, ARMV7M_PC
,
71 * These registers are not memory-mapped. The ARMv7-M profile includes
72 * memory mapped registers too, such as for the NVIC (interrupt controller)
73 * and SysTick (timer) modules; those can mostly be treated as peripherals.
75 * The ARMv6-M profile is almost identical in this respect, except that it
76 * doesn't include basepri or faultmask registers.
86 { ARMV7M_R0
, "r0", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
87 { ARMV7M_R1
, "r1", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
88 { ARMV7M_R2
, "r2", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
89 { ARMV7M_R3
, "r3", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
90 { ARMV7M_R4
, "r4", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
91 { ARMV7M_R5
, "r5", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
92 { ARMV7M_R6
, "r6", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
93 { ARMV7M_R7
, "r7", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
94 { ARMV7M_R8
, "r8", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
95 { ARMV7M_R9
, "r9", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
96 { ARMV7M_R10
, "r10", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
97 { ARMV7M_R11
, "r11", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
98 { ARMV7M_R12
, "r12", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
99 { ARMV7M_R13
, "sp", 32, REG_TYPE_DATA_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
100 { ARMV7M_R14
, "lr", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
101 { ARMV7M_PC
, "pc", 32, REG_TYPE_CODE_PTR
, "general", "org.gnu.gdb.arm.m-profile" },
102 { ARMV7M_xPSR
, "xPSR", 32, REG_TYPE_INT
, "general", "org.gnu.gdb.arm.m-profile" },
104 { ARMV7M_MSP
, "msp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
105 { ARMV7M_PSP
, "psp", 32, REG_TYPE_DATA_PTR
, "system", "org.gnu.gdb.arm.m-system" },
107 { ARMV7M_PRIMASK
, "primask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
108 { ARMV7M_BASEPRI
, "basepri", 8, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
109 { ARMV7M_FAULTMASK
, "faultmask", 1, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
110 { ARMV7M_CONTROL
, "control", 2, REG_TYPE_INT8
, "system", "org.gnu.gdb.arm.m-system" },
112 { ARMV7M_D0
, "d0", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
113 { ARMV7M_D1
, "d1", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
114 { ARMV7M_D2
, "d2", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
115 { ARMV7M_D3
, "d3", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
116 { ARMV7M_D4
, "d4", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
117 { ARMV7M_D5
, "d5", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
118 { ARMV7M_D6
, "d6", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
119 { ARMV7M_D7
, "d7", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
120 { ARMV7M_D8
, "d8", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
121 { ARMV7M_D9
, "d9", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
122 { ARMV7M_D10
, "d10", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
123 { ARMV7M_D11
, "d11", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
124 { ARMV7M_D12
, "d12", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
125 { ARMV7M_D13
, "d13", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
126 { ARMV7M_D14
, "d14", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
127 { ARMV7M_D15
, "d15", 64, REG_TYPE_IEEE_DOUBLE
, "float", "org.gnu.gdb.arm.vfp" },
129 { ARMV7M_FPSCR
, "fpscr", 32, REG_TYPE_INT
, "float", "org.gnu.gdb.arm.vfp" },
132 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
135 * Restores target context using the cache of core registers set up
136 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
138 int armv7m_restore_context(struct target
*target
)
141 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
142 struct reg_cache
*cache
= armv7m
->arm
.core_cache
;
146 if (armv7m
->pre_restore_context
)
147 armv7m
->pre_restore_context(target
);
149 for (i
= cache
->num_regs
- 1; i
>= 0; i
--) {
150 if (cache
->reg_list
[i
].dirty
) {
151 armv7m
->arm
.write_core_reg(target
, &cache
->reg_list
[i
], i
,
152 ARM_MODE_ANY
, cache
->reg_list
[i
].value
);
159 /* Core state functions */
162 * Maps ISR number (from xPSR) to name.
163 * Note that while names and meanings for the first sixteen are standardized
164 * (with zero not a true exception), external interrupts are only numbered.
165 * They are assigned by vendors, which generally assign different numbers to
166 * peripherals (such as UART0 or a USB peripheral controller).
168 const char *armv7m_exception_string(int number
)
170 static char enamebuf
[32];
172 if ((number
< 0) | (number
> 511))
173 return "Invalid exception";
175 return armv7m_exception_strings
[number
];
176 sprintf(enamebuf
, "External Interrupt(%i)", number
- 16);
180 static int armv7m_get_core_reg(struct reg
*reg
)
183 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
184 struct target
*target
= armv7m_reg
->target
;
185 struct arm
*arm
= target_to_arm(target
);
187 if (target
->state
!= TARGET_HALTED
)
188 return ERROR_TARGET_NOT_HALTED
;
190 retval
= arm
->read_core_reg(target
, reg
, armv7m_reg
->num
, arm
->core_mode
);
195 static int armv7m_set_core_reg(struct reg
*reg
, uint8_t *buf
)
197 struct arm_reg
*armv7m_reg
= reg
->arch_info
;
198 struct target
*target
= armv7m_reg
->target
;
200 if (target
->state
!= TARGET_HALTED
)
201 return ERROR_TARGET_NOT_HALTED
;
203 buf_cpy(buf
, reg
->value
, reg
->size
);
210 static int armv7m_read_core_reg(struct target
*target
, struct reg
*r
,
211 int num
, enum arm_mode mode
)
215 struct arm_reg
*armv7m_core_reg
;
216 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
218 assert(num
< (int)armv7m
->arm
.core_cache
->num_regs
);
220 armv7m_core_reg
= armv7m
->arm
.core_cache
->reg_list
[num
].arch_info
;
222 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
223 /* map D0..D15 to S0..S31 */
224 size_t regidx
= ARMV7M_S0
+ 2 * (armv7m_core_reg
->num
- ARMV7M_D0
);
225 retval
= armv7m
->load_core_reg_u32(target
, regidx
, ®_value
);
226 if (retval
!= ERROR_OK
)
228 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
,
230 retval
= armv7m
->load_core_reg_u32(target
, regidx
+ 1, ®_value
);
231 if (retval
!= ERROR_OK
)
233 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
+ 4,
236 retval
= armv7m
->load_core_reg_u32(target
,
237 armv7m_core_reg
->num
, ®_value
);
238 if (retval
!= ERROR_OK
)
240 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[num
].value
, 0, 32, reg_value
);
243 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= 1;
244 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= 0;
249 static int armv7m_write_core_reg(struct target
*target
, struct reg
*r
,
250 int num
, enum arm_mode mode
, uint8_t *value
)
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 if ((armv7m_core_reg
->num
>= ARMV7M_D0
) && (armv7m_core_reg
->num
<= ARMV7M_D15
)) {
261 /* map D0..D15 to S0..S31 */
262 size_t regidx
= ARMV7M_S0
+ 2 * (armv7m_core_reg
->num
- ARMV7M_D0
);
264 uint32_t t
= buf_get_u32(value
, 0, 32);
265 retval
= armv7m
->store_core_reg_u32(target
, regidx
, t
);
266 if (retval
!= ERROR_OK
)
269 t
= buf_get_u32(value
+ 4, 0, 32);
270 retval
= armv7m
->store_core_reg_u32(target
, regidx
+ 1, t
);
271 if (retval
!= ERROR_OK
)
274 uint32_t t
= buf_get_u32(value
, 0, 32);
276 LOG_DEBUG("write core reg %i value 0x%" PRIx32
"", num
, t
);
277 retval
= armv7m
->store_core_reg_u32(target
, armv7m_core_reg
->num
, t
);
278 if (retval
!= ERROR_OK
)
282 armv7m
->arm
.core_cache
->reg_list
[num
].valid
= 1;
283 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= 0;
288 LOG_ERROR("Error setting register");
289 armv7m
->arm
.core_cache
->reg_list
[num
].dirty
= armv7m
->arm
.core_cache
->reg_list
[num
].valid
;
290 return ERROR_JTAG_DEVICE_ERROR
;
294 * Returns generic ARM userspace registers to GDB.
296 int armv7m_get_gdb_reg_list(struct target
*target
, struct reg
**reg_list
[],
297 int *reg_list_size
, enum target_register_class reg_class
)
299 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
302 if (reg_class
== REG_CLASS_ALL
)
303 *reg_list_size
= armv7m
->arm
.core_cache
->num_regs
;
305 *reg_list_size
= ARMV7M_NUM_CORE_REGS
;
307 *reg_list
= malloc(sizeof(struct reg
*) * (*reg_list_size
));
308 if (*reg_list
== NULL
)
311 for (i
= 0; i
< *reg_list_size
; i
++)
312 (*reg_list
)[i
] = &armv7m
->arm
.core_cache
->reg_list
[i
];
317 /** Runs a Thumb algorithm in the target. */
318 int armv7m_run_algorithm(struct target
*target
,
319 int num_mem_params
, struct mem_param
*mem_params
,
320 int num_reg_params
, struct reg_param
*reg_params
,
321 target_addr_t entry_point
, target_addr_t exit_point
,
322 int timeout_ms
, void *arch_info
)
326 retval
= armv7m_start_algorithm(target
,
327 num_mem_params
, mem_params
,
328 num_reg_params
, reg_params
,
329 entry_point
, exit_point
,
332 if (retval
== ERROR_OK
)
333 retval
= armv7m_wait_algorithm(target
,
334 num_mem_params
, mem_params
,
335 num_reg_params
, reg_params
,
336 exit_point
, timeout_ms
,
342 /** Starts a Thumb algorithm in the target. */
343 int armv7m_start_algorithm(struct target
*target
,
344 int num_mem_params
, struct mem_param
*mem_params
,
345 int num_reg_params
, struct reg_param
*reg_params
,
346 target_addr_t entry_point
, target_addr_t exit_point
,
349 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
350 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
351 enum arm_mode core_mode
= armv7m
->arm
.core_mode
;
352 int retval
= ERROR_OK
;
354 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
355 * at the exit point */
357 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
358 LOG_ERROR("current target isn't an ARMV7M target");
359 return ERROR_TARGET_INVALID
;
362 if (target
->state
!= TARGET_HALTED
) {
363 LOG_WARNING("target not halted");
364 return ERROR_TARGET_NOT_HALTED
;
367 /* refresh core register cache
368 * Not needed if core register cache is always consistent with target process state */
369 for (unsigned i
= 0; i
< armv7m
->arm
.core_cache
->num_regs
; i
++) {
371 armv7m_algorithm_info
->context
[i
] = buf_get_u32(
372 armv7m
->arm
.core_cache
->reg_list
[i
].value
,
377 for (int i
= 0; i
< num_mem_params
; i
++) {
378 /* TODO: Write only out params */
379 retval
= target_write_buffer(target
, mem_params
[i
].address
,
381 mem_params
[i
].value
);
382 if (retval
!= ERROR_OK
)
386 for (int i
= 0; i
< num_reg_params
; i
++) {
388 register_get_by_name(armv7m
->arm
.core_cache
, reg_params
[i
].reg_name
, 0);
389 /* uint32_t regvalue; */
392 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
393 return ERROR_COMMAND_SYNTAX_ERROR
;
396 if (reg
->size
!= reg_params
[i
].size
) {
397 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
398 reg_params
[i
].reg_name
);
399 return ERROR_COMMAND_SYNTAX_ERROR
;
402 /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
403 armv7m_set_core_reg(reg
, reg_params
[i
].value
);
406 if (armv7m_algorithm_info
->core_mode
!= ARM_MODE_ANY
&&
407 armv7m_algorithm_info
->core_mode
!= core_mode
) {
409 /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
410 if (armv7m_algorithm_info
->core_mode
== ARM_MODE_HANDLER
) {
411 armv7m_algorithm_info
->core_mode
= ARM_MODE_THREAD
;
412 LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
415 LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
416 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
417 0, 1, armv7m_algorithm_info
->core_mode
);
418 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= 1;
419 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= 1;
422 /* save previous core mode */
423 armv7m_algorithm_info
->core_mode
= core_mode
;
425 retval
= target_resume(target
, 0, entry_point
, 1, 1);
430 /** Waits for an algorithm in the target. */
431 int armv7m_wait_algorithm(struct target
*target
,
432 int num_mem_params
, struct mem_param
*mem_params
,
433 int num_reg_params
, struct reg_param
*reg_params
,
434 target_addr_t exit_point
, int timeout_ms
,
437 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
438 struct armv7m_algorithm
*armv7m_algorithm_info
= arch_info
;
439 int retval
= ERROR_OK
;
442 /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
443 * at the exit point */
445 if (armv7m_algorithm_info
->common_magic
!= ARMV7M_COMMON_MAGIC
) {
446 LOG_ERROR("current target isn't an ARMV7M target");
447 return ERROR_TARGET_INVALID
;
450 retval
= target_wait_state(target
, TARGET_HALTED
, timeout_ms
);
451 /* If the target fails to halt due to the breakpoint, force a halt */
452 if (retval
!= ERROR_OK
|| target
->state
!= TARGET_HALTED
) {
453 retval
= target_halt(target
);
454 if (retval
!= ERROR_OK
)
456 retval
= target_wait_state(target
, TARGET_HALTED
, 500);
457 if (retval
!= ERROR_OK
)
459 return ERROR_TARGET_TIMEOUT
;
462 armv7m
->load_core_reg_u32(target
, 15, &pc
);
463 if (exit_point
&& (pc
!= exit_point
)) {
464 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32
", expected 0x%" TARGET_PRIxADDR
,
467 return ERROR_TARGET_TIMEOUT
;
470 /* Read memory values to mem_params[] */
471 for (int i
= 0; i
< num_mem_params
; i
++) {
472 if (mem_params
[i
].direction
!= PARAM_OUT
) {
473 retval
= target_read_buffer(target
, mem_params
[i
].address
,
475 mem_params
[i
].value
);
476 if (retval
!= ERROR_OK
)
481 /* Copy core register values to reg_params[] */
482 for (int i
= 0; i
< num_reg_params
; i
++) {
483 if (reg_params
[i
].direction
!= PARAM_OUT
) {
484 struct reg
*reg
= register_get_by_name(armv7m
->arm
.core_cache
,
485 reg_params
[i
].reg_name
,
489 LOG_ERROR("BUG: register '%s' not found", reg_params
[i
].reg_name
);
490 return ERROR_COMMAND_SYNTAX_ERROR
;
493 if (reg
->size
!= reg_params
[i
].size
) {
495 "BUG: register '%s' size doesn't match reg_params[i].size",
496 reg_params
[i
].reg_name
);
497 return ERROR_COMMAND_SYNTAX_ERROR
;
500 buf_set_u32(reg_params
[i
].value
, 0, 32, buf_get_u32(reg
->value
, 0, 32));
504 for (int i
= armv7m
->arm
.core_cache
->num_regs
- 1; i
>= 0; i
--) {
506 regvalue
= buf_get_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
, 0, 32);
507 if (regvalue
!= armv7m_algorithm_info
->context
[i
]) {
508 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32
,
509 armv7m
->arm
.core_cache
->reg_list
[i
].name
,
510 armv7m_algorithm_info
->context
[i
]);
511 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[i
].value
,
512 0, 32, armv7m_algorithm_info
->context
[i
]);
513 armv7m
->arm
.core_cache
->reg_list
[i
].valid
= 1;
514 armv7m
->arm
.core_cache
->reg_list
[i
].dirty
= 1;
518 /* restore previous core mode */
519 if (armv7m_algorithm_info
->core_mode
!= armv7m
->arm
.core_mode
) {
520 LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info
->core_mode
);
521 buf_set_u32(armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].value
,
522 0, 1, armv7m_algorithm_info
->core_mode
);
523 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].dirty
= 1;
524 armv7m
->arm
.core_cache
->reg_list
[ARMV7M_CONTROL
].valid
= 1;
527 armv7m
->arm
.core_mode
= armv7m_algorithm_info
->core_mode
;
532 /** Logs summary of ARMv7-M state for a halted target. */
533 int armv7m_arch_state(struct target
*target
)
535 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
536 struct arm
*arm
= &armv7m
->arm
;
539 /* avoid filling log waiting for fileio reply */
540 if (arm
->semihosting_hit_fileio
)
543 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
544 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
546 LOG_USER("target halted due to %s, current mode: %s %s\n"
547 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s%s",
548 debug_reason_name(target
),
549 arm_mode_name(arm
->core_mode
),
550 armv7m_exception_string(armv7m
->exception_number
),
551 buf_get_u32(arm
->cpsr
->value
, 0, 32),
552 buf_get_u32(arm
->pc
->value
, 0, 32),
553 (ctrl
& 0x02) ? 'p' : 'm',
555 arm
->is_semihosting
? ", semihosting" : "",
556 arm
->is_semihosting_fileio
? " fileio" : "");
561 static const struct reg_arch_type armv7m_reg_type
= {
562 .get
= armv7m_get_core_reg
,
563 .set
= armv7m_set_core_reg
,
566 /** Builds cache of architecturally defined registers. */
567 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
569 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
570 struct arm
*arm
= &armv7m
->arm
;
571 int num_regs
= ARMV7M_NUM_REGS
;
572 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
573 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
574 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
575 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
576 struct reg_feature
*feature
;
579 /* Build the process context cache */
580 cache
->name
= "arm v7m registers";
582 cache
->reg_list
= reg_list
;
583 cache
->num_regs
= num_regs
;
586 for (i
= 0; i
< num_regs
; i
++) {
587 arch_info
[i
].num
= armv7m_regs
[i
].id
;
588 arch_info
[i
].target
= target
;
589 arch_info
[i
].arm
= arm
;
591 reg_list
[i
].name
= armv7m_regs
[i
].name
;
592 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
593 size_t storage_size
= DIV_ROUND_UP(armv7m_regs
[i
].bits
, 8);
594 if (storage_size
< 4)
596 reg_list
[i
].value
= calloc(1, storage_size
);
597 reg_list
[i
].dirty
= 0;
598 reg_list
[i
].valid
= 0;
599 reg_list
[i
].type
= &armv7m_reg_type
;
600 reg_list
[i
].arch_info
= &arch_info
[i
];
602 reg_list
[i
].group
= armv7m_regs
[i
].group
;
603 reg_list
[i
].number
= i
;
604 reg_list
[i
].exist
= true;
605 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
607 feature
= calloc(1, sizeof(struct reg_feature
));
609 feature
->name
= armv7m_regs
[i
].feature
;
610 reg_list
[i
].feature
= feature
;
612 LOG_ERROR("unable to allocate feature list");
614 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
615 if (reg_list
[i
].reg_data_type
)
616 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
618 LOG_ERROR("unable to allocate reg type list");
621 arm
->cpsr
= reg_list
+ ARMV7M_xPSR
;
622 arm
->pc
= reg_list
+ ARMV7M_PC
;
623 arm
->core_cache
= cache
;
628 void armv7m_free_reg_cache(struct target
*target
)
630 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
631 struct arm
*arm
= &armv7m
->arm
;
632 struct reg_cache
*cache
;
636 cache
= arm
->core_cache
;
641 for (i
= 0; i
< cache
->num_regs
; i
++) {
642 reg
= &cache
->reg_list
[i
];
645 free(reg
->reg_data_type
);
649 free(cache
->reg_list
[0].arch_info
);
650 free(cache
->reg_list
);
653 arm
->core_cache
= NULL
;
656 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
658 /* nothing todo for armv7m */
662 /** Sets up target as a generic ARMv7-M core */
663 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
665 struct arm
*arm
= &armv7m
->arm
;
667 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
668 armv7m
->fp_feature
= FP_NONE
;
669 armv7m
->trace_config
.trace_bus_id
= 1;
670 /* Enable stimulus port #0 by default */
671 armv7m
->trace_config
.itm_ter
[0] = 1;
673 arm
->core_type
= ARM_MODE_THREAD
;
674 arm
->arch_info
= armv7m
;
675 arm
->setup_semihosting
= armv7m_setup_semihosting
;
677 arm
->read_core_reg
= armv7m_read_core_reg
;
678 arm
->write_core_reg
= armv7m_write_core_reg
;
680 return arm_init_arch_info(target
, arm
);
683 /** Generates a CRC32 checksum of a memory region. */
684 int armv7m_checksum_memory(struct target
*target
,
685 target_addr_t address
, uint32_t count
, uint32_t *checksum
)
687 struct working_area
*crc_algorithm
;
688 struct armv7m_algorithm armv7m_info
;
689 struct reg_param reg_params
[2];
692 static const uint8_t cortex_m_crc_code
[] = {
693 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
696 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
697 if (retval
!= ERROR_OK
)
700 retval
= target_write_buffer(target
, crc_algorithm
->address
,
701 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
702 if (retval
!= ERROR_OK
)
705 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
706 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
708 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
709 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
711 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
712 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
714 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
716 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
717 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
718 timeout
, &armv7m_info
);
720 if (retval
== ERROR_OK
)
721 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
723 LOG_ERROR("error executing cortex_m crc algorithm");
725 destroy_reg_param(®_params
[0]);
726 destroy_reg_param(®_params
[1]);
729 target_free_working_area(target
, crc_algorithm
);
734 /** Checks whether a memory region is erased. */
735 int armv7m_blank_check_memory(struct target
*target
,
736 target_addr_t address
, uint32_t count
, uint32_t *blank
, uint8_t erased_value
)
738 struct working_area
*erase_check_algorithm
;
739 struct reg_param reg_params
[3];
740 struct armv7m_algorithm armv7m_info
;
745 static const uint8_t erase_check_code
[] = {
746 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
748 static const uint8_t zero_erase_check_code
[] = {
749 #include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
752 switch (erased_value
) {
754 code
= zero_erase_check_code
;
755 code_size
= sizeof(zero_erase_check_code
);
759 code
= erase_check_code
;
760 code_size
= sizeof(erase_check_code
);
763 /* make sure we have a working area */
764 if (target_alloc_working_area(target
, code_size
,
765 &erase_check_algorithm
) != ERROR_OK
)
766 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
768 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
770 if (retval
!= ERROR_OK
)
773 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
774 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
776 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
777 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
779 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
780 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
782 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
783 buf_set_u32(reg_params
[2].value
, 0, 32, erased_value
);
785 retval
= target_run_algorithm(target
,
790 erase_check_algorithm
->address
,
791 erase_check_algorithm
->address
+ (code_size
- 2),
795 if (retval
== ERROR_OK
)
796 *blank
= buf_get_u32(reg_params
[2].value
, 0, 32);
798 destroy_reg_param(®_params
[0]);
799 destroy_reg_param(®_params
[1]);
800 destroy_reg_param(®_params
[2]);
803 target_free_working_area(target
, erase_check_algorithm
);
808 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
810 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
811 struct reg
*r
= armv7m
->arm
.pc
;
815 /* if we halted last time due to a bkpt instruction
816 * then we have to manually step over it, otherwise
817 * the core will break again */
819 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
821 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
824 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
825 if ((op
& 0xFF00) == 0xBE00) {
826 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
827 buf_set_u32(r
->value
, 0, 32, pc
);
831 LOG_DEBUG("Skipping over BKPT instruction");
837 *inst_found
= result
;
842 const struct command_registration armv7m_command_handlers
[] = {
844 .chain
= arm_command_handlers
,
847 .chain
= dap_command_handlers
,
849 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)