arm: soc: nxp k6x: Add Initial support for NXP MPU

This patch adds initial MPU support to NXP K6x family.
The boot configuration prevents the following security issues:
* Prevent to read at an address that is reserved in the memory map.
* Prevent to write into the boot Flash/ROM.
* Prevent from running code located in SRAM.

This driver has been tested on FRDM-K64F.

Change-Id: I907168fff0c6028f1c665f1d3c224cbeec31be32
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@linaro.org>
This commit is contained in:
Vincenzo Frascino 2017-03-24 20:18:13 +00:00 committed by Kumar Gala
commit adf0bf90b6
10 changed files with 267 additions and 0 deletions

View file

@ -13,3 +13,11 @@ config ARM_MPU
default n default n
help help
MCU has ARM MPU MCU has ARM MPU
config NXP_MPU
bool "NXP MPU Support"
depends on CPU_HAS_MPU
depends on SOC_FAMILY_KINETIS
default n
help
MCU has NXP MPU

View file

@ -1 +1,2 @@
obj-$(CONFIG_ARM_MPU) += arm_mpu.o obj-$(CONFIG_ARM_MPU) += arm_mpu.o
obj-$(CONFIG_NXP_MPU) += nxp_mpu.o

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <init.h>
#include <kernel.h>
#include <soc.h>
#include <arch/arm/cortex_m/cmsis.h>
#include <arch/arm/cortex_m/mpu/nxp_mpu.h>
#include <logging/sys_log.h>
#include <misc/__assert.h>
static inline u8_t _get_num_regions(void)
{
u32_t type = (SYSMPU->CESR & SYSMPU_CESR_NRGD_MASK)
>> SYSMPU_CESR_NRGD_SHIFT;
switch (type) {
case 0:
return 8;
case 1:
return 12;
case 2:
return 16;
default:
__ASSERT(0, "Unsupported MPU configuration.");
return 0;
}
return NXP_MPU_REGION_NUMBER;
}
static void _region_init(u32_t index, u32_t region_base,
u32_t region_end, u32_t region_attr)
{
SYSMPU->WORD[index][0] = region_base;
SYSMPU->WORD[index][1] = region_end;
SYSMPU->WORD[index][2] = region_attr;
SYSMPU->WORD[index][3] = SYSMPU_WORD_VLD_MASK;
SYS_LOG_DBG("[%d] 0x%08x 0x%08x 0x%08x 0x%08x", index,
SYSMPU->WORD[index][0],
SYSMPU->WORD[index][1],
SYSMPU->WORD[index][2],
SYSMPU->WORD[index][3]);
}
/*
* @brief MPU default configuration
*
* This function provides the default configuration mechanism for the Memory
* Protection Unit (MPU).
*/
static void _nxp_mpu_config(void)
{
u32_t r_index;
SYS_LOG_DBG("region number: %d", _get_num_regions());
/* NXP MPU supports up to 16 Regions */
if (mpu_config.num_regions > _get_num_regions()) {
return;
}
/* Disable MPU */
SYSMPU->CESR &= ~SYSMPU_CESR_VLD_MASK;
/* Clear Interrupts */
SYSMPU->CESR |= SYSMPU_CESR_SPERR_MASK;
/* MPU Configuration */
/* Disable Region 0 */
SYSMPU->WORD[0][2] = 0;
/*
* Configure regions:
* r_index starts from 0 but is passed to region_init as r_index + 1,
* region 0 is not configurable
*/
for (r_index = 0; r_index < mpu_config.num_regions; r_index++) {
_region_init(r_index + 1,
mpu_config.mpu_regions[r_index].base,
mpu_config.mpu_regions[r_index].end,
mpu_config.mpu_regions[r_index].attr);
}
/* Enable MPU */
SYSMPU->CESR |= SYSMPU_CESR_VLD_MASK;
/* Make sure that all the registers are set before proceeding */
__DSB();
__ISB();
}
/*
* @brief MPU clock configuration
*
* This function provides the clock configuration for the Memory Protection
* Unit (MPU).
*/
static void _nxp_mpu_clock_cfg(void)
{
/* Enable Clock */
CLOCK_EnableClock(kCLOCK_Sysmpu0);
}
static int nxp_mpu_init(struct device *arg)
{
ARG_UNUSED(arg);
_nxp_mpu_clock_cfg();
_nxp_mpu_config();
return 0;
}
#if defined(CONFIG_SYS_LOG)
/* To have logging the driver needs to be initialized later */
SYS_INIT(nxp_mpu_init, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#else
SYS_INIT(nxp_mpu_init, PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif

View file

@ -64,6 +64,14 @@ config HAS_LPSCI
help help
Set if the low power uart (LPSCI) module is present in the SoC. Set if the low power uart (LPSCI) module is present in the SoC.
config HAS_SYSMPU
bool "Enable MPU"
depends on CPU_HAS_MPU
select NXP_MPU
default n
help
Enable MPU
if HAS_OSC if HAS_OSC
choice choice

View file

@ -12,5 +12,6 @@ config SOC_SERIES_KINETIS_K6X
select SOC_FAMILY_KINETIS select SOC_FAMILY_KINETIS
select SYS_POWER_LOW_POWER_STATE_SUPPORTED select SYS_POWER_LOW_POWER_STATE_SUPPORTED
select CPU_HAS_SYSTICK select CPU_HAS_SYSTICK
select CPU_HAS_MPU
help help
Enable support for Kinetis K6x MCU series Enable support for Kinetis K6x MCU series

View file

@ -1,2 +1,3 @@
obj-y += soc.o obj-y += soc.o
obj-y += wdog.o obj-y += wdog.o
obj-$(CONFIG_HAS_SYSMPU) += nxp_mpu_regions.o

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <soc.h>
#include <arch/arm/cortex_m/mpu/nxp_mpu.h>
#define FLEXBUS_BASE_ADDRESS 0x08000000
#define SRAM_L_BASE_ADDRESS 0x1FFF0000
#define DEVICE_S_BASE_ADDRESS 0x20030000
static struct nxp_mpu_region mpu_regions[] = {
/* Region 0 */
MPU_REGION_ENTRY("FLASH_0",
CONFIG_FLASH_BASE_ADDRESS,
0x07FFFFFF,
REGION_FLASH_ATTR),
/* Region 1 */
/*
* This region (Flexbus + FlexNVM) is bigger than the FLEXBUS one in
* order to save 1 region allocation in the MPU.
*/
MPU_REGION_ENTRY("FLEXBUS_0",
FLEXBUS_BASE_ADDRESS,
0x1BFFFFFF,
REGION_IO_ATTR),
/* Region 2 */
MPU_REGION_ENTRY("RAM_L_0",
SRAM_L_BASE_ADDRESS,
0x1FFFFFFF,
REGION_RAM_ATTR),
/* Region 3 */
MPU_REGION_ENTRY("RAM_U_0",
CONFIG_SRAM_BASE_ADDRESS,
(CONFIG_SRAM_BASE_ADDRESS +
(CONFIG_SRAM_SIZE * 1024) - 1),
REGION_RAM_ATTR),
/* Region 4 */
MPU_REGION_ENTRY("DEVICE_0",
DEVICE_S_BASE_ADDRESS,
0xFFFFFFFF,
REGION_IO_ATTR),
};
struct nxp_mpu_config mpu_config = {
.num_regions = ARRAY_SIZE(mpu_regions),
.mpu_regions = mpu_regions,
};

View file

@ -153,7 +153,9 @@ static int fsl_frdm_k64f_init(struct device *arg)
ARG_UNUSED(arg); ARG_UNUSED(arg);
int oldLevel; /* old interrupt lock level */ int oldLevel; /* old interrupt lock level */
#if !defined(CONFIG_HAS_SYSMPU)
u32_t temp_reg; u32_t temp_reg;
#endif /* !CONFIG_HAS_SYSMPU */
/* disable interrupts */ /* disable interrupts */
oldLevel = irq_lock(); oldLevel = irq_lock();
@ -161,6 +163,7 @@ static int fsl_frdm_k64f_init(struct device *arg)
/* release I/O power hold to allow normal run state */ /* release I/O power hold to allow normal run state */
PMC->REGSC |= PMC_REGSC_ACKISO_MASK; PMC->REGSC |= PMC_REGSC_ACKISO_MASK;
#if !defined(CONFIG_HAS_SYSMPU)
/* /*
* Disable memory protection and clear slave port errors. * Disable memory protection and clear slave port errors.
* Note that the K64F does not implement the optional ARMv7-M memory * Note that the K64F does not implement the optional ARMv7-M memory
@ -171,6 +174,7 @@ static int fsl_frdm_k64f_init(struct device *arg)
temp_reg &= ~SYSMPU_CESR_VLD_MASK; temp_reg &= ~SYSMPU_CESR_VLD_MASK;
temp_reg |= SYSMPU_CESR_SPERR_MASK; temp_reg |= SYSMPU_CESR_SPERR_MASK;
SYSMPU->CESR = temp_reg; SYSMPU->CESR = temp_reg;
#endif /* !CONFIG_HAS_SYSMPU */
_ClearFaults(); _ClearFaults();

View file

@ -9,3 +9,6 @@ CONFIG_CORTEX_M_SYSTICK=y
CONFIG_GPIO=y CONFIG_GPIO=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000
CONFIG_OSC_EXTERNAL=y CONFIG_OSC_EXTERNAL=y
# Enable MPU
CONFIG_HAS_SYSMPU=y

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _NXP_MPU_H_
#define _NXP_MPU_H_
#include <fsl_common.h>
#define NXP_MPU_BASE SYSMPU_BASE
#define NXP_MPU_REGION_NUMBER 12
/* Read Attribute */
#define MPU_REGION_READ ((1 << 2) | (1 << 8) | (1 << 14))
/* Write Attribute */
#define MPU_REGION_WRITE ((1 << 1) | (1 << 7) | (1 << 13))
/* Execute Attribute */
#define MPU_REGION_EXEC ((1 << 0) | (1 << 6) | (1 << 12))
/* Super User Attributes */
#define MPU_REGION_SU ((3 << 3) | (3 << 9) | (3 << 15) | (3 << 21))
/* 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)
/* Region definition data structure */
struct nxp_mpu_region {
/* Region Base Address */
u32_t base;
/* Region End Address */
u32_t end;
/* Region Name */
const char *name;
/* Region Attributes */
u32_t attr;
};
#define MPU_REGION_ENTRY(_name, _base, _end, _attr) \
{\
.name = _name, \
.base = _base, \
.end = _end, \
.attr = _attr, \
}
/* MPU configuration data structure */
struct nxp_mpu_config {
/* Number of regions */
u32_t num_regions;
/* Regions */
struct nxp_mpu_region *mpu_regions;
};
/* Reference to the MPU configuration */
extern struct nxp_mpu_config mpu_config;
#endif /* _NXP_MPU_H_ */