arm_mpu:Reentrant allocation Region

Changes have been completed:
1.armv7m
2.armv8m
3.armv7r
4.arm64

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
This commit is contained in:
chenrun1 2024-04-25 14:12:58 +08:00 committed by Xiang Xiao
parent 3a25286862
commit 62f598e547
8 changed files with 1753 additions and 693 deletions

View file

@ -26,6 +26,7 @@
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include "mpu.h"
#include "arm_internal.h"
@ -69,9 +70,9 @@ static const uint8_t g_ls_regionmask[9] =
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
/* The next available region number */
/* The available region bitmap */
static uint8_t g_region;
static unsigned int g_mpu_region;
/****************************************************************************
* Private Functions
@ -89,6 +90,13 @@ static uint8_t g_region;
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* size: The size of the region.
* l2size: The L2 size of the region.
*
* Returned Value:
* The sub-region bitmask.
*
****************************************************************************/
static inline uint32_t mpu_subregion_ms(size_t size, uint8_t l2size)
@ -140,6 +148,13 @@ static inline uint32_t mpu_subregion_ms(size_t size, uint8_t l2size)
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* offset: The offset of the region.
* l2size: The L2 size of the region.
*
* Returned Value:
* The sub-region bitmask.
*
****************************************************************************/
static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size)
@ -184,6 +199,12 @@ static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size)
* Description:
* Resets the MPU to disabled.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET)
@ -218,17 +239,51 @@ static void mpu_reset_internal()
* Description:
* Allocate the next region
*
* Assumptions:
* - Regions are never deallocated
* - Regions are only allocated early in initialization, so no special
* protection against re-entrancy is required;
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void)
{
DEBUGASSERT(g_region < CONFIG_ARM_MPU_NREGIONS);
return (unsigned int)g_region++;
unsigned int i = ffs(~g_mpu_region) - 1;
/* There are not enough regions to apply */
DEBUGASSERT(i < CONFIG_ARM_MPU_NREGIONS);
g_mpu_region |= 1 << i;
return i;
}
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region)
{
DEBUGASSERT(region < CONFIG_ARM_MPU_NREGIONS);
/* Clear and disable the given MPU Region */
putreg32(region, MPU_RNR);
putreg32(0, MPU_RASR);
putreg32(0, MPU_RBAR);
g_mpu_region &= ~(1 << region);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
@ -240,6 +295,12 @@ unsigned int mpu_allocregion(void)
*
* size <= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the ceiling value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionceil(size_t size)
@ -261,6 +322,12 @@ uint8_t mpu_log2regionceil(size_t size)
*
* size >= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the floor value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionfloor(size_t size)
@ -287,6 +354,14 @@ uint8_t mpu_log2regionfloor(size_t size)
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* l2size - Log2 of the actual region size is <= (1 << l2size).
*
* Returned Value:
* The subregion settings as a 32-bit value.
*
****************************************************************************/
uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size)
@ -338,6 +413,16 @@ uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size)
* Description:
* Configure and enable (or disable) the MPU
*
* Input Parameters:
* enable - Flag indicating whether to enable the MPU.
* hfnmiena - Flag indicating whether to enable the MPU during hard
* fult, NMI, and FAULTMAS.
* privdefena - Flag indicating whether to enable privileged access to
* the default memory map.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_control(bool enable, bool hfnmiena, bool privdefena)
@ -368,22 +453,34 @@ void mpu_control(bool enable, bool hfnmiena, bool privdefena)
}
/****************************************************************************
* Name: mpu_configure_region
* Name: mpu_modify_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - Region number to modify.
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags)
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
uintptr_t alignedbase;
/* Check that the region is valid */
DEBUGASSERT(g_mpu_region & (1 << region));
/* Ensure the base address alignment
*
* ARMv7-M Architecture Reference Manual
@ -429,6 +526,111 @@ void mpu_configure_region(uintptr_t base, size_t size,
ARM_ISB();
}
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags)
{
unsigned int region = mpu_allocregion();
mpu_modify_region(region, base, size, flags);
return region;
}
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU initialization table.
* hfnmiena - A boolean indicating whether the MPU should enable the
* HFNMIENA bit.
* privdefena - A boolean indicating whether the MPU should enable the
* PRIVDEFENA bit.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table, bool hfnmiena,
bool privdefena)
{
const struct mpu_region_s *conf;
int index;
mpu_control(false, false, false);
for (index = 0; index < nitems(table); index++)
{
conf = &table[index];
mpu_configure_region(conf->base, conf->size, conf->flags);
}
mpu_control(true, hfnmiena, privdefena);
}
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void)
{
int i;
int count = 0;
uint32_t rasr;
uint32_t rbar;
uint32_t ctrl;
/* Get free region */
ctrl = getreg32(MPU_CTRL);
_info("MPU-CTRL Enable:%" PRIu32 ", HFNMIENA:%"PRIu32","
"PRIVDEFENA:%" PRIu32 "\n", ctrl & MPU_CTRL_ENABLE,
ctrl & MPU_CTRL_HFNMIENA, ctrl & MPU_CTRL_PRIVDEFENA);
for (i = 0; i < CONFIG_ARM_MPU_NREGIONS; i++)
{
putreg32(i, MPU_RNR);
rasr = getreg32(MPU_RASR);
rbar = getreg32(MPU_RBAR);
_info("MPU-%d, alignedbase=0%08X l2size=%"PRIu32" SRD=%X"
"AP=%X XN=%u\n", i, rbar & MPU_RBAR_ADDR_MASK,
rasr & MPU_RASR_SIZE_MASK, rasr & MPU_RASR_SRD_MASK,
rasr & MPU_RASR_AP_MASK, rasr & MPU_RASR_XN);
if (rasr & MPU_RASR_ENABLE)
{
count++;
}
}
_info("Total Use Region:%d, Remaining Available:%d\n", count,
CONFIG_ARM_MPU_NREGIONS - count);
}
/****************************************************************************
* Name: mpu_reset
*
@ -436,6 +638,12 @@ void mpu_configure_region(uintptr_t base, size_t size,
* Conditional public interface that resets the MPU to disabled during
* MPU initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET)
void mpu_reset()
@ -451,6 +659,12 @@ void mpu_reset()
* Conditional public interface that resets the MPU to disabled immediately
* after reset.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_EARLY_RESET)
void mpu_early_reset()

View file

@ -130,6 +130,21 @@
# 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 */
struct mpu_region_s
{
/* Region Base Address */
uintptr_t base;
/* Region Size */
size_t size;
/* Region Attributes */
uint32_t flags;
};
/****************************************************************************
* Name: mpu_reset
*
@ -137,6 +152,12 @@
* Conditional public interface that resets the MPU to disabled during
* MPU initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET)
@ -152,6 +173,12 @@ void mpu_reset(void);
* Conditional public interface that resets the MPU to disabled immediately
* after reset.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_EARLY_RESET)
@ -180,12 +207,34 @@ extern "C"
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void);
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region);
/****************************************************************************
* Name: mpu_log2regionceil
*
@ -195,6 +244,12 @@ unsigned int mpu_allocregion(void);
*
* size <= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the ceiling value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionceil(size_t size);
@ -208,6 +263,12 @@ uint8_t mpu_log2regionceil(size_t size);
*
* size >= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the floor value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionfloor(size_t size);
@ -216,14 +277,22 @@ uint8_t mpu_log2regionfloor(size_t size);
* Name: mpu_subregion
*
* Description:
* Given (1) the offset to the beginning of valid data, (2) the size of the
* memory to be mapped and (2) the log2 size of the mapping to use,
* determine the minimal sub-region set to span that memory region.
* Given the size of the (1) memory to be mapped and (2) the log2 size
* of the mapping to use, determine the minimal sub-region set to span
* that memory region.
*
* Assumption:
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* l2size - Log2 of the actual region size is <= (1 << l2size).
*
* Returned Value:
* The subregion settings as a 32-bit value.
*
****************************************************************************/
uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size);
@ -234,19 +303,95 @@ uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size);
* Description:
* Configure and enable (or disable) the MPU
*
* Input Parameters:
* enable - Flag indicating whether to enable the MPU.
* hfnmiena - Flag indicating whether to enable the MPU during hard
* fult, NMI, and FAULTMAS.
* privdefena - Flag indicating whether to enable privileged access to
* the default memory map.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_control(bool enable, bool hfnmiena, bool privdefena);
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void);
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - Region number to modify.
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags);
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags);
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU initialization table.
* hfnmiena - A boolean indicating whether the MPU should enable the
* HFNMIENA bit.
* privdefena - A boolean indicating whether the MPU should enable the
* PRIVDEFENA bit.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table, bool hfnmiena,
bool privdefena);
/****************************************************************************
* Inline Functions
@ -284,18 +429,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_priv_stronglyordered(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
/* Not Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */); \
} \
while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
/* Not Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_user_flash
@ -306,18 +447,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_user_flash(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
/* Not Shareable */ \
MPU_RASR_AP_RORO /* P:RO U:RO */ \
/* Instruction access */); \
} \
while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
/* Not Shareable */ \
MPU_RASR_AP_RORO /* P:RO U:RO */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_priv_flash
@ -328,18 +465,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_priv_flash(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
/* Not Shareable */ \
MPU_RASR_AP_RONO /* P:RO U:None */ \
/* Instruction access */); \
} \
while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
/* Not Shareable */ \
MPU_RASR_AP_RONO /* P:RO U:None */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_user_intsram
@ -350,18 +483,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_user_intsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW /* P:RW U:RW */ \
/* Instruction access */); \
} \
while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW /* P:RW U:RW */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_priv_intsram
@ -372,18 +501,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_priv_intsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */); \
} \
while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
/* Not Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_priv_shmem
@ -393,18 +518,15 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
*
****************************************************************************/
#define mpu_priv_shmem(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO | /* P:RW U:None */ \
MPU_RASR_XN /* No Instruction access */); \
} while (0)
#define mpu_priv_shmem(base, size) \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO | /* P:RW U:None */ \
MPU_RASR_XN /* No Instruction access */)
/****************************************************************************
* Name: mpu_user_extsram
@ -415,17 +537,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_user_extsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW /* P:RW U:RW */ \
/* Instruction access */); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW /* P:RW U:RW */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_priv_extsram
@ -436,17 +555,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_priv_extsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_SO | /* Ordered */ \
MPU_RASR_C | /* Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO /* P:RW U:None */ \
/* Instruction access */)
/****************************************************************************
* Name: mpu_peripheral
@ -457,17 +573,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_peripheral(base, size) \
do \
{ \
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_DEV | /* Device */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO | /* P:RW U:None */ \
MPU_RASR_XN /* No Instruction access */); \
} while (0)
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_DEV | /* Device */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWNO | /* P:RW U:None */ \
MPU_RASR_XN /* No Instruction access */)
/****************************************************************************
* Name: mpu_user_peripheral
@ -478,17 +591,14 @@ void mpu_configure_region(uintptr_t base, size_t size, uint32_t flags);
****************************************************************************/
#define mpu_user_peripheral(base, size) \
do \
{ \
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_DEV | /* Device */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW | /* P:RW U:RW */ \
MPU_RASR_XN /* No Instruction access */); \
} while (0)
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RASR_TEX_DEV | /* Device */ \
/* Not Cacheable */ \
MPU_RASR_B | /* Bufferable */ \
MPU_RASR_S | /* Shareable */ \
MPU_RASR_AP_RWRW | /* P:RW U:RW */ \
MPU_RASR_XN /* No Instruction access */)
#undef EXTERN
#if defined(__cplusplus)

