target/cortex_m: introduce security manipulation routines

Running target algorithms on ARMv8M may require core in secure
mode with SAU and MPU off (as set after reset).

cortex_m_set_secure() forces this mode with optional save of
the previous state.

cortex_m_security_restore() restores previously saved state.

Change-Id: Ia71826db47ee7b0557eaffd55244ce13eacbcb4b
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: https://review.openocd.org/c/openocd/+/8959
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Tomas Vanek
2025-06-17 16:23:12 +02:00
committed by Antonio Borneo
parent ce3bf664c8
commit f547e55076
2 changed files with 133 additions and 0 deletions

View File

@@ -2563,6 +2563,112 @@ static bool cortex_m_has_tz(struct target *target)
return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0;
}
int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec)
{
if (ssec) {
ssec->dscsr_dirty = false;
ssec->sau_ctrl_dirty = false;
ssec->mpu_ctrl_dirty = false;
}
if (!cortex_m_has_tz(target))
return ERROR_OK;
uint32_t dscsr;
int retval = target_read_u32(target, DCB_DSCSR, &dscsr);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR read failed");
return retval;
}
if (!(dscsr & DSCSR_CDS)) {
if (ssec) {
ssec->dscsr_dirty = true;
ssec->dscsr = dscsr;
}
LOG_TARGET_DEBUG(target, "Setting Current Domain Secure in DSCSR");
retval = target_write_u32(target, DCB_DSCSR, DSCSR_CDS);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed");
return retval;
}
}
uint32_t sau_ctrl;
retval = target_read_u32(target, SAU_CTRL, &sau_ctrl);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL read failed");
return retval;
}
if (sau_ctrl & SAU_CTRL_ENABLE) {
if (ssec) {
ssec->sau_ctrl_dirty = true;
ssec->sau_ctrl = sau_ctrl;
}
retval = target_write_u32(target, SAU_CTRL, sau_ctrl & ~SAU_CTRL_ENABLE);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL write failed");
return retval;
}
}
uint32_t mpu_ctrl;
retval = target_read_u32(target, MPU_CTRL, &mpu_ctrl);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL read failed");
return retval;
}
if (mpu_ctrl & MPU_CTRL_ENABLE) {
if (ssec) {
ssec->mpu_ctrl_dirty = true;
ssec->mpu_ctrl = mpu_ctrl;
}
retval = target_write_u32(target, MPU_CTRL, mpu_ctrl & ~MPU_CTRL_ENABLE);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL write failed");
return retval;
}
}
return ERROR_OK;
}
int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec)
{
int retval;
if (!cortex_m_has_tz(target))
return ERROR_OK;
if (!ssec)
return ERROR_OK;
if (ssec->mpu_ctrl_dirty) {
retval = target_write_u32(target, MPU_CTRL, ssec->mpu_ctrl);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M security restore: MPU_CTRL write failed");
return retval;
}
ssec->mpu_ctrl_dirty = false;
}
if (ssec->sau_ctrl_dirty) {
retval = target_write_u32(target, SAU_CTRL, ssec->sau_ctrl);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M security restore: SAU_CTRL write failed");
return retval;
}
ssec->sau_ctrl_dirty = false;
}
if (ssec->dscsr_dirty) {
LOG_TARGET_DEBUG(target, "Restoring Current Domain Security in DSCSR");
retval = target_write_u32(target, DCB_DSCSR, ssec->dscsr & ~DSCSR_CDSKEY);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed");
return retval;
}
ssec->dscsr_dirty = false;
}
return ERROR_OK;
}
#define MVFR0 0xE000EF40
#define MVFR0_SP_MASK 0x000000F0

View File

@@ -167,6 +167,8 @@ struct cortex_m_part_info {
#define NVIC_DFSR 0xE000ED30
#define NVIC_MMFAR 0xE000ED34
#define NVIC_BFAR 0xE000ED38
#define MPU_CTRL 0xE000ED94
#define SAU_CTRL 0xE000EDD0
#define NVIC_SFSR 0xE000EDE4
#define NVIC_SFAR 0xE000EDE8
@@ -184,6 +186,9 @@ struct cortex_m_part_info {
#define DFSR_VCATCH 8
#define DFSR_EXTERNAL 16
#define MPU_CTRL_ENABLE BIT(0)
#define SAU_CTRL_ENABLE BIT(0)
#define FPCR_CODE 0
#define FPCR_LITERAL 1
#define FPCR_REPLACE_REMAP (0ul << 30)
@@ -264,6 +269,15 @@ struct cortex_m_common {
bool incorrect_halt_erratum;
};
struct cortex_m_saved_security {
bool dscsr_dirty;
uint32_t dscsr;
bool sau_ctrl_dirty;
uint32_t sau_ctrl;
bool mpu_ctrl_dirty;
uint32_t mpu_ctrl;
};
static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m)
{
return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC;
@@ -341,4 +355,17 @@ void cortex_m_deinit_target(struct target *target);
int cortex_m_profiling(struct target *target, uint32_t *samples,
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
/**
* Forces Cortex-M core to the basic secure context with SAU and MPU off
* @param ssec pointer to save previous security state or NULL
* @returns error code or ERROR_OK if secure mode was set or is not applicable
* (not ARMv8M with security extension)
*/
int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec);
/**
* Restores saved security context to MPU_CTRL, SAU_CTRL and DSCSR
*/
int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec);
#endif /* OPENOCD_TARGET_CORTEX_M_H */