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 uint32_t entry_point
, uint32_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 uint32_t entry_point
, uint32_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 uint32_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%" PRIx32
,
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 ctrl
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_CONTROL
].value
, 0, 32);
540 sp
= buf_get_u32(arm
->core_cache
->reg_list
[ARMV7M_R13
].value
, 0, 32);
542 LOG_USER("target halted due to %s, current mode: %s %s\n"
543 "xPSR: %#8.8" PRIx32
" pc: %#8.8" PRIx32
" %csp: %#8.8" PRIx32
"%s",
544 debug_reason_name(target
),
545 arm_mode_name(arm
->core_mode
),
546 armv7m_exception_string(armv7m
->exception_number
),
547 buf_get_u32(arm
->cpsr
->value
, 0, 32),
548 buf_get_u32(arm
->pc
->value
, 0, 32),
549 (ctrl
& 0x02) ? 'p' : 'm',
551 arm
->is_semihosting
? ", semihosting" : "");
556 static const struct reg_arch_type armv7m_reg_type
= {
557 .get
= armv7m_get_core_reg
,
558 .set
= armv7m_set_core_reg
,
561 /** Builds cache of architecturally defined registers. */
562 struct reg_cache
*armv7m_build_reg_cache(struct target
*target
)
564 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
565 struct arm
*arm
= &armv7m
->arm
;
566 int num_regs
= ARMV7M_NUM_REGS
;
567 struct reg_cache
**cache_p
= register_get_last_cache_p(&target
->reg_cache
);
568 struct reg_cache
*cache
= malloc(sizeof(struct reg_cache
));
569 struct reg
*reg_list
= calloc(num_regs
, sizeof(struct reg
));
570 struct arm_reg
*arch_info
= calloc(num_regs
, sizeof(struct arm_reg
));
571 struct reg_feature
*feature
;
574 /* Build the process context cache */
575 cache
->name
= "arm v7m registers";
577 cache
->reg_list
= reg_list
;
578 cache
->num_regs
= num_regs
;
581 for (i
= 0; i
< num_regs
; i
++) {
582 arch_info
[i
].num
= armv7m_regs
[i
].id
;
583 arch_info
[i
].target
= target
;
584 arch_info
[i
].arm
= arm
;
586 reg_list
[i
].name
= armv7m_regs
[i
].name
;
587 reg_list
[i
].size
= armv7m_regs
[i
].bits
;
588 size_t storage_size
= DIV_ROUND_UP(armv7m_regs
[i
].bits
, 8);
589 if (storage_size
< 4)
591 reg_list
[i
].value
= calloc(1, storage_size
);
592 reg_list
[i
].dirty
= 0;
593 reg_list
[i
].valid
= 0;
594 reg_list
[i
].type
= &armv7m_reg_type
;
595 reg_list
[i
].arch_info
= &arch_info
[i
];
597 reg_list
[i
].group
= armv7m_regs
[i
].group
;
598 reg_list
[i
].number
= i
;
599 reg_list
[i
].exist
= true;
600 reg_list
[i
].caller_save
= true; /* gdb defaults to true */
602 feature
= calloc(1, sizeof(struct reg_feature
));
604 feature
->name
= armv7m_regs
[i
].feature
;
605 reg_list
[i
].feature
= feature
;
607 LOG_ERROR("unable to allocate feature list");
609 reg_list
[i
].reg_data_type
= calloc(1, sizeof(struct reg_data_type
));
610 if (reg_list
[i
].reg_data_type
)
611 reg_list
[i
].reg_data_type
->type
= armv7m_regs
[i
].type
;
613 LOG_ERROR("unable to allocate reg type list");
616 arm
->cpsr
= reg_list
+ ARMV7M_xPSR
;
617 arm
->pc
= reg_list
+ ARMV7M_PC
;
618 arm
->core_cache
= cache
;
623 void armv7m_free_reg_cache(struct target
*target
)
625 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
626 struct arm
*arm
= &armv7m
->arm
;
627 struct reg_cache
*cache
;
631 cache
= arm
->core_cache
;
636 for (i
= 0; i
< cache
->num_regs
; i
++) {
637 reg
= &cache
->reg_list
[i
];
640 free(reg
->reg_data_type
);
644 free(cache
->reg_list
[0].arch_info
);
645 free(cache
->reg_list
);
648 arm
->core_cache
= NULL
;
651 static int armv7m_setup_semihosting(struct target
*target
, int enable
)
653 /* nothing todo for armv7m */
657 /** Sets up target as a generic ARMv7-M core */
658 int armv7m_init_arch_info(struct target
*target
, struct armv7m_common
*armv7m
)
660 struct arm
*arm
= &armv7m
->arm
;
662 armv7m
->common_magic
= ARMV7M_COMMON_MAGIC
;
663 armv7m
->fp_feature
= FP_NONE
;
664 armv7m
->trace_config
.trace_bus_id
= 1;
665 /* Enable stimulus port #0 by default */
666 armv7m
->trace_config
.itm_ter
[0] = 1;
668 arm
->core_type
= ARM_MODE_THREAD
;
669 arm
->arch_info
= armv7m
;
670 arm
->setup_semihosting
= armv7m_setup_semihosting
;
672 arm
->read_core_reg
= armv7m_read_core_reg
;
673 arm
->write_core_reg
= armv7m_write_core_reg
;
675 return arm_init_arch_info(target
, arm
);
678 /** Generates a CRC32 checksum of a memory region. */
679 int armv7m_checksum_memory(struct target
*target
,
680 uint32_t address
, uint32_t count
, uint32_t *checksum
)
682 struct working_area
*crc_algorithm
;
683 struct armv7m_algorithm armv7m_info
;
684 struct reg_param reg_params
[2];
687 static const uint8_t cortex_m_crc_code
[] = {
688 #include "../../contrib/loaders/checksum/armv7m_crc.inc"
691 retval
= target_alloc_working_area(target
, sizeof(cortex_m_crc_code
), &crc_algorithm
);
692 if (retval
!= ERROR_OK
)
695 retval
= target_write_buffer(target
, crc_algorithm
->address
,
696 sizeof(cortex_m_crc_code
), (uint8_t *)cortex_m_crc_code
);
697 if (retval
!= ERROR_OK
)
700 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
701 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
703 init_reg_param(®_params
[0], "r0", 32, PARAM_IN_OUT
);
704 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
706 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
707 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
709 int timeout
= 20000 * (1 + (count
/ (1024 * 1024)));
711 retval
= target_run_algorithm(target
, 0, NULL
, 2, reg_params
, crc_algorithm
->address
,
712 crc_algorithm
->address
+ (sizeof(cortex_m_crc_code
) - 6),
713 timeout
, &armv7m_info
);
715 if (retval
== ERROR_OK
)
716 *checksum
= buf_get_u32(reg_params
[0].value
, 0, 32);
718 LOG_ERROR("error executing cortex_m crc algorithm");
720 destroy_reg_param(®_params
[0]);
721 destroy_reg_param(®_params
[1]);
724 target_free_working_area(target
, crc_algorithm
);
729 /** Checks whether a memory region is zeroed. */
730 int armv7m_blank_check_memory(struct target
*target
,
731 uint32_t address
, uint32_t count
, uint32_t *blank
)
733 struct working_area
*erase_check_algorithm
;
734 struct reg_param reg_params
[3];
735 struct armv7m_algorithm armv7m_info
;
738 static const uint8_t erase_check_code
[] = {
739 #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
742 /* make sure we have a working area */
743 if (target_alloc_working_area(target
, sizeof(erase_check_code
),
744 &erase_check_algorithm
) != ERROR_OK
)
745 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
747 retval
= target_write_buffer(target
, erase_check_algorithm
->address
,
748 sizeof(erase_check_code
), (uint8_t *)erase_check_code
);
749 if (retval
!= ERROR_OK
)
752 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
753 armv7m_info
.core_mode
= ARM_MODE_THREAD
;
755 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
756 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
758 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
759 buf_set_u32(reg_params
[1].value
, 0, 32, count
);
761 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
762 buf_set_u32(reg_params
[2].value
, 0, 32, 0xff);
764 retval
= target_run_algorithm(target
,
769 erase_check_algorithm
->address
,
770 erase_check_algorithm
->address
+ (sizeof(erase_check_code
) - 2),
774 if (retval
== ERROR_OK
)
775 *blank
= buf_get_u32(reg_params
[2].value
, 0, 32);
777 destroy_reg_param(®_params
[0]);
778 destroy_reg_param(®_params
[1]);
779 destroy_reg_param(®_params
[2]);
782 target_free_working_area(target
, erase_check_algorithm
);
787 int armv7m_maybe_skip_bkpt_inst(struct target
*target
, bool *inst_found
)
789 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
790 struct reg
*r
= armv7m
->arm
.pc
;
794 /* if we halted last time due to a bkpt instruction
795 * then we have to manually step over it, otherwise
796 * the core will break again */
798 if (target
->debug_reason
== DBG_REASON_BREAKPOINT
) {
800 uint32_t pc
= buf_get_u32(r
->value
, 0, 32);
803 if (target_read_u16(target
, pc
, &op
) == ERROR_OK
) {
804 if ((op
& 0xFF00) == 0xBE00) {
805 pc
= buf_get_u32(r
->value
, 0, 32) + 2;
806 buf_set_u32(r
->value
, 0, 32, pc
);
810 LOG_DEBUG("Skipping over BKPT instruction");
816 *inst_found
= result
;
821 const struct command_registration armv7m_command_handlers
[] = {
823 .chain
= arm_command_handlers
,
826 .chain
= dap_command_handlers
,
828 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)