View file

@ -26,6 +26,7 @@
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include "mpu.h"
#include "arm_internal.h"
@ -68,9 +69,9 @@ static const uint8_t g_ls_regionmask[9] =
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
/* The next available region number */
/* The available region bitmap */
static uint8_t g_region;
static unsigned int g_mpu_region;
/****************************************************************************
* Private Functions
@ -88,6 +89,13 @@ static uint8_t g_region;
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* size: The size of the region.
* l2size: The L2 size of the region.
*
* Returned Value:
* The sub-region bitmask.
*
****************************************************************************/
static inline uint32_t mpu_subregion_ms(size_t size, uint8_t l2size)
@ -139,6 +147,13 @@ static inline uint32_t mpu_subregion_ms(size_t size, uint8_t l2size)
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* offset: The offset of the region.
* l2size: The L2 size of the region.
*
* Returned Value:
* The sub-region bitmask.
*
****************************************************************************/
static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size)
@ -183,6 +198,12 @@ static inline uint32_t mpu_subregion_ls(size_t offset, uint8_t l2size)
* Description:
* Resets the MPU to disabled.
*
* * Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET)
@ -214,17 +235,52 @@ static void mpu_reset_internal()
* Description:
* Allocate the next region
*
* Assumptions:
* - Regions are never deallocated
* - Regions are only allocated early in initialization, so no special
* protection against re-entrancy is required;
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void)
{
DEBUGASSERT(g_region < CONFIG_ARM_MPU_NREGIONS);
return (unsigned int)g_region++;
unsigned int i = ffs(~g_mpu_region) - 1;
/* There are not enough regions to apply */
DEBUGASSERT(i < CONFIG_ARM_MPU_NREGIONS);
g_mpu_region |= 1 << i;
return i;
}
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region)
{
DEBUGASSERT(region < CONFIG_ARM_MPU_NREGIONS);
/* Clear and disable the given MPU Region */
mpu_set_rgnr(region);
mpu_set_drbar(0);
mpu_set_dracr(0);
mpu_set_drsr(0);
g_mpu_region &= ~(1 << region);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
@ -236,6 +292,12 @@ unsigned int mpu_allocregion(void)
*
* size <= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the ceiling value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionceil(size_t size)
@ -257,6 +319,12 @@ uint8_t mpu_log2regionceil(size_t size)
*
* size >= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the floor value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionfloor(size_t size)
@ -283,6 +351,14 @@ uint8_t mpu_log2regionfloor(size_t size)
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* l2size - Log2 of the actual region size is <= (1 << l2size).
*
* Returned Value:
* The subregion settings as a 32-bit value.
*
****************************************************************************/
uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size)
@ -328,6 +404,156 @@ uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size)
return ret;
}
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - Region number to modify.
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags)
{
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Check that the region is valid */
DEBUGASSERT(g_mpu_region & (1 << region));
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* Configure the Region */
mpu_set_dracr(flags);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2(l2size) | /* Region size */
(subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region.
*
* Input Parameters:
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags)
{
unsigned int region = mpu_allocregion();
mpu_modify_region(region, base, size, flags);
return region;
}
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU Initiaze table.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table)
{
const struct mpu_region_s *conf;
int index;
mpu_control(false);
for (index = 0; index < nitems(table); index++)
{
conf = &table[index];
mpu_configure_region(conf->base, conf->size, conf->flags);
}
mpu_control(true);
}
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void)
{
int i;
int count = 0;
uint32_t dracr;
uint32_t drbar;
uint32_t drsr;
uint32_t sctrl;
/* Get free region */
sctrl = cp15_rdsctlr();
_info("MPU-SCTRL Enable:%" PRIu32 "\n", sctrl & SCTLR_M);
for (i = 0; i < CONFIG_ARM_MPU_NREGIONS; i++)
{
mpu_set_rgnr(i);
drbar = mpu_get_drbar();
dracr = mpu_get_dracr();
drsr = mpu_get_drsr();
_info("MPU-%d, base=0%08X l2size=%"PRIu32" bufferable=%u"
"cacheable=%u shareable=%u\n", i, drbar & MPU_RBAR_ADDR_MASK,
drsr & MPU_RASR_RSIZE_MASK, dracr & MPU_RACR_B,
dracr & MPU_RACR_C, dracr & MPU_RACR_S);
if (drsr & MPU_RASR_ENABLE)
{
count++;
}
}
_info("Total Use Region:%d, Remaining Available:%d\n", count,
CONFIG_ARM_MPU_NREGIONS - count);
}
/****************************************************************************
* Name: mpu_reset
*
@ -335,6 +561,12 @@ uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size)
* Conditional public interface that resets the MPU to disabled during
* MPU initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET)
void mpu_reset()
@ -350,6 +582,12 @@ void mpu_reset()
* Conditional public interface that resets the MPU to disabled immediately
* after reset.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_EARLY_RESET)
void mpu_early_reset()

View file

@ -126,6 +126,12 @@ extern "C"
* Conditional public interface that resets the MPU to disabled during
* MPU initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET)
@ -141,6 +147,12 @@ void mpu_reset(void);
* Conditional public interface that resets the MPU to disabled immediately
* after reset.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_EARLY_RESET)
@ -153,12 +165,34 @@ void mpu_early_reset(void);
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void);
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region);
/****************************************************************************
* Name: mpu_log2regionceil
*
@ -168,6 +202,12 @@ unsigned int mpu_allocregion(void);
*
* size <= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the ceiling value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionceil(size_t size);
@ -181,26 +221,111 @@ uint8_t mpu_log2regionceil(size_t size);
*
* size >= (1 << l2size)
*
* Input Parameters:
* size - The size of the region.
*
* Returned Value:
* The logarithm base 2 of the floor value for the MPU region size.
*
****************************************************************************/
uint8_t mpu_log2regionfloor(size_t size);
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void);
/****************************************************************************
* Name: mpu_subregion
*
* Description:
* Given (1) the offset to the beginning of valid data, (2) the size of the
* memory to be mapped and (2) the log2 size of the mapping to use,
* determine the minimal sub-region set to span that memory region.
* Given the size of the (1) memory to be mapped and (2) the log2 size
* of the mapping to use, determine the minimal sub-region set to span
* that memory region.
*
* Assumption:
* l2size has the same properties as the return value from
* mpu_log2regionceil()
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* l2size - Log2 of the actual region size is <= (1 << l2size).
*
* Returned Value:
* The subregion settings as a 32-bit value.
*
****************************************************************************/
uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size);
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - Region number to modify.
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags);
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* base - Base address of the region.
* size - Size of the region.
* flags - Flags to configure the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags);
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU Initiaze table.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table);
/****************************************************************************
* Inline Functions
****************************************************************************/
@ -218,6 +343,45 @@ static inline unsigned int mpu_get_mpuir(void)
return CP15_GET(MPUIR);
}
/****************************************************************************
* Name: mpu_get_drbar
*
* Description:
* Get the DRBAR register
*
****************************************************************************/
static inline unsigned int mpu_get_drbar(void)
{
return CP15_GET(DRBAR);
}
/****************************************************************************
* Name: mpu_get_drsr
*
* Description:
* Get the DRSR register
*
****************************************************************************/
static inline unsigned int mpu_get_drsr(void)
{
return CP15_GET(DRSR);
}
/****************************************************************************
* Name: mpu_get_dracr
*
* Description:
* Get the DRACR register
*
****************************************************************************/
static inline unsigned int mpu_get_dracr(void)
{
return CP15_GET(DRACR);
}
/****************************************************************************
* Name: mpu_set_drbar
*
@ -338,7 +502,13 @@ static inline void mpu_showtype(void)
* Name: mpu_control
*
* Description:
* Enable (or disable) the MPU
* Configure and enable (or disable) the MPU
*
* Input Parameters:
* enable - Flag indicating whether to enable the MPU.
*
* Returned Value:
* None.
*
****************************************************************************/
@ -373,39 +543,12 @@ static inline void mpu_control(bool enable)
*
****************************************************************************/
static inline void mpu_priv_stronglyordered(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = /* Not Cacheable */
/* Not Bufferable */
MPU_RACR_S | /* Shareable */
MPU_RACR_AP_RWNO; /* P:RW U:None */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_priv_stronglyordered(base, size) \
/* Not Cacheable */ \
/* Not Bufferable */ \
/* Shareable */ \
/* P:RW U:None */ \
mpu_configure_region(base, size, MPU_RACR_S | MPU_RACR_AP_RWNO)
/****************************************************************************
* Name: mpu_user_flash
@ -415,38 +558,10 @@ static inline void mpu_priv_stronglyordered(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_user_flash(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = /* Not Cacheable */
MPU_RACR_C | /* Cacheable */
MPU_RACR_AP_RORO; /* P:RO U:RO */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_user_flash(base, size) \
/* Cacheable */ \
/* P:RO U:RO */ \
mpu_configure_region(base, size, MPU_RACR_C | MPU_RACR_AP_RORO)
/****************************************************************************
* Name: mpu_priv_noncache
@ -456,43 +571,18 @@ static inline void mpu_user_flash(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_priv_noncache(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region
* inner/outer non-cache : TEX(4), C(0), B(0), S(1)
*/
regval = /* Not Cacheable */
/* Not Bufferable */
MPU_RACR_S | /* Shareable */
MPU_RACR_TEX(4) | /* TEX */
MPU_RACR_AP_RWRW | /* P:RO U:None */
MPU_RACR_XN; /* Instruction access disable */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_priv_noncache(base, size) \
/* inner/outer non-cache : TEX(4), C(0), B(0), S(1) */ \
/* Not Cacheable */ \
/* Not Bufferable */ \
/* Shareable */ \
/* TEX */ \
/* P:RO U:None ` */ \
/* Instruction access disable */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_TEX(4) | \
MPU_RACR_AP_RWRW | \
MPU_RACR_XN)
/****************************************************************************
* Name: mpu_priv_flash
@ -502,37 +592,10 @@ static inline void mpu_priv_noncache(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_priv_flash(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = MPU_RACR_C | /* Cacheable */
MPU_RACR_AP_RONO; /* P:RO U:None */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_priv_flash(base, size) \
/* Cacheable */ \
/* P:RO U:None */ \
mpu_configure_region(base, size, MPU_RACR_C | MPU_RACR_AP_RONO)
/****************************************************************************
* Name: mpu_user_intsram
@ -542,38 +605,13 @@ static inline void mpu_priv_flash(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_user_intsram(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = MPU_RACR_S | /* Shareable */
MPU_RACR_C | /* Cacheable */
MPU_RACR_AP_RWRW; /* P:RW U:RW */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_user_intsram(base, size) \
/* Shareable */ \
/* Cacheable */ \
/* P:RW U:RW */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_C | \
MPU_RACR_AP_RWRW)
/****************************************************************************
* Name: mpu_priv_intsram
@ -583,38 +621,13 @@ static inline void mpu_user_intsram(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_priv_intsram(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = MPU_RACR_S | /* Shareable */
MPU_RACR_C | /* Cacheable */
MPU_RACR_AP_RWNO; /* P:RW U:None */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_priv_intsram(base, size) \
/* Shareable */ \
/* Cacheable */ \
/* P:RW U:None */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_C | \
MPU_RACR_AP_RWNO)
/****************************************************************************
* Name: mpu_user_extsram
@ -624,39 +637,15 @@ static inline void mpu_priv_intsram(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_user_extsram(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = MPU_RACR_S | /* Shareable */
MPU_RACR_C | /* Cacheable */
MPU_RACR_B | /* Bufferable */
MPU_RACR_AP_RWRW; /* P:RW U:RW */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_user_extsram(base, size) \
/* Shareable */ \
/* Cacheable */ \
/* Bufferable */ \
/* P:RW U:RW */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_C | \
MPU_RACR_B | \
MPU_RACR_AP_RWRW)
/****************************************************************************
* Name: mpu_priv_extsram
@ -666,39 +655,15 @@ static inline void mpu_user_extsram(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_priv_extsram(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region */
regval = MPU_RACR_S | /* Shareable */
MPU_RACR_C | /* Cacheable */
MPU_RACR_B | /* Bufferable */
MPU_RACR_AP_RWNO; /* P:RW U:None */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_priv_extsram(base, size) \
/* Shareable */ \
/* Cacheable */ \
/* Bufferable */ \
/* P:RW U:None */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_C | \
MPU_RACR_B | \
MPU_RACR_AP_RWNO)
/****************************************************************************
* Name: mpu_peripheral
@ -708,39 +673,15 @@ static inline void mpu_priv_extsram(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_peripheral(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* Then configure the region */
regval = MPU_RACR_S | /* Shareable */
MPU_RACR_B | /* Bufferable */
MPU_RACR_AP_RWNO | /* P:RW U:None */
MPU_RACR_XN; /* Instruction access disable */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_peripheral(base, size) \
/* Shareable */ \
/* Bufferable */ \
/* P:RW U:None */ \
/* Instruction access disable */ \
mpu_configure_region(base, size, MPU_RACR_S | \
MPU_RACR_B | \
MPU_RACR_AP_RWNO | \
MPU_RACR_XN)
/****************************************************************************
* Name: mpu_user_intsram_wb
@ -751,41 +692,14 @@ static inline void mpu_peripheral(uintptr_t base, size_t size)
*
****************************************************************************/
static inline void mpu_user_intsram_wb(uintptr_t base, size_t size)
{
unsigned int region = mpu_allocregion();
uint32_t regval;
uint8_t l2size;
uint8_t subregions;
/* Select the region */
mpu_set_rgnr(region);
/* Select the region base address */
mpu_set_drbar(base & MPU_RBAR_ADDR_MASK);
/* Select the region size and the sub-region map */
l2size = mpu_log2regionceil(size);
subregions = mpu_subregion(base, size, l2size);
/* The configure the region
* WB/Write Allocate: TEX(5), C(0), B(1), S(1)
*/
regval = /* Not Cacheable */
MPU_RACR_B | /* Not Bufferable */
MPU_RACR_TEX(5) | /* TEX */
MPU_RACR_AP_RWRW; /* P:RW U:RW */
mpu_set_dracr(regval);
regval = MPU_RASR_ENABLE | /* Enable region */
MPU_RASR_RSIZE_LOG2((uint32_t)l2size) | /* Region size */
((uint32_t)subregions << MPU_RASR_SRD_SHIFT); /* Sub-regions */
mpu_set_drsr(regval);
}
#define mpu_user_intsram_wb(base, size) \
/* Not Cacheable */ \
/* Not Bufferable */ \
/* TEX */ \
/* P:RW U:RW */ \
mpu_configure_region(base, size, MPU_RACR_B | \
MPU_RACR_TEX(5) | \
MPU_RACR_AP_RWRW)
#undef EXTERN
#if defined(__cplusplus)

