diff --git a/arch/arm/core/cortex_m/scb.c b/arch/arm/core/cortex_m/scb.c index 957c66dcc9f50..849b823757e48 100644 --- a/arch/arm/core/cortex_m/scb.c +++ b/arch/arm/core/cortex_m/scb.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2025 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +23,8 @@ #include #include #include +#include +#include #if defined(CONFIG_CPU_HAS_NXP_SYSMPU) #include @@ -151,3 +154,99 @@ void z_arm_init_arch_hw_at_boot(void) barrier_isync_fence_full(); } #endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */ + +/** + * @brief Save essential SCB registers into a provided context structure. + * + * This function reads the current values of critical System Control Block (SCB) + * registers that are safe to backup, and stores them into the `context` structure. + * Access to SCB registers requires atomicity and consistency, so calling code + * should guarantee that interrupts are disabled. + * + * @param context Pointer to an `scb_context` structure where the register + * values will be stored. Must not be NULL. + */ +void z_arm_save_scb_context(struct scb_context *context) +{ + __ASSERT_NO_MSG(context != NULL); + +#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR) + context->vtor = SCB->VTOR; +#endif + context->aircr = SCB->AIRCR; + context->scr = SCB->SCR; + context->ccr = SCB->CCR; + + /* + * Backup the System Handler Priority Registers. + * SCB->SHPR is defined as u8[] or u32[] depending + * on the target Cortex-M core, but it can always + * be accessed using word-sized reads and writes. + * Make u32 pointer using explicit cast to allow + * access on all cores without compiler warnings. + */ + volatile uint32_t *shpr = (volatile uint32_t *)SCB->SHPR; + + for (int i = 0; i < SHPR_SIZE_W; i++) { + context->shpr[i] = shpr[i]; + } + + context->shcsr = SCB->SHCSR; +#if defined(CPACR_PRESENT) + context->cpacr = SCB->CPACR; +#endif /* CPACR_PRESENT */ +} + +/** + * @brief Restores essential SCB registers from a provided context structure. + * + * This function writes the values from the `context` structure back to the + * respective System Control Block (SCB) registers. Access to SCB registers + * requires atomicity and consistency, so calling code should guarantee that + * interrupts are disabled. + * + * @param context Pointer to a `scb_context` structure containing the + * register values to be restored. Must not be NULL. + */ +void z_arm_restore_scb_context(const struct scb_context *context) +{ + __ASSERT_NO_MSG(context != NULL); + +#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR) + /* Restore VTOR if present on this CPU */ + SCB->VTOR = context->vtor; +#endif + /* Restoring AIRCR requires writing VECTKEY along with desired bits. + * Mask backed up data to ensure only modifiable bits are restored. + */ + SCB->AIRCR = (context->aircr & ~SCB_AIRCR_VECTKEY_Msk) | + (AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos); + + SCB->SCR = context->scr; + SCB->CCR = context->ccr; + + /* Restore System Handler Priority Registers */ + volatile uint32_t *shpr = (volatile uint32_t *)SCB->SHPR; + + for (int i = 0; i < SHPR_SIZE_W; i++) { + shpr[i] = context->shpr[i]; + } + + /* Restore SHCSR */ + SCB->SHCSR = context->shcsr; + +#if defined(CPACR_PRESENT) + /* Restore CPACR */ + SCB->CPACR = context->cpacr; +#endif /* CPACR_PRESENT */ + + /** + * Ensure that updates to the SCB are visible by executing a DSB followed by ISB. + * This sequence is recommended in the M-profile Architecture Reference Manuals: + * - ARMv6: DDI0419 Issue E - §B2.5 "Barrier support for system correctness" + * - ARMv7: DDI0403 Issue E.e - §A3.7.3 "Memory barriers" (at end of section) + * - ARMv8: DDI0553 Version B.Y - §B7.2.16 "Synchronization requirements [...]" + */ + __DSB(); + __ISB(); +} diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 0d321561d01b1..44dc431ff8629 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -78,6 +78,11 @@ New APIs and options * Architectures * :kconfig:option:`CONFIG_SRAM_SW_ISR_TABLE` + * ARM (Cortex-M) system state save/restore primitives + + * :c:func:`z_arm_save_scb_context` / :c:func:`z_arm_restore_scb_context` + * :c:func:`z_arm_save_mpu_context` / :c:func:`z_arm_restore_mpu_context` + * Existing :c:func:`z_arm_save_fp_context` and :c:func:`z_arm_save_fp_context` have also been updated * Bluetooth diff --git a/include/zephyr/arch/arm/cortex_m/scb.h b/include/zephyr/arch/arm/cortex_m/scb.h new file mode 100644 index 0000000000000..d71f8b51794ba --- /dev/null +++ b/include/zephyr/arch/arm/cortex_m/scb.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System control block context helpers for Cortex-M CPUs + * + * System control block context helpers for backup and restore + */ + +#ifndef ARM_CORTEX_M_SCB_H_ +#define ARM_CORTEX_M_SCB_H_ + +#include +#include + +/* Define macros for CPU-conditional features */ +#if defined(CONFIG_CPU_CORTEX_M0) || \ + defined(CONFIG_CPU_CORTEX_M0PLUS) || \ + defined(CONFIG_CPU_CORTEX_M1) || \ + defined(CONFIG_CPU_CORTEX_M23) +#define SHPR_SIZE_W 2 +#else +#define SHPR_SIZE_W 3 +#define CPACR_PRESENT 1 +#endif + +/** + * @brief Structure to store essential, mutable SCB register values for backup/restore. + * + * This structure only contains SCB registers that are safe and meaningful to backup + * and restore. In particular, registers that are read-only (such as CPUID) or contain + * volatile information (ICSR / CFSR) are ignored, since their value is tied to the + * system state or fixed in hardware, rather than related to a configuration option. + */ +struct scb_context { +#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR) + uint32_t vtor; /*!< Vector Table Offset Register */ +#endif + uint32_t aircr; /*!< Application Interrupt and Reset Control Register */ + uint32_t scr; /*!< System Control Register */ + uint32_t ccr; /*!< Configuration Control Register */ + uint32_t shpr[SHPR_SIZE_W]; /*!< System Handler Priority Registers */ + uint32_t shcsr; /*!< System Handler Control and State Register */ +#if defined(CPACR_PRESENT) + uint32_t cpacr; /*!< Coprocessor Access Control Register */ +#endif /* CPACR_PRESENT */ +}; + +/** + * @name SCB Register Backup/Restore Functions + * @brief Functions for saving and restoring mutable SCB register state. + * @{ + */ + +/** + * @brief Save essential SCB registers into a provided context structure. + * + * This function reads the current values of critical System Control Block (SCB) + * registers that are safe to backup and stores them into the `context` structure. + * + * @param context Pointer to an `scb_context` structure where the register + * values will be stored. Must not be NULL. + */ +void z_arm_save_scb_context(struct scb_context *context); + +/** + * @brief Restores essential SCB registers from a provided context structure. + * + * This function writes the values from the `context` structure back to the + * respective System Control Block (SCB) registers. + * + * @warning Extreme caution is advised when restoring SCB registers. Only + * mutable registers are restored. Specifically, the ICSR register + * is NOT restored directly due to its volatile nature and read-only/ + * write-only bits. + * + * @param context Pointer to a `scb_context` structure containing the + * register values to be restored. Must not be NULL. + */ +void z_arm_restore_scb_context(const struct scb_context *context); + +/** @} */ + +#endif /* ARM_CORTEX_M_SCB_H_ */