Skip to content

Commit 8af0773

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 8af0773

File tree

2 files changed

+208
-0
lines changed
  • arch/arm/core/cortex_m
  • include/zephyr/arch/arm/cortex_m

2 files changed

+208
-0
lines changed

arch/arm/core/cortex_m/scb.c

Lines changed: 111 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,98 @@ 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+
volatile uint32_t *shpr = (volatile 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+
#if defined(CPACR_PRESENT)
202+
context->cpacr = SCB->CPACR;
203+
#endif /* CPACR_PRESENT */
204+
}
205+
206+
/**
207+
* @brief Restores essential SCB registers from a provided context structure.
208+
*
209+
* This function writes the values from the `context` structure back to the
210+
* respective System Control Block (SCB) registers. Access to SCB registers
211+
* requires atomicity and consistency, so calling code should guarantee that
212+
* interrupts are disabled.
213+
*
214+
* @warning The ICSR register is NOT restored directly due to its volatile nature
215+
* and presence of read-only status bits and write-only clear/set bits.
216+
* Direct restoration can lead to undefined behavior or corrupt interrupt state.
217+
* If specific ICSR bits need to be managed as part of a context,
218+
* a separate, highly controlled mechanism should be implemented.
219+
*
220+
* @param context Pointer to a `scb_context` structure containing the
221+
* register values to be restored. Must not be NULL.
222+
*/
223+
void z_arm_restore_scb_context(const struct scb_context *context)
224+
{
225+
__ASSERT_NO_MSG(context != NULL);
226+
227+
#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
228+
/* Restore Vector Table Offset Register first if it was modified. */
229+
SCB->VTOR = context->vtor;
230+
#endif
231+
/* Restore AIRCR: Must write the VECTKEY (0x05FA) along with the desired bits.
232+
* Ensure only the relevant modifiable bits are restored.
233+
*/
234+
SCB->AIRCR = (context->aircr & ~SCB_AIRCR_VECTKEY_Msk) |
235+
(0x05FAUL << SCB_AIRCR_VECTKEY_Pos);
236+
237+
SCB->SCR = context->scr;
238+
SCB->CCR = context->ccr;
239+
240+
/* Restore System Handler Priority Registers */
241+
volatile uint32_t *shpr = (volatile uint32_t *) SCB->SHPR_FIELD_NAME;
242+
243+
for (int i = 0; i < SHPR_SIZE_W; i++) {
244+
shpr[i] = context->shpr[i];
245+
}
246+
247+
/* Restore SHCSR */
248+
SCB->SHCSR = context->shcsr;
249+
250+
#if defined(CPACR_PRESENT)
251+
/* Restore CPACR */
252+
SCB->CPACR = context->cpacr;
253+
#endif /* CPACR_PRESENT */
254+
255+
/**
256+
* Ensure that updates to the SCB are visible by executing a DSB followed by ISB.
257+
* This sequence is recommended in the M-profile Architecture Reference Manuals:
258+
* - ARMv6: DDI0419 Issue E - §B2.5 "Barrier support for system correctness"
259+
* - ARMv7: DDI0403 Issue E.e - §A3.7.3 "Memory barriers" (at end of section)
260+
* - ARMv8: DDI0553 Version B.Y - §B7.2.16 "Synchronization requirements [...]"
261+
*/
262+
__DSB();
263+
__ISB();
264+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2025 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief System control block context helpers for Cortex-M CPUs
10+
*
11+
* System control block context helpers for backup and restore
12+
*/
13+
14+
#ifndef ARM_CORTEX_M_SCB_H_
15+
#define ARM_CORTEX_M_SCB_H_
16+
17+
#include <stdint.h>
18+
#include <cmsis_core.h>
19+
20+
/* Define macro for SHPR size */
21+
#if defined(CONFIG_CPU_CORTEX_M0) || \
22+
defined(CONFIG_CPU_CORTEX_M0PLUS) || \
23+
defined(CONFIG_CPU_CORTEX_M1) || \
24+
defined(CONFIG_CPU_CORTEX_M23)
25+
#define SHPR_SIZE_W 2
26+
#else
27+
#define SHPR_SIZE_W 3
28+
#endif
29+
30+
/* Define macro for CPACR presence */
31+
#if defined(CONFIG_CPU_CORTEX_M4) || \
32+
defined(CONFIG_CPU_CORTEX_M7) || \
33+
defined(CONFIG_CPU_CORTEX_M33) || \
34+
defined(CONFIG_CPU_CORTEX_M55) || \
35+
defined(CONFIG_CPU_CORTEX_M85)
36+
#define CPACR_PRESENT
37+
#endif
38+
39+
/**
40+
* @brief Structure to store essential, mutable SCB register values for backup/restore.
41+
*
42+
* This structure explicitly lists the SCB registers that are safe and meaningful
43+
* to backup and restore for common system state management. It avoids volatile,
44+
* read-only, or write-only status bits that should not be directly restored.
45+
*/
46+
struct scb_context {
47+
#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
48+
uint32_t vtor; /*!< offset 0x08, Vector Table Offset Register */
49+
#endif
50+
uint32_t aircr; /*!< offset 0x0C, Application Interrupt and Reset Control Register
51+
* (only modifiable bits)
52+
*/
53+
uint32_t scr; /*!< offset 0x10, System Control Register */
54+
uint32_t ccr; /*!< offset 0x14, Configuration Control Register */
55+
uint32_t shpr[SHPR_SIZE_W]; /*!< offset 0x18 or 0x1C, System Handler Priority Registers */
56+
uint32_t shcsr; /*!< offset 0x24, System Handler Control and State Register */
57+
#if defined(CPACR_PRESENT)
58+
uint32_t cpacr; /*!< offset 0x88, Coprocessor Access Control Register */
59+
#endif /* CPACR_PRESENT */
60+
};
61+
62+
/**
63+
* @name SCB Register Backup/Restore Functions
64+
* @brief Functions for saving and restoring mutable SCB register state.
65+
* @{
66+
*/
67+
68+
/**
69+
* @brief Save essential SCB registers into a provided context structure.
70+
*
71+
* This function reads the current values of critical System Control Block (SCB)
72+
* registers that are safe to backup and stores them into the `context` structure.
73+
*
74+
* @param context Pointer to an `scb_context` structure where the register
75+
* values will be stored. Must not be NULL.
76+
*/
77+
void z_arm_save_scb_context(struct scb_context *context);
78+
79+
/**
80+
* @brief Restores essential SCB registers from a provided context structure.
81+
*
82+
* This function writes the values from the `context` structure back to the
83+
* respective System Control Block (SCB) registers.
84+
*
85+
* @warning Extreme caution is advised when restoring SCB registers. Only
86+
* mutable registers are restored. Specifically, the ICSR register
87+
* is NOT restored directly due to its volatile nature and read-only/
88+
* write-only bits.
89+
*
90+
* @param context Pointer to a `scb_context` structure containing the
91+
* register values to be restored. Must not be NULL.
92+
*/
93+
void z_arm_restore_scb_context(const struct scb_context *context);
94+
95+
/** @} */
96+
97+
#endif /* ARM_CORTEX_M_SCB_H_ */

0 commit comments

Comments
 (0)