View file

@ -26,6 +26,8 @@
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <sys/param.h>
#include "mpu.h"
#include "arm_internal.h"
@ -45,39 +47,26 @@
* Private Data
****************************************************************************/
/* The next available region number */
/* The available region bitmap */
static uint8_t g_region;
static unsigned int g_mpu_region;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
*
* Assumptions:
* - Regions are never deallocated
* - Regions are only allocated early in initialization, so no special
* protection against re-entrancy is required;
*
****************************************************************************/
unsigned int mpu_allocregion(void)
{
DEBUGASSERT(g_region < CONFIG_ARM_MPU_NREGIONS);
return (unsigned int)g_region++;
}
/****************************************************************************
* Name: mpu_reset_internal
*
* Description:
* Resets the MPU to disabled.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET) || defined(CONFIG_ARM_MPU_EARLY_RESET)
@ -91,7 +80,7 @@ static void mpu_reset_internal()
for (region = 0; region < regions; region++)
{
putreg32(region, MPU_RNR);
putreg32(0, MPU_RASR);
putreg32(0, MPU_RLAR);
putreg32(0, MPU_RBAR);
}
@ -106,12 +95,75 @@ static void mpu_reset_internal()
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void)
{
unsigned int i = ffs(~g_mpu_region) - 1;
/* There are not enough regions to apply */
DEBUGASSERT(i < CONFIG_ARM_MPU_NREGIONS);
g_mpu_region |= 1 << i;
return i;
}
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region)
{
DEBUGASSERT(region < CONFIG_ARM_MPU_NREGIONS);
/* Clear and disable the given MPU Region */
putreg32(region, MPU_RNR);
putreg32(0, MPU_RLAR);
putreg32(0, MPU_RBAR);
g_mpu_region &= ~(1 << region);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
* Name: mpu_control
*
* Description:
* Configure and enable (or disable) the MPU
*
* Input Parameters:
* enable - Flag indicating whether to enable the MPU.
* hfnmiena - Flag indicating whether to enable the MPU during hard
* fult, NMI, and FAULTMAS.
* privdefena - Flag indicating whether to enable privileged access to
* the default memory map.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_control(bool enable, bool hfnmiena, bool privdefena)
@ -151,18 +203,32 @@ void mpu_control(bool enable, bool hfnmiena, bool privdefena)
}
/****************************************************************************
* Name: mpu_configure_region
* Name: mpu_modify_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - The index of the MPU region to modify.
* base - The base address of the region.
* size - The size of the region.
* flags1 - Additional flags for the region.
* flags2 - Additional flags for the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2)
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2)
{
unsigned int region = mpu_allocregion();
uintptr_t limit;
uintptr_t limit;
uintptr_t rbase;
/* Check that the region is valid */
DEBUGASSERT(g_mpu_region & (1 << region));
/* Ensure the base address alignment
*
@ -173,7 +239,7 @@ void mpu_configure_region(uintptr_t base, size_t size,
*/
limit = (base + size - 1) & MPU_RLAR_LIMIT_MASK;
base &= MPU_RBAR_BASE_MASK;
rbase = base & MPU_RBAR_BASE_MASK;
/* Select the region */
@ -181,7 +247,7 @@ void mpu_configure_region(uintptr_t base, size_t size,
/* Set the region base, limit and attribute */
putreg32(base | flags1, MPU_RBAR);
putreg32(rbase | flags1, MPU_RBAR);
putreg32(limit | flags2 | MPU_RLAR_ENABLE, MPU_RLAR);
/* Ensure MPU setting take effects */
@ -190,6 +256,113 @@ void mpu_configure_region(uintptr_t base, size_t size,
ARM_ISB();
}
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* flags1 - Additional flags for the region.
* flags2 - Additional flags for the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2)
{
unsigned int region = mpu_allocregion();
mpu_modify_region(region, base, size, flags1, flags2);
return region;
}
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU initialization table.
* hfnmiena - A boolean indicating whether the MPU should enable the
* HFNMIENA bit.
* privdefena - A boolean indicating whether the MPU should enable the
* PRIVDEFENA bit.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table, bool hfnmiena,
bool privdefena)
{
const struct mpu_region_s *conf;
int index;
mpu_control(false, false, false);
for (index = 0; index < nitems(table); index++)
{
conf = &table[index];
mpu_configure_region(conf->base, conf->size, conf->flags1,
conf->flags2);
}
mpu_control(true, hfnmiena, privdefena);
}
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void)
{
int i;
int count = 0;
uint32_t rlar;
uint32_t rbar;
uint32_t ctrl;
/* Get free region */
ctrl = getreg32(MPU_CTRL);
_info("MPU-CTRL Enable:%" PRIu32 ", HFNMIENA:%"PRIu32","
"PRIVDEFENA:%" PRIu32 "\n", ctrl & MPU_CTRL_ENABLE,
ctrl & MPU_CTRL_HFNMIENA, ctrl & MPU_CTRL_PRIVDEFENA);
for (i = 0; i < CONFIG_ARM_MPU_NREGIONS; i++)
{
putreg32(i, MPU_RNR);
rlar = getreg32(MPU_RLAR);
rbar = getreg32(MPU_RBAR);
_info("MPU-%d, 0x%08X-0x%08X SH=%X AP=%X XN=%u\n",
i, rbar & MPU_RBAR_BASE_MASK, rlar & MPU_RLAR_LIMIT_MASK,
rbar & MPU_RBAR_SH_MASK, rbar & MPU_RBAR_AP_MASK,
rbar & MPU_RBAR_XN);
if (rlar & MPU_RLAR_ENABLE)
{
count++;
}
}
_info("Total Use Region:%d, Remaining Available:%d\n", count,
CONFIG_ARM_MPU_NREGIONS - count);
}
/****************************************************************************
* Name: mpu_reset
*
@ -197,6 +370,12 @@ void mpu_configure_region(uintptr_t base, size_t size,
* Conditional public interface that resets the MPU to disabled during
* MPU initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_RESET)
void mpu_reset()
@ -212,6 +391,12 @@ void mpu_reset()
* Conditional public interface that resets the MPU to disabled immediately
* after reset.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU_EARLY_RESET)
void mpu_early_reset()

View file

@ -168,6 +168,21 @@
MPU_MAIR_OUTER_RA | MPU_MAIR_OUTER_WA | \
MPU_MAIR_INNER_NT | MPU_MAIR_INNER_WB | \
MPU_MAIR_INNER_RA | MPU_MAIR_INNER_WA)
struct mpu_region_s
{
/* Region Base Address */
uintptr_t base;
/* Region Size */
size_t size;
/* Region Attributes */
uint32_t flags1;
uint32_t flags2;
};
/****************************************************************************
* Name: mpu_reset
@ -215,26 +230,135 @@ extern "C"
#define EXTERN extern
#endif
/****************************************************************************
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void);
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region);
/****************************************************************************
* Name: mpu_control
*
* Description:
* Configure and enable (or disable) the MPU
*
* Input Parameters:
* enable - Flag indicating whether to enable the MPU.
* hfnmiena - Flag indicating whether to enable the MPU during hard
* fult, NMI, and FAULTMAS.
* privdefena - Flag indicating whether to enable privileged access to
* the default memory map.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_control(bool enable, bool hfnmiena, bool privdefena);
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_dump_region(void);
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - The index of the MPU region to modify.
* base - The base address of the region.
* size - The size of the region.
* flags1 - Additional flags for the region.
* flags2 - Additional flags for the region.
*
* Returned Value:
* None.
*
****************************************************************************/
void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2);
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* base - The base address of the region.
* size - The size of the region.
* flags1 - Additional flags for the region.
* flags2 - Additional flags for the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
void mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2);
unsigned int mpu_configure_region(uintptr_t base, size_t size,
uint32_t flags1, uint32_t flags2);
/****************************************************************************
* Name: mpu_initialize
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - MPU initialization table.
* hfnmiena - A boolean indicating whether the MPU should enable the
* HFNMIENA bit.
* privdefena - A boolean indicating whether the MPU should enable the
* PRIVDEFENA bit.
*
* Returned Value:
* NULL.
*
****************************************************************************/
void mpu_initialize(const struct mpu_region_s *table, bool hfnmiena,
bool privdefena);
/****************************************************************************
* Inline Functions
@ -271,14 +395,11 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_priv_stronglyordered(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_STRONGLY_ORDER | \
MPU_RLAR_PXN); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_STRONGLY_ORDER | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_user_flash
@ -289,13 +410,10 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_user_flash(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RORO, \
MPU_RLAR_WRITE_BACK); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RORO, \
MPU_RLAR_WRITE_BACK)
/****************************************************************************
* Name: mpu_priv_flash
@ -306,13 +424,10 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_priv_flash(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RONO, \
MPU_RLAR_WRITE_BACK); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RONO, \
MPU_RLAR_WRITE_BACK)
/****************************************************************************
* Name: mpu_user_intsram
@ -323,15 +438,12 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_user_intsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW, \
MPU_RLAR_NONCACHEABLE | \
MPU_RLAR_PXN); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW, \
MPU_RLAR_NONCACHEABLE | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_priv_intsram
@ -342,14 +454,11 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_priv_intsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_NONCACHEABLE | \
MPU_RLAR_PXN); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_NONCACHEABLE | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_priv_shmem
@ -359,16 +468,13 @@ void mpu_configure_region(uintptr_t base, size_t size,
*
****************************************************************************/
#define mpu_priv_shmem(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_NONCACHEABLE | \
MPU_RBAR_SH_INNER | \
MPU_RLAR_PXN); \
} while (0)
#define mpu_priv_shmem(base, size) \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_NONCACHEABLE | \
MPU_RBAR_SH_INNER | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_user_extsram
@ -379,16 +485,13 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_user_extsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW | \
MPU_RBAR_SH_OUTER, \
MPU_RLAR_WRITE_BACK | \
MPU_RLAR_PXN); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW | \
MPU_RBAR_SH_OUTER, \
MPU_RLAR_WRITE_BACK | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_priv_extsram
@ -399,15 +502,12 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_priv_extsram(base, size) \
do \
{ \
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO | \
MPU_RBAR_SH_OUTER, \
MPU_RLAR_WRITE_BACK | \
MPU_RLAR_PXN); \
} while (0)
/* The configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO | \
MPU_RBAR_SH_OUTER, \
MPU_RLAR_WRITE_BACK | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_peripheral
@ -418,14 +518,11 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_peripheral(base, size) \
do \
{ \
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_DEVICE | \
MPU_RLAR_PXN); \
} while (0)
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_AP_RWNO, \
MPU_RLAR_DEVICE | \
MPU_RLAR_PXN)
/****************************************************************************
* Name: mpu_user_peripheral
@ -436,15 +533,12 @@ void mpu_configure_region(uintptr_t base, size_t size,
****************************************************************************/
#define mpu_user_peripheral(base, size) \
do \
{ \
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW, \
MPU_RLAR_DEVICE | \
MPU_RLAR_PXN); \
} while (0)
/* Then configure the region */ \
mpu_configure_region(base, size, \
MPU_RBAR_XN | \
MPU_RBAR_AP_RWRW, \
MPU_RLAR_DEVICE | \
MPU_RLAR_PXN)
#undef EXTERN
#if defined(__cplusplus)

