Skip to content

Commit 0c5b4c4

Browse files
committed
arch: arm: cortex_m: Add API for scb save and restore
Add two API to save SCB context and restore it, typically used in suspend to RAM use case. The scb_context_t and the backup/restore functions are designed to only handle SCB registers that are: - Mutable: Their values can be changed by software. - Configurable: They control system behavior or features. - Stateful: Their values represent a specific configuration that an application might want to preserve and restore. Register excluded from backup/restore are: 1. CPUID (CPUID Base Register) Motivation for Exclusion: This is a read-only identification register. 2. ICSR (Interrupt Control and State Register) Motivation for Exclusion (from restoration): While its current value can be read, directly restoring a saved ICSR value is highly dangerous and generally unsafe in an RTOS context. Contains Read-Only Status Bits: A significant portion of ICSR consists of read-only bits (VECTACTIVE, VECTPENDING, ISRPREEMPT, TSRUNPEND). These bits reflect the current state of the exception system (e.g., which exception is active, which are pending) and are managed dynamically by the CPU and the RTOS. Forcing a previous state onto these bits would corrupt the live system's interrupt handling. Contains Write-Only Set/Clear Bits: Some bits are write-only to set or clear a pending interrupt (PENDSVSET, PENDSVCLR, SYSTICKSET, SYSTICKCLR). If these bits were set in the saved context, restoring them might immediately trigger an interrupt or change its pending state unexpectedly, outside the RTOS's control. RTOS Management: In Zephyr (and other RTOSes), the kernel tightly manages the interrupt and exception state. Direct manipulation of ICSR's volatile bits could conflict with the RTOS's internal state machine, leading to crashes or unpredictable behavior. 3. CFSR (Configurable Fault Status Register) Motivation for Exclusion: This is a read-only status register that reports the current state of Memory Management, Bus Fault, and Usage Faults. It's used by fault handlers to determine the cause of a fault. 4. HFSR (HardFault Status Register) Motivation for Exclusion: Similar to CFSR, this is a read-only status register that reports the current state of HardFaults. It's for reporting, not for configuration or restoration. 5. DFSR (Debug Fault Status Register) Motivation for Exclusion: This is a read-only status register that reports debug-related faults. It's primarily used by debuggers and is not part of the application's runtime context to be saved/restored. 6. MMFAR (MemManage Fault Address Register) Motivation for Exclusion: This is a read-only register that stores the address that caused a Memory Management fault. It's a diagnostic register, not a configurable parameter. 7. BFAR (BusFault Address Register) Motivation for Exclusion: Similar to MMFAR, this is a read-only register that stores the address that caused a BusFault. It's a diagnostic register. 8. AFSR (Auxiliary Fault Status Register) Motivation for Exclusion: This register is implementation-defined and read-only. Signed-off-by: Michele Sardo <[email protected]>
1 parent 322da1d commit 0c5b4c4

File tree

1 file changed

+93
-0
lines changed
  • arch/arm/core/cortex_m

1 file changed

+93
-0
lines changed

arch/arm/core/cortex_m/scb.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2013-2014 Wind River Systems, Inc.
3+
* Copyright (c) 2025 STMicroelectronics
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -22,6 +23,21 @@
2223
#include <zephyr/linker/linker-defs.h>
2324
#include <zephyr/cache.h>
2425
#include <zephyr/arch/cache.h>
26+
#include <zephyr/arch/arm/cortex_m/scb.h>
27+
28+
/* For historical reasons, in Cortex-M family, CMSIS code calls System Handler Priority
29+
* register SHP or SHPR. This code defines the name of the register
30+
* according to the specific Cortex-M variant.
31+
*/
32+
#if defined(CONFIG_CPU_CORTEX_M0) || \
33+
defined(CONFIG_CPU_CORTEX_M0PLUS) || \
34+
defined(CONFIG_CPU_CORTEX_M1) || \
35+
defined(CONFIG_CPU_CORTEX_M3) || \
36+
defined(CONFIG_CPU_CORTEX_M4)
37+
#define SHPR_FIELD_NAME SHP
38+
#else
39+
#define SHPR_FIELD_NAME SHPR
40+
#endif
2541

