Commit 958bec0d authored by Michele Sardo's avatar Michele Sardo Committed by Chris Friedt
Browse files

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: default avatarMichele Sardo <msmttchr@gmail.com>
parent fa184026
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -14,11 +14,18 @@
#include <kernel_arch_data.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <zephyr/arch/arm/mpu/arm_mpu.h>

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

#if Z_ARM_CPU_HAS_PMSAV8_MPU
#define ATTRIBUTE_AND_SIZE_REG_NAME RLAR
#else
#define ATTRIBUTE_AND_SIZE_REG_NAME RASR
#endif

#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
/* The order here is on purpose since ARMv8-M SoCs may define
 * 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
	}
}

#if defined(CONFIG_CPU_CORTEX_M)
/**
 * @brief Save the current MPU configuration into the provided context struct.
 */
void z_arm_save_mpu_context(struct z_mpu_context_retained *ctx)
{
	uint32_t regions = get_num_regions();

	__ASSERT_NO_MSG(ctx != NULL);

	if (regions == 0 || regions > Z_ARM_MPU_MAX_REGIONS) {
		LOG_DBG("Invalid MPU region count: %u", regions);
		ctx->num_valid_regions = 0;
		return;
	}

	ctx->num_valid_regions = regions;

	for (uint32_t i = 0; i < regions; i++) {
		MPU->RNR = i;
		__DSB(); /* Ensure MPU->RNR write completes before reading registers */
		__ISB();
		ctx->rbar[i] = MPU->RBAR;
		ctx->rasr_rlar[i] = MPU->ATTRIBUTE_AND_SIZE_REG_NAME;
	}
#if Z_ARM_CPU_HAS_PMSAV8_MPU
	ctx->mair[0] = MPU->MAIR0;
	ctx->mair[1] = MPU->MAIR1;
#endif
	ctx->ctrl = MPU->CTRL;
}

/**
 * @brief Restore the MPU configuration from the provided context struct.
 */
void z_arm_restore_mpu_context(const struct z_mpu_context_retained *ctx)
{
	__ASSERT_NO_MSG(ctx != NULL);

	if (ctx->num_valid_regions == 0 || ctx->num_valid_regions > Z_ARM_MPU_MAX_REGIONS) {
		LOG_DBG("Invalid MPU context num_valid_regions: %u", ctx->num_valid_regions);
		return;
	}

	/* Disable MPU before reprogramming */
	arm_core_mpu_disable();

	for (uint32_t i = 0; i < ctx->num_valid_regions; i++) {
		MPU->RNR = i;
		MPU->RBAR = ctx->rbar[i];
		MPU->ATTRIBUTE_AND_SIZE_REG_NAME = ctx->rasr_rlar[i];
	}

#if Z_ARM_CPU_HAS_PMSAV8_MPU
	MPU->MAIR0 = ctx->mair[0];
	MPU->MAIR1 = ctx->mair[1];
#endif
	/* Restore MPU control register (including enable bit if set) */
	MPU->CTRL = ctx->ctrl;

	/* Ensure MPU settings take effect before continuing */
	__DSB();
	__ISB();
}
#endif /* CONFIG_CPU_CORTEX_M */

/* ARM MPU Driver Initial Setup */

/*
+52 −0
Original line number Diff line number Diff line
@@ -17,7 +17,23 @@
#error "Unsupported ARM CPU"
#endif

#if defined(CONFIG_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE)
/* PMSAv8 MPU */
#define Z_ARM_CPU_HAS_PMSAV8_MPU 1
#else
/* PMSAv6 / PMSAv7 (MPU is identical) */
#define Z_ARM_CPU_HAS_PMSAV8_MPU 0
#endif

#if defined(CONFIG_ARMV8_M_MAINLINE)
#define Z_ARM_MPU_MAX_REGIONS 16U
#else
#define Z_ARM_MPU_MAX_REGIONS 8U
#endif


#ifndef _ASMLANGUAGE
#include <stdint.h>

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

#if defined(CONFIG_CPU_CORTEX_M)
/**
 * @brief MPU context structure to retain MPU register state across deep sleep.
 *
 * This structure holds the MPU region base and attribute registers,
 * as well as the MPU control register and a valid region count.
 *
 * The implemented architecture dictates which MPU registers exist:
 * - ARMv8-M has per-region RBAR+RLAR, and global MAIR0~1
 * - ARMv6/v7-M have per-region RBAR+RASR
 */
struct z_mpu_context_retained {
	uint32_t rbar[Z_ARM_MPU_MAX_REGIONS];
	uint32_t rasr_rlar[Z_ARM_MPU_MAX_REGIONS];
#if Z_ARM_CPU_HAS_PMSAV8_MPU
	uint32_t mair[2];
#endif
	uint32_t ctrl;
	uint32_t num_valid_regions;
};

/**
 * @brief Save the current MPU configuration into the provided context struct.
 *
 * @param ctx Pointer to the MPU context structure to save into.
 */
void z_arm_save_mpu_context(struct z_mpu_context_retained *ctx);

/**
 * @brief Restore the MPU configuration from the provided context struct.
 *
 * @param ctx Pointer to the MPU context structure to restore from.
 */
void z_arm_restore_mpu_context(const struct z_mpu_context_retained *ctx);

#endif /* CONFIG_CPU_CORTEX_M */
#endif /* _ASMLANGUAGE */

#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ */