Skip to content

Commit 958bec0

Browse files
msmttchrcfriedt
authored andcommitted
arch: arm: add Cortex-M MPU context save/restore API
Add struct z_mpu_context_retained and parameterized functions z_arm_save_mpu_context() and z_arm_restore_mpu_context() to allow saving and restoring MPU configuration to/from retained RAM. This enables preserving MPU state across deep sleep or power-down modes on Cortex-M devices. The API is exposed under include/zephyr/arch/arm/mpu/arm_mpu.h and implemented in arch/arm/core/mpu/arm_mpu.c. Signed-off-by: Michele Sardo <[email protected]>
1 parent fa18402 commit 958bec0

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

arch/arm/core/mpu/arm_mpu.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@
1414
#include <kernel_arch_data.h>
1515
#include <zephyr/mem_mgmt/mem_attr.h>
1616
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
17+
#include <zephyr/arch/arm/mpu/arm_mpu.h>
1718

1819
#define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
1920
#include <zephyr/logging/log.h>
2021
LOG_MODULE_DECLARE(mpu);
2122

23+
#if Z_ARM_CPU_HAS_PMSAV8_MPU
24+
#define ATTRIBUTE_AND_SIZE_REG_NAME RLAR
25+
#else
26+
#define ATTRIBUTE_AND_SIZE_REG_NAME RASR
27+
#endif
28+
2229
#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
2330
/* The order here is on purpose since ARMv8-M SoCs may define
2431
* CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE
@@ -407,6 +414,72 @@ void arm_core_mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition
407414
}
408415
}
409416

417+
#if defined(CONFIG_CPU_CORTEX_M)
418+
/**
419+
* @brief Save the current MPU configuration into the provided context struct.
420+
*/
421+
void z_arm_save_mpu_context(struct z_mpu_context_retained *ctx)
422+
{
423+
uint32_t regions = get_num_regions();
424+
425+
__ASSERT_NO_MSG(ctx != NULL);
426+
427+
if (regions == 0 || regions > Z_ARM_MPU_MAX_REGIONS) {
428+
LOG_DBG("Invalid MPU region count: %u", regions);
429+
ctx->num_valid_regions = 0;
430+
return;
431+
}
432+
433+
ctx->num_valid_regions = regions;
434+
435+
for (uint32_t i = 0; i < regions; i++) {
436+
MPU->RNR = i;
437+
__DSB(); /* Ensure MPU->RNR write completes before reading registers */
438+
__ISB();
439+
ctx->rbar[i] = MPU->RBAR;
440+
ctx->rasr_rlar[i] = MPU->ATTRIBUTE_AND_SIZE_REG_NAME;
441+
}
442+
#if Z_ARM_CPU_HAS_PMSAV8_MPU
443+
ctx->mair[0] = MPU->MAIR0;
444+
ctx->mair[1] = MPU->MAIR1;
445+
#endif
446+
ctx->ctrl = MPU->CTRL;
447+
}
448+
449+
/**
450+
* @brief Restore the MPU configuration from the provided context struct.
451+
*/
452+
void z_arm_restore_mpu_context(const struct z_mpu_context_retained *ctx)
453+
{
454+
__ASSERT_NO_MSG(ctx != NULL);
455+
456+
if (ctx->num_valid_regions == 0 || ctx->num_valid_regions > Z_ARM_MPU_MAX_REGIONS) {
457+
LOG_DBG("Invalid MPU context num_valid_regions: %u", ctx->num_valid_regions);
458+
return;
459+
}
460+
461+
/* Disable MPU before reprogramming */
462+
arm_core_mpu_disable();
463+
464+
for (uint32_t i = 0; i < ctx->num_valid_regions; i++) {
465+
MPU->RNR = i;
466+
MPU->RBAR = ctx->rbar[i];
467+
MPU->ATTRIBUTE_AND_SIZE_REG_NAME = ctx->rasr_rlar[i];
468+
}
469+
470+
#if Z_ARM_CPU_HAS_PMSAV8_MPU
471+
MPU->MAIR0 = ctx->mair[0];
472+
MPU->MAIR1 = ctx->mair[1];
473+
#endif
474+
/* Restore MPU control register (including enable bit if set) */
475+
MPU->CTRL = ctx->ctrl;
476+
477+
/* Ensure MPU settings take effect before continuing */
478+
__DSB();
479+
__ISB();
480+
}
481+
#endif /* CONFIG_CPU_CORTEX_M */
482+
410483
/* ARM MPU Driver Initial Setup */
411484

412485
/*

include/zephyr/arch/arm/mpu/arm_mpu.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,23 @@
1717
#error "Unsupported ARM CPU"
1818
#endif
1919

20+
#if defined(CONFIG_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE)
21+
/* PMSAv8 MPU */
22+
#define Z_ARM_CPU_HAS_PMSAV8_MPU 1
23+
#else
24+
/* PMSAv6 / PMSAv7 (MPU is identical) */
25+
#define Z_ARM_CPU_HAS_PMSAV8_MPU 0
26+
#endif
27+
28+
#if defined(CONFIG_ARMV8_M_MAINLINE)
29+
#define Z_ARM_MPU_MAX_REGIONS 16U
30+
#else
31+
#define Z_ARM_MPU_MAX_REGIONS 8U
32+
#endif
33+
34+
2035
#ifndef _ASMLANGUAGE
36+
#include <stdint.h>
2137

2238
/* Region definition data structure */
2339
struct arm_mpu_region {
@@ -68,6 +84,42 @@ struct arm_mpu_config {
6884
*/
6985
extern const struct arm_mpu_config mpu_config;
7086

87+
#if defined(CONFIG_CPU_CORTEX_M)
88+
/**
89+
* @brief MPU context structure to retain MPU register state across deep sleep.
90+
*
91+
* This structure holds the MPU region base and attribute registers,
92+
* as well as the MPU control register and a valid region count.
93+
*
94+
* The implemented architecture dictates which MPU registers exist:
95+
* - ARMv8-M has per-region RBAR+RLAR, and global MAIR0~1
96+
* - ARMv6/v7-M have per-region RBAR+RASR
97+
*/
98+
struct z_mpu_context_retained {
99+
uint32_t rbar[Z_ARM_MPU_MAX_REGIONS];
100+
uint32_t rasr_rlar[Z_ARM_MPU_MAX_REGIONS];
101+
#if Z_ARM_CPU_HAS_PMSAV8_MPU
102+
uint32_t mair[2];
103+
#endif
104+
uint32_t ctrl;
105+
uint32_t num_valid_regions;
106+
};
107+
108+
/**
109+
* @brief Save the current MPU configuration into the provided context struct.
110+
*
111+
* @param ctx Pointer to the MPU context structure to save into.
112+
*/
113+
void z_arm_save_mpu_context(struct z_mpu_context_retained *ctx);
114+
115+
/**
116+
* @brief Restore the MPU configuration from the provided context struct.
117+
*
118+
* @param ctx Pointer to the MPU context structure to restore from.
119+
*/
120+
void z_arm_restore_mpu_context(const struct z_mpu_context_retained *ctx);
121+
122+
#endif /* CONFIG_CPU_CORTEX_M */
71123
#endif /* _ASMLANGUAGE */
72124

73125
#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ */

0 commit comments

Comments
 (0)