From 9d8f7126f6cee0b7af3c13c2f14a5d8593b69c5f Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Wed, 22 Sep 2021 10:28:35 -0700 Subject: [PATCH] armv7-m,armv7-r,armv8-m:MPU Add mpu_reset and ARM_MPU_EARLY_RESET When NuttX is booted from a foreign (non NuttX) bootloader. There as a possibility that the bootloader configured the MPU, in an incompatible way for the NuttX memory usage. The option to reset the MPU before it is initialized may not succeed if the bss and data initialization code violated the previous MPU configurations. Added herein are ARM_MPU_RESET and ARM_MPU_EARLY_RESET. The former can be used If the system is capable of booting and running NuttX MPU configuration code without an MPU violation. The latter is used if the system can not run the bss and data initialization code. These are options so that a NuttX may be configured to not clobber a bootloader MPU configuration in a system that is architected to share the MPU configuration task. --- arch/arm/Kconfig | 28 +++++++++++++++++ arch/arm/src/armv7-m/arm_mpu.c | 57 ++++++++++++++++++++++++++++++++++ arch/arm/src/armv7-m/mpu.h | 30 ++++++++++++++++++ arch/arm/src/armv7-r/arm_mpu.c | 57 ++++++++++++++++++++++++++++++++++ arch/arm/src/armv7-r/mpu.h | 30 ++++++++++++++++++ arch/arm/src/armv8-m/arm_mpu.c | 57 ++++++++++++++++++++++++++++++++++ arch/arm/src/armv8-m/mpu.h | 30 ++++++++++++++++++ 7 files changed, 289 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a768a79170..56b9a4f811 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -879,6 +879,34 @@ config ARM_MPU_NREGIONS ---help--- This is the number of protection regions supported by the MPU. +config ARM_MPU_RESET + bool "MPU Reset before MPU initialization" + default n + depends on ARM_MPU + ---help--- + Configures the MPU initialization sequence to disable the MPU + before configuring it. + + This may be needed in a system with a bootloader that has + configured the MPU prior to running NuttX. This may be all that is + needed to allow booting if the previous MPU configuration allow + the system to execute the MPU initialization code. If not use + ARM_MPU_EARLY_RESET. + +config ARM_MPU_EARLY_RESET + bool "MPU Early Reset" + default n + depends on ARCH_HAVE_MPU + ---help--- + Configures the early system initialization sequence to disable the MPU. + + This may be needed in a system with a bootloader that has + configured the MPU prior to running NuttX. This is useful if the system + faults during bbs, or data initialization or before the + stm32_mpuinitialize can be called. + + Note: This can be used without MPU Support enabled. + config ARCH_HAVE_LOWVECTORS bool diff --git a/arch/arm/src/armv7-m/arm_mpu.c b/arch/arm/src/armv7-m/arm_mpu.c index b24166114b..7a35108495 100644 --- a/arch/arm/src/armv7-m/arm_mpu.c +++ b/arch/arm/src/armv7-m/arm_mpu.c @@ -177,6 +177,33 @@ static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size) return g_ls_regionmask[nsrs]; } +/**************************************************************************** + * Name: mpu_reset_internal + * + * Description: + * Resets the MPU to disabled. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET) +static void mpu_reset_internal() +{ + int region; + int regions; + regions = (getreg32(MPU_TYPE) & MPU_TYPE_DREGION_MASK) + >> MPU_TYPE_DREGION_SHIFT; + + for (region = 0; region < regions; region++) + { + putreg32(region, MPU_RNR); + putreg32(0, MPU_RASR); + putreg32(0, MPU_RBAR); + } + + putreg32(0, MPU_CTRL); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -387,3 +414,33 @@ void mpu_configure_region(uintptr_t base, size_t size, flags; putreg32(regval, MPU_RASR); } + +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ +#if defined(CONFIG_MPU_RESET) +void mpu_reset() +{ + mpu_reset_internal(); +} +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset() +{ + mpu_reset_internal(); +} +#endif diff --git a/arch/arm/src/armv7-m/mpu.h b/arch/arm/src/armv7-m/mpu.h index 2d8fb885bd..870fea6207 100644 --- a/arch/arm/src/armv7-m/mpu.h +++ b/arch/arm/src/armv7-m/mpu.h @@ -132,6 +132,36 @@ # define MPU_RASR_AP_RORO (6 << MPU_RASR_AP_SHIFT) /* P:RO U:RO */ # define MPU_RASR_XN (1 << 28) /* Bit 28: Instruction access disable */ +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) +void mpu_reset(void); +#else +# define mpu_reset() do { } while (0) +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ + +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset(void); +#else +# define mpu_early_reset() do { } while (0) +#endif + #ifdef CONFIG_ARM_MPU /**************************************************************************** diff --git a/arch/arm/src/armv7-r/arm_mpu.c b/arch/arm/src/armv7-r/arm_mpu.c index 5fd372339b..2023909243 100644 --- a/arch/arm/src/armv7-r/arm_mpu.c +++ b/arch/arm/src/armv7-r/arm_mpu.c @@ -177,6 +177,33 @@ static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size) return g_ls_regionmask[nsrs]; } +/**************************************************************************** + * Name: mpu_reset_internal + * + * Description: + * Resets the MPU to disabled. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET) +static void mpu_reset_internal() +{ + int region; + int regions; + regions = (getreg32(MPU_TYPE) & MPU_TYPE_DREGION_MASK) + >> MPU_TYPE_DREGION_SHIFT; + + for (region = 0; region < regions; region++) + { + putreg32(region, MPU_RNR); + putreg32(0, MPU_RASR); + putreg32(0, MPU_RBAR); + } + + putreg32(0, MPU_CTRL); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -300,3 +327,33 @@ uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size) ret |= mpu_subregion_ls(offset, l2size); return ret; } + +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ +#if defined(CONFIG_MPU_RESET) +void mpu_reset() +{ + mpu_reset_internal(); +} +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset() +{ + mpu_reset_internal(); +} +#endif diff --git a/arch/arm/src/armv7-r/mpu.h b/arch/arm/src/armv7-r/mpu.h index e4ccc98735..5824353908 100644 --- a/arch/arm/src/armv7-r/mpu.h +++ b/arch/arm/src/armv7-r/mpu.h @@ -120,6 +120,36 @@ extern "C" #define EXTERN extern #endif +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) +void mpu_reset(void); +#else +# define mpu_reset() do { } while (0) +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ + +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset(void); +#else +# define mpu_early_reset() do { } while (0) +#endif + /**************************************************************************** * Name: mpu_allocregion * diff --git a/arch/arm/src/armv8-m/arm_mpu.c b/arch/arm/src/armv8-m/arm_mpu.c index 29bb63df1e..50ae4ff63c 100644 --- a/arch/arm/src/armv8-m/arm_mpu.c +++ b/arch/arm/src/armv8-m/arm_mpu.c @@ -71,6 +71,33 @@ unsigned int mpu_allocregion(void) return (unsigned int)g_region++; } +/**************************************************************************** + * Name: mpu_reset_internal + * + * Description: + * Resets the MPU to disabled. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET) +static void mpu_reset_internal() +{ + int region; + int regions; + regions = (getreg32(MPU_TYPE) & MPU_TYPE_DREGION_MASK) + >> MPU_TYPE_DREGION_SHIFT; + + for (region = 0; region < regions; region++) + { + putreg32(region, MPU_RNR); + putreg32(0, MPU_RASR); + putreg32(0, MPU_RBAR); + } + + putreg32(0, MPU_CTRL); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -148,3 +175,33 @@ void mpu_configure_region(uintptr_t base, size_t size, putreg32(base | flags1, MPU_RBAR); putreg32(limit | flags2 | MPU_RLAR_ENABLE, MPU_RLAR); } + +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ +#if defined(CONFIG_MPU_RESET) +void mpu_reset() +{ + mpu_reset_internal(); +} +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset() +{ + mpu_reset_internal(); +} +#endif diff --git a/arch/arm/src/armv8-m/mpu.h b/arch/arm/src/armv8-m/mpu.h index 4e793dedce..428a06aff7 100644 --- a/arch/arm/src/armv8-m/mpu.h +++ b/arch/arm/src/armv8-m/mpu.h @@ -171,6 +171,36 @@ MPU_MAIR_INNER_NT | MPU_MAIR_INNER_WB | \ MPU_MAIR_INNER_RA | MPU_MAIR_INNER_WA) +/**************************************************************************** + * Name: mpu_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled during + * MPU initialization. + * + ****************************************************************************/ + +#if defined(CONFIG_MPU_RESET) +void mpu_reset(void); +#else +# define mpu_reset() do { } while (0) +#endif + +/**************************************************************************** + * Name: mpu_early_reset + * + * Description: + * Conditional public interface that resets the MPU to disabled immediately + * after reset. + * + ****************************************************************************/ + +#if defined(CONFIG_ARM_MPU_EARLY_RESET) +void mpu_early_reset(void); +#else +# define mpu_early_reset() do { } while (0) +#endif + #ifdef CONFIG_ARM_MPU /****************************************************************************