View file

@ -1,4 +1,4 @@
/***************************************************************************
/****************************************************************************
* arch/arm64/src/common/arm64_mpu.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -16,11 +16,11 @@
* License for the specific language governing permissions and limitations
* under the License.
*
***************************************************************************/
****************************************************************************/
/***************************************************************************
/****************************************************************************
* Included Files
***************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
@ -36,9 +36,9 @@
#include "arm64_fatal.h"
#include "arm64_mpu.h"
/***************************************************************************
/****************************************************************************
* Pre-processor Definitions
***************************************************************************/
****************************************************************************/
#define __MPU_ASSERT(__cond, fmt, ...) \
do \
@ -70,65 +70,50 @@
* regions.
*/
static uint8_t static_regions_num;
static unsigned int g_mpu_region;
/***************************************************************************
/****************************************************************************
* Private Functions
***************************************************************************/
****************************************************************************/
/* Get the number of supported MPU regions. */
/****************************************************************************
* Name: get_num_regions
*
* Description:
* Get the number of supported MPU regions.
*
* Input Parameters:
* None
*
* Returned Value:
* Numbers of the region.
*
****************************************************************************/
static inline uint8_t get_num_regions(void)
static inline unsigned int get_num_regions(void)
{
uint64_t type;
type = read_sysreg(mpuir_el1);
type = type & MPU_IR_REGION_MSK;
return (uint8_t)type;
return (unsigned int)type;
}
/* ARM Core MPU Driver API Implementation for ARM MPU */
/* Enable the MPU */
void arm64_core_mpu_enable(void)
{
uint64_t val;
val = read_sysreg(sctlr_el1);
val |= (SCTLR_M_BIT
#ifndef CONFIG_ARM64_DCACHE_DISABLE
| SCTLR_C_BIT
#endif
);
write_sysreg(val, sctlr_el1);
ARM64_DSB();
ARM64_ISB();
}
/* Disable the MPU */
void arm64_core_mpu_disable(void)
{
uint64_t val;
/* Force any outstanding transfers to complete before disabling MPU */
ARM64_DMB();
val = read_sysreg(sctlr_el1);
val &= ~(SCTLR_M_BIT | SCTLR_C_BIT);
write_sysreg(val, sctlr_el1);
ARM64_DSB();
ARM64_ISB();
}
/* ARM MPU Driver Initial Setup
/****************************************************************************
* Name: mpu_init
*
* Configure the cache-ability attributes for all the
* different types of memory regions.
*/
* Description:
* Configure the cache-ability attributes for all the different types
* of memory regions.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void mpu_init(void)
{
@ -145,44 +130,257 @@ static void mpu_init(void)
ARM64_ISB();
}
static inline void mpu_set_region(uint32_t rnr, uint64_t rbar,
uint64_t rlar)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void)
{
write_sysreg(rnr, prselr_el1);
unsigned int num_regions = get_num_regions();
unsigned int i = ffs(~g_mpu_region) - 1;
/* There are not enough regions to apply */
DEBUGASSERT(i < num_regions);
g_mpu_region |= 1 << i;
return i;
}
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region)
{
unsigned int num_regions = get_num_regions();
/* Check region vaild */
DEBUGASSERT(region < num_regions);
write_sysreg(region, prselr_el1);
ARM64_DSB();
/* Set the region base, limit and attribute */
write_sysreg(0, prbar_el1);
write_sysreg(0, prlar_el1);
g_mpu_region &= ~(1 << region);
ARM64_DSB();
ARM64_ISB();
}
/****************************************************************************
* Name: arm64_mpu_enable
*
* Description:
* Enable the MPU
*
* Input Parameters:
* None
*
* Return Value:
* None
*
****************************************************************************/
void arm64_mpu_enable(void)
{
uint64_t val;
val = read_sysreg(sctlr_el1);
val |= (SCTLR_M_BIT
#ifndef CONFIG_ARM64_DCACHE_DISABLE
| SCTLR_C_BIT
#endif
);
write_sysreg(val, sctlr_el1);
ARM64_DSB();
ARM64_ISB();
}
/****************************************************************************
* Name: arm64_mpu_disable
*
* Description:
* Disable the MPU
*
* Input Parameters:
* None
*
* Return Value:
* None
*
****************************************************************************/
void arm64_mpu_disable(void)
{
uint64_t val;
/* Force any outstanding transfers to complete before disabling MPU */
ARM64_DMB();
val = read_sysreg(sctlr_el1);
val &= ~(SCTLR_M_BIT | SCTLR_C_BIT);
write_sysreg(val, sctlr_el1);
ARM64_DSB();
ARM64_ISB();
}
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - The index of the MPU region to modify.
* table - Pointer to a struct containing the configuration
* parameters for the region.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_modify_region(unsigned int region,
const struct arm64_mpu_region *table)
{
uint64_t rbar = table->base & MPU_RBAR_BASE_MSK;
uint64_t rlar = (table->limit - 1) & MPU_RLAR_LIMIT_MSK;
/* Check that the region is valid */
DEBUGASSERT(g_mpu_region & (1 << region));
rbar |= table->attr.rbar &
(MPU_RBAR_XN_MSK | MPU_RBAR_AP_MSK | MPU_RBAR_SH_MSK);
rlar |=
(table->attr.mair_idx <<
MPU_RLAR_ATTRINDX_POS) & MPU_RLAR_ATTRINDX_MSK;
rlar |= MPU_RLAR_EN_MSK;
/* Select the region */
write_sysreg(region, prselr_el1);
ARM64_DSB();
/* Set the region base, limit and attribute */
write_sysreg(rbar, prbar_el1);
write_sysreg(rlar, prlar_el1);
ARM64_DSB();
ARM64_ISB();
}
/* This internal functions performs MPU region initialization. */
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - Pointer to a struct containing the configuration
* parameters for the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
static void region_init(const uint32_t index,
const struct arm64_mpu_region *region_conf)
unsigned int mpu_configure_region(const struct arm64_mpu_region *
table)
{
uint64_t rbar = region_conf->base & MPU_RBAR_BASE_MSK;
uint64_t rlar = (region_conf->limit - 1) & MPU_RLAR_LIMIT_MSK;
rbar |= region_conf->attr.rbar &
(MPU_RBAR_XN_MSK | MPU_RBAR_AP_MSK | MPU_RBAR_SH_MSK);
rlar |=
(region_conf->attr.mair_idx <<
MPU_RLAR_ATTRINDX_POS) & MPU_RLAR_ATTRINDX_MSK;
rlar |= MPU_RLAR_EN_MSK;
mpu_set_region(index, rbar, rlar);
unsigned int region = mpu_allocregion();
mpu_modify_region(region, table);
return region;
}
/***************************************************************************
* Public Functions
***************************************************************************/
/* @brief MPU default configuration
/****************************************************************************
* Name: mpu_dump_region
*
* This function here provides the default configuration mechanism
* for the Memory Protection Unit (MPU).
*/
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
****************************************************************************/
void mpu_dump_region(void)
{
uint64_t sctlr_el1;
uint64_t prlar;
uint64_t prbar;
unsigned int num_regions;
int i;
int count = 0;
num_regions = get_num_regions();
sctlr_el1 = read_sysreg(sctlr_el1);
_info("MPU-SCTLR_EL1 Enable:%" PRIu64 ", Cacheable: %" PRIu64 "\n",
sctlr_el1 & SCTLR_M_BIT, sctlr_el1 & SCTLR_C_BIT);
for (i = 0; i < num_regions; i++)
{
write_sysreg(i, prselr_el1);
prlar = read_sysreg(prlar_el1);
prbar = read_sysreg(prbar_el1);
_info("MPU-%d, 0x%08X-0x%08X SH=%X AP=%X XN=%X\n", i,
prbar & MPU_RBAR_BASE_MSK, prlar & MPU_RLAR_LIMIT_MSK,
prbar & MPU_RBAR_SH_MSK, prbar & MPU_RBAR_AP_MSK,
prbar & MPU_RBAR_XN_MSK);
if (prlar & MPU_RLAR_EN_MSK)
{
count++;
}
}
_info("Total Use Region:%d, Remaining Available:%d\n", count,
num_regions - count);
}
/****************************************************************************
* Name: arm64_mpu_init
*
* Description:
* This function here provides the default configuration mechanism
* for the Memory Protection Unit (MPU).
*
* Input Parameters:
* is_primary_core: A boolean indicating whether the current core is the
* primary core.
*
* Returned Value:
* None
*
****************************************************************************/
void arm64_mpu_init(bool is_primary_core)
{
@ -206,21 +404,7 @@ void arm64_mpu_init(bool is_primary_core)
return;
}
if (g_mpu_config.num_regions > get_num_regions())
{
/* Attempt to configure more MPU regions than
* what is supported by hardware. As this operation
* is executed during system (pre-kernel) initialization,
* we want to ensure we can detect an attempt to
* perform invalid configuration.
*/
__MPU_ASSERT(0, "Request to configure: %u regions (supported: %u)\n",
g_mpu_config.num_regions, get_num_regions());
return;
}
arm64_core_mpu_disable();
arm64_mpu_disable();
/* Architecture-specific configuration */
@ -230,12 +414,8 @@ void arm64_mpu_init(bool is_primary_core)
for (r_index = 0U; r_index < g_mpu_config.num_regions; r_index++)
{
region_init(r_index, &g_mpu_config.mpu_regions[r_index]);
mpu_configure_region(&g_mpu_config.mpu_regions[r_index]);
}
/* Update the number of programmed MPU regions. */
static_regions_num = g_mpu_config.num_regions;
arm64_core_mpu_enable();
arm64_mpu_enable();
}