2642
#if defined(CONFIG_CPU_HAS_NXP_SYSMPU)
2743
#include <fsl_sysmpu.h>
@@ -151,3 +167,80 @@ void z_arm_init_arch_hw_at_boot(void)
151167
barrier_isync_fence_full();
152168
}
153169
#endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */
170+
171+
/**
172+
* @brief Save essential SCB registers into a provided context structure.
173+
*
174+
* This function reads the current values of critical System Control Block (SCB)
175+
* registers that are safe to backup, and stores them into the `context` structure.
176+
* Access to SCB registers requires atomicity and consistency, so calling code
177+
* should guarantee that interrupts are disabled.
178+
*
179+
* @param context Pointer to an `scb_context` structure where the register
180+
* values will be stored. Must not be NULL.
181+
*/
182+
void z_arm_save_scb_context(struct scb_context *context)
183+
{
184+
__ASSERT_NO_MSG(context != NULL);
185+
186+
#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
187+
context->vtor = SCB->VTOR;
188+
#endif
189+
context->aircr = SCB->AIRCR;
190+
context->scr = SCB->SCR;
191+
context->ccr = SCB->CCR;
192+
193+
/* Backup System Handler Priority Registers */
194+
__IOM uint32_t *shpr = (__IOM uint32_t *) SCB->SHPR_FIELD_NAME;
195+
196+
for (int i = 0; i < SHPR_SIZE_W; i++) {
197+
context->shpr[i] = shpr[i];
198+
}
199+
200+
context->shcsr = SCB->SHCSR;
201+
}
202+
203+
/**
204+
* @brief Restores essential SCB registers from a provided context structure.
205+
*
206+
* This function writes the values from the `context` structure back to the
207+
* respective System Control Block (SCB) registers. Access to SCB registers
208+
* requires atomicity and consistency, so calling code should guarantee that
209+
* interrupts are disabled.
210+
*
211+
* @warning The ICSR register is NOT restored directly due to its volatile nature
212+
* and presence of read-only status bits and write-only clear/set bits.
213+
* Direct restoration can lead to undefined behavior or corrupt interrupt state.
214+
* If specific ICSR bits need to be managed as part of a context,
215+
* a separate, highly controlled mechanism should be implemented.
216+
*
217+
* @param context Pointer to a `scb_context` structure containing the
218+
* register values to be restored. Must not be NULL.
219+
*/
220+
void z_arm_restore_scb_context(const struct scb_context *context)
221+
{
222+
__ASSERT_NO_MSG(context != NULL);
223+
224+
#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
225+
/* Restore Vector Table Offset Register first if it was modified. */
226+
SCB->VTOR = context->vtor;
227+
#endif
228+
/* Restore AIRCR: Must write the VECTKEY (0x05FA) along with the desired bits.
229+
* Ensure only the relevant modifiable bits are restored.
230+
*/
231+
SCB->AIRCR = (context->aircr & ~SCB_AIRCR_VECTKEY_Msk) |
232+
(0x05FAUL << SCB_AIRCR_VECTKEY_Pos);
233+
234+
SCB->SCR = context->scr;
235+
SCB->CCR = context->ccr;
236+
237+
/* Restore System Handler Priority Registers */
238+
__IOM uint32_t *shpr = (__IOM uint32_t *) SCB->SHPR_FIELD_NAME;
239+
240+
for (int i = 0; i < SHPR_SIZE_W; i++) {
241+
shpr[i] = context->shpr[i];
242+
}
243+
244+
/* Restore SHCSR */
245+
SCB->SHCSR = context->shcsr;
246+
}

0 commit comments

Comments
 (0)