Memory Protection Unit (MPU)

IC:

Introduction

The Memory Protection Unit (MPU) is a component provided by Arm Cortex-M series MCU and is used to provide hardware protection by software definition. The number of MPU entries varies for each CPU, as shown in the table below:

CPU

MPU entry count

KM0

4

KM4

  • Secure World: 4

  • Non-secure World: 8

MPU APIs

The SDK provides the mpu_region_config struct to set the region memory attribute of MPU. The following table lists the member variables of the mpu_region_config struct.

Member variable name

Type

Description

region_base

uint32_t

MPU region base address, 32 bytes aligned

region_size

uint32_t

MPU region size, 32 bytes aligned

xn

uint8_t

Execute Never attribute

  • MPU_EXEC_ALLOW: Allows program execution in this region

  • MPU_EXEC_NEVER: Does not allow program execution in this region

ap

uint8_t

Access permissions

  • MPU_PRIV_RW: Read/write by privileged code only

  • MPU_UN_PRIV_RW: Read/write by any privilege level

  • MPU_PRIV_RO: Read only by privileged code only

  • MPU_UN_PRIV_RO: Read only by any privilege level

sh

uint8_t

Shareability of Normal memory

  • MPU_NON_SHAREABLE: Non-shareable

  • MPU_OUT_SHAREABLE: Outer shareable

  • MPU_INR_SHAREABLE: Inner shareable

attr_idx

uint8_t

Memory attribute indirect index

This parameter can be a value of 0 ~ 7, with detailed attributes defined in mpu_init() and customizable. The typical definition is as follows:

  • 0: MPU_MEM_ATTR_IDX_NC, defines memory attribute of Normal memory as non-cacheable.

  • 1: MPU_MEM_ATTR_IDX_WT_T_RA, defines memory attribute of Normal memory as write-through transient, read allocation.

  • 2: MPU_MEM_ATTR_IDX_WB_T_RWA, defines memory attribute of Normal memory as write-back transient, read and write allocation.

  • 3 ~ 7: MPU_MEM_ATTR_IDX_DEVICE, defines memory attribute of Device memory as non-gathering, non-reordering, non-early Write Acknowledge.

mpu_init

void mpu_init(void)

Initialize MPU region memory attribute to typical value

  • Parameters: None

  • Return value: None

mpu_set_mem_attr

void mpu_set_mem_attr(uint8_t attr_idx, uint8_t mem_attr)

Change MPU region memory attribute

  • Parameters:

    • attr_idx: Memory attribute indirect index, which can be 0 ~ 7.

    • mem_attr: region memory attributes, customizable as well.

  • Return value: None

mpu_region_cfg

void mpu_region_cfg(uint8_t region_num, mpu_region_config *pmpu_cfg)

Configure MPU region memory attributes based on the given parameters.

  • Parameters:

    • region_num: MPU entry idx

    • pmpu_cfg: point to the mpu_region_config struct which has been configured

  • Return value: None

mpu_entry_free

void mpu_entry_free(u32 entry_index)

Release the software tag corresponding to the MPU entry, at which point the MPU entry will be marked as available.

  • Parameters:

    • entry_index: MPU entry idx

  • Return value: None

mpu_entry_alloc

char mpu_entry_alloc(void)

Allocate a free MPU entry.

  • Parameters: None

  • Return value: MPU entry idx, Return -1 if allocation fails.

Usage

During system boot, in the app_start() function of ameba_app_start.c, the mpu_init() function is called to initialize the MPU. Once the MPU initialization is complete, the app_mpu_nocache_init() function configures the non-cacheable data buffer based on the predefined non-cacheable data buffer .

Note

Neither the I-Cache nor the D-Cache will cache the addresses in the MCU’s internal ROM.

During execution, if the code or data is mistakenly accessed, and the MPU region’s read-only attribute is to be used to assist in analysis, the MPU region can be set up by following these steps:

  1. Define new variable and struct

    • Define a variable char mpu_entry; to store MPU entry index;

    • Define a struct mpu_region_config mpu_cfg; to store the region memory attribute

  2. Call mpu_entry = mpu_entry_alloc(); to allocate a free MPU entry, where -1 indicates allocation failure.

  3. Set the struct for region’s memory attribute

    mpu_cfg.region_base = start_addr; // The starting address to protect, aligned to 32 bytes.
    mpu_cfg.region_size = size_bytes; // The size to protect, aligned to 32 bytes.
    mpu_cfg.xn = MPU_EXEC_ALLOW;
    mpu_cfg.ap = MPU_UN_PRIV_RO; // The read-only attribute can help prevent accidental access.
    mpu_cfg.sh = MPU_NON_SHAREABLE;
    mpu_cfg.attr_idx = MPU_MEM_ATTR_IDX_WT_T_RA;
    
  4. Call mpu_region_cfg(mpu_entry, &mpu_cfg); to configure MPU region memory attribute.