Commit a90a47b1 authored by Michele Sardo's avatar Michele Sardo Committed by Fabio Baltieri
Browse files

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: default avatarMichele Sardo <msmttchr@gmail.com>
parent 7c30d7a9
Loading
Loading
Loading
Loading
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2014 Wind River Systems, Inc.
 * Copyright (c) 2025 STMicroelectronics
 *
 * SPDX-License-Identifier: Apache-2.0
 */
@@ -22,6 +23,21 @@
#include <zephyr/linker/linker-defs.h>
#include <zephyr/cache.h>
#include <zephyr/arch/cache.h>
#include <zephyr/arch/arm/cortex_m/scb.h>

/* For historical reasons, in Cortex-M family, CMSIS code calls System Handler Priority
 * register SHP or SHPR. This code defines the name of the register
 * according to the specific Cortex-M variant.
 */
#if defined(CONFIG_CPU_CORTEX_M0)  || \
	defined(CONFIG_CPU_CORTEX_M0PLUS)  || \
	defined(CONFIG_CPU_CORTEX_M1)  || \
	defined(CONFIG_CPU_CORTEX_M3) || \
	defined(CONFIG_CPU_CORTEX_M4)
#define SHPR_FIELD_NAME SHP
#else
#define SHPR_FIELD_NAME SHPR
#endif

#if defined(CONFIG_CPU_HAS_NXP_SYSMPU)
#include <fsl_sysmpu.h>
@@ -151,3 +167,98 @@ 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 System Handler Priority Registers */
	volatile uint32_t *shpr = (volatile uint32_t *) SCB->SHPR_FIELD_NAME;

	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.
 *
 * @warning The ICSR register is NOT restored directly due to its volatile nature
 * and presence of read-only status bits and write-only clear/set bits.
 * Direct restoration can lead to undefined behavior or corrupt interrupt state.
 * If specific ICSR bits need to be managed as part of a context,
 * a separate, highly controlled mechanism should be implemented.
 *
 * @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 Vector Table Offset Register first if it was modified. */
	SCB->VTOR = context->vtor;
#endif
	/* Restore AIRCR: Must write the VECTKEY (0x05FA) along with the desired bits.
	 * Ensure only the relevant modifiable bits are restored.
	 */
	SCB->AIRCR = (context->aircr & ~SCB_AIRCR_VECTKEY_Msk) |
					(0x05FAUL << 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_FIELD_NAME;

	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();
}
+89 −0
Original line number Diff line number Diff line
/*
 * 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 <stdint.h>
#include <cmsis_core.h>

/* 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 explicitly lists the SCB registers that are safe and meaningful
 * to backup and restore for common system state management. It avoids volatile,
 * read-only, or write-only status bits that should not be directly restored.
 */
struct scb_context {
#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
	uint32_t vtor;   /*!< offset 0x08, Vector Table Offset Register */
#endif
	uint32_t aircr;  /*!< offset 0x0C, Application Interrupt and Reset Control Register
			  * (only modifiable bits)
			  */
	uint32_t scr;    /*!< offset 0x10, System Control Register */
	uint32_t ccr;    /*!< offset 0x14, Configuration Control Register */
	uint32_t shpr[SHPR_SIZE_W]; /*!< offset 0x18 or 0x1C, System Handler Priority Registers */
	uint32_t shcsr;  /*!< offset 0x24, System Handler Control and State Register */
#if defined(CPACR_PRESENT)
	uint32_t cpacr; /*!< offset 0x88, 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_ */