diff --git a/arch/arm/core/cortex_m/mpu/nxp_mpu.c b/arch/arm/core/cortex_m/mpu/nxp_mpu.c index eb472e582ca..05e627d8f80 100644 --- a/arch/arm/core/cortex_m/mpu/nxp_mpu.c +++ b/arch/arm/core/cortex_m/mpu/nxp_mpu.c @@ -13,6 +13,29 @@ #include #include +#define STACK_GUARD_REGION_SIZE 32 + +/* NXP MPU Enabled state */ +static u8_t nxp_mpu_enabled; + +/** + * This internal function is utilized by the MPU driver to parse the intent + * type (i.e. THREAD_STACK_REGION) and return the correct parameter set. + */ +static inline u32_t _get_region_attr_by_type(u32_t type) +{ + switch (type) { + case THREAD_STACK_REGION: + return 0; + case THREAD_STACK_GUARD_REGION: + /* The stack guard region has to be not accessible */ + return REGION_RO_ATTR; + default: + /* Size 0 region */ + return 0; + } +} + static inline u8_t _get_num_regions(void) { u32_t type = (SYSMPU->CESR & SYSMPU_CESR_NRGD_MASK) @@ -48,6 +71,108 @@ static void _region_init(u32_t index, u32_t region_base, SYSMPU->WORD[index][3]); } +/* ARM Core MPU Driver API Implementation for NXP MPU */ + +/** + * @brief enable the MPU + */ +void arm_core_mpu_enable(void) +{ + if (nxp_mpu_enabled == 0) { + /* Enable MPU */ + SYSMPU->CESR |= SYSMPU_CESR_VLD_MASK; + + nxp_mpu_enabled = 1; + } +} + +/** + * @brief disable the MPU + */ +void arm_core_mpu_disable(void) +{ + if (nxp_mpu_enabled == 1) { + /* Disable MPU */ + SYSMPU->CESR &= ~SYSMPU_CESR_VLD_MASK; + /* Clear Interrupts */ + SYSMPU->CESR |= SYSMPU_CESR_SPERR_MASK; + + nxp_mpu_enabled = 0; + } +} + +/** + * @brief configure the base address and size for an MPU region + * + * @param type MPU region type + * @param base base address in RAM + * @param size size of the region + */ +void arm_core_mpu_configure(u8_t type, u32_t base, u32_t size) +{ + SYS_LOG_DBG("Region info: 0x%x 0x%x", base, size); + /* + * The new MPU regions are are allocated per type after the statically + * configured regions. + */ + u32_t region_index = mpu_config.num_regions + type; + u32_t region_attr = _get_region_attr_by_type(type); + u32_t last_region = _get_num_regions() - 1; + + /* + * The NXP MPU manages the permissions of the overlapping regions + * doing the logic OR in between them, hence they can't be used + * for stack/stack guard protection. For this reason the last region of + * the MPU will be reserved. + * + * A consequence of this is that the SRAM is splitted in different + * regions. In example if THREAD_STACK_GUARD_REGION is selected: + * - SRAM before THREAD_STACK_GUARD_REGION: RW + * - SRAM THREAD_STACK_GUARD_REGION: RO + * - SRAM after THREAD_STACK_GUARD_REGION: RW + */ + /* NXP MPU supports up to 16 Regions */ + if (region_index > _get_num_regions() - 2) { + return; + } + + /* Configure SRAM_0 region */ + /* + * The mpu_config.sram_region contains the index of the region in + * the mpu_config.mpu_regions array but the region 0 on the NXP MPU + * is the background region, so on this MPU the regions are mapped + * starting from 1, hence the mpu_config.sram_region on the data + * structure is mapped on the mpu_config.sram_region + 1 region of + * the MPU. + */ + _region_init(mpu_config.sram_region + 1, + mpu_config.mpu_regions[mpu_config.sram_region].base, + ENDADDR_ROUND(base), + mpu_config.mpu_regions[mpu_config.sram_region].attr); + + switch (type) { + case THREAD_STACK_REGION: + break; + case THREAD_STACK_GUARD_REGION: + _region_init(region_index, base, + ENDADDR_ROUND(base + STACK_GUARD_REGION_SIZE), + region_attr); + break; + default: + break; + } + + /* Configure SRAM_1 region */ + _region_init(last_region, + base + STACK_GUARD_REGION_SIZE, + ENDADDR_ROUND( + mpu_config.mpu_regions[mpu_config.sram_region].end), + mpu_config.mpu_regions[mpu_config.sram_region].attr); + +} + +/* NXP MPU Driver Initial Setup */ + /* * @brief MPU default configuration * @@ -75,6 +200,12 @@ static void _nxp_mpu_config(void) /* Disable Region 0 */ SYSMPU->WORD[0][2] = 0; + SYS_LOG_DBG("[0] 0x%08x 0x%08x 0x%08x 0x%08x", + SYSMPU->WORD[0][0], + SYSMPU->WORD[0][1], + SYSMPU->WORD[0][2], + SYSMPU->WORD[0][3]); + /* * Configure regions: * r_index starts from 0 but is passed to region_init as r_index + 1, @@ -90,6 +221,8 @@ static void _nxp_mpu_config(void) /* Enable MPU */ SYSMPU->CESR |= SYSMPU_CESR_VLD_MASK; + nxp_mpu_enabled = 1; + /* Make sure that all the registers are set before proceeding */ __DSB(); __ISB(); diff --git a/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c b/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c index 72da4a6ea62..8a9af1fad37 100644 --- a/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c +++ b/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c @@ -46,4 +46,5 @@ static struct nxp_mpu_region mpu_regions[] = { struct nxp_mpu_config mpu_config = { .num_regions = ARRAY_SIZE(mpu_regions), .mpu_regions = mpu_regions, + .sram_region = 3, }; diff --git a/include/arch/arm/cortex_m/mpu/nxp_mpu.h b/include/arch/arm/cortex_m/mpu/nxp_mpu.h index ba4e74415e2..9b33bb84b29 100644 --- a/include/arch/arm/cortex_m/mpu/nxp_mpu.h +++ b/include/arch/arm/cortex_m/mpu/nxp_mpu.h @@ -25,11 +25,15 @@ /* Super User Attributes */ #define MPU_REGION_SU ((3 << 3) | (3 << 9) | (3 << 15) | (3 << 21)) +/* The ENDADDR field has the last 5 bit reserved and set to 1 */ +#define ENDADDR_ROUND(x) (x - 0x1F) + /* Some helper defines for common regions */ #define REGION_RAM_ATTR (MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU) #define REGION_FLASH_ATTR (MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU) #define REGION_IO_ATTR (MPU_REGION_READ | MPU_REGION_WRITE | \ MPU_REGION_EXEC | MPU_REGION_SU) +#define REGION_RO_ATTR (MPU_REGION_READ | MPU_REGION_SU) /* Region definition data structure */ struct nxp_mpu_region { @@ -57,6 +61,8 @@ struct nxp_mpu_config { u32_t num_regions; /* Regions */ struct nxp_mpu_region *mpu_regions; + /* SRAM Region */ + u32_t sram_region; }; /* Reference to the MPU configuration */ diff --git a/samples/mpu_stack_guard_test/testcase.ini b/samples/mpu_stack_guard_test/testcase.ini index 1de64db74af..01a0401af73 100644 --- a/samples/mpu_stack_guard_test/testcase.ini +++ b/samples/mpu_stack_guard_test/testcase.ini @@ -7,4 +7,4 @@ build_only = true extra_args = CONF_FILE=prj_stack_guard.conf tags = apps arch_whitelist = arm -filter = CONFIG_MPU_STACK_GUARD and CONFIG_ARM_MPU +filter = CONFIG_MPU_STACK_GUARD