View file

@ -304,6 +304,131 @@ extern const struct arm64_mpu_config g_mpu_config;
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mpu_allocregion
*
* Description:
* Allocate the next region
*
* Input Parameters:
* None
*
* Returned Value:
* The index of the allocated region.
*
****************************************************************************/
unsigned int mpu_allocregion(void);
/****************************************************************************
* Name: mpu_freeregion
*
* Description:
* Free target region.
*
* Input Parameters:
* region - The index of the region to be freed.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_freeregion(unsigned int region);
/****************************************************************************
* Name: arm64_mpu_enable
*
* Description:
* Enable the MPU
*
* Input Parameters:
* None
*
* Return Value:
* None
*
****************************************************************************/
void arm64_mpu_enable(void);
/****************************************************************************
* Name: arm64_mpu_disable
*
* Description:
* Disable the MPU
*
* Input Parameters:
* None
*
* Return Value:
* None
*
****************************************************************************/
void arm64_mpu_disable(void);
/****************************************************************************
* Name: mpu_dump_region
*
* Description:
* Dump the region that has been used.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
****************************************************************************/
void mpu_dump_region(void);
/****************************************************************************
* Name: mpu_modify_region
*
* Description:
* Modify a region for privileged, strongly ordered memory
*
* Input Parameters:
* region - The index of the MPU region to modify.
* table - Pointer to a struct containing the configuration
* parameters for the region.
*
* Returned Value:
* None
*
****************************************************************************/
void mpu_modify_region(unsigned int region,
const struct arm64_mpu_region *table);
/****************************************************************************
* Name: mpu_configure_region
*
* Description:
* Configure a region for privileged, strongly ordered memory
*
* Input Parameters:
* table - Pointer to a struct containing the configuration
* parameters for the region.
*
* Returned Value:
* The region number allocated for the configured region.
*
****************************************************************************/
unsigned int mpu_configure_region(const struct arm64_mpu_region *
table);
/****************************************************************************
* Name: arm64_mpu_init
*
* Description:
* This function here provides the default configuration mechanism
* for the Memory Protection Unit (MPU).
*
****************************************************************************/
void arm64_mpu_init(bool is_primary_core);
#endif /* __ASSEMBLY__ */