MPU Memory Protection Unit

The Cortex-M Processor Modes

Thread mode
Used to execute application software. The processor enters Thread mode when it comes out of reset.

Handler mode
Used to handle exceptions. The processor returns to Thread mode when it has finished all exception processing.

The Cortex-M Privilege Levels

Unprivileged:
Unprivileged code execution limits or excludes access to some resources like certain instructions and specific memory locations

Privileged:
The software can use all the instructions and has access to all resources.

Privileges and Modes (cont.):
The MPU allows us to change the region of memory that can be accessed based on the operating mode and the privilege level.

image.png

Privileges and Modes

Thread Mode:
In Thread mode, the CONTROL register controls whether software execution is privileged or unprivileged

Handler Mode:
In Handler mode, software execution is always privileged

image.png

image.png

image.png

#define MPU_TYPE_REG        (*(volatile uint32_t *)0xE000ED90)
#define START_OF_DREGION    8

uint8_t num_of_regions;

int main()
{
    /*Initialize debug UART*/
    debug_uart_init();

    num_of_regions = MPU_TYPE_REG >> START_OF_DREGION;

    printf("Number of regions : %d\n\r", num_of_regions);
}

image.png

image.png

image.png

image.png

image.png

#define MPU_RBASE_ADDR_REG  (*(volatile uint32_t *)0xE000ED9C)

uint32_t min_region_sz;

int main()
{

    /*Set bits 4 to 32 to 1 in the MPU_RBASE_ADDR_REG
     * and then read the MPU_RBASE_ADDR_REG. If the bits remain set then the
     * minimum possible region size of 32bytes is supported */

    MPU_RBASE_ADDR_REG = 0xFFFFFFE0;      // 0b 1111 1111......1110 0000

    min_region_sz = MPU_RBASE_ADDR_REG;

    while (1)
    {
    }
}

image.png

Memory Attributes and Access Permissions

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

_A1 , _A2 and _A3

_A1 , _A2 and _A3

the MemManageFault Registers

image.png

image.png

Catching Stack Overflow using the MPU

image.png

we changed the end of stack in the linker file

we changed the end of stack in the linker file

#include <stdint.h>

/* System control registers */
#define SHCSR_REG              (*(volatile uint32_t *)0xE000ED24)
#define MPU_CTRL_REG           (*(volatile uint32_t *)0xE000ED94)
#define MPU_RAS_REG            (*(volatile uint32_t *)0xE000EDA0)
#define MPU_RBASE_ADDR_REG     (*(volatile uint32_t *)0xE000ED9C)
#define MPU_TYPE_REG           (*(volatile uint32_t *)0xE000ED90)

#define START_OF_DREGION       8
#define MEMFAULTENA            (1U<<16)

uint8_t  num_of_regions;
uint32_t min_region_sz;

#define SIZE_TO_CONFIG         32

/* The maximum stack we have defined in the linker script */
#define MAX_STACK              128

uint32_t factorial(uint32_t n)
{
    if(n == 0 || n == 1)
    {
        return 1;
    }
    else{
        return n * factorial(n - 1);
    }
}

int main()
{
    /*Enable FPU*/
    fpu_enable();

    /*Initialize debug UART*/
    debug_uart_init();

    /*Enable MemFault Handler*/
    SHCSR_REG |= MEMFAULTENA;

    /*Check number of regions*/
    num_of_regions = MPU_TYPE_REG >> START_OF_DREGION;

    /*Check minimum region size*/
    /*Set bits 4 to 32 to 1 in the MPU_RBASE_ADDR_REG
     * and then read the MPU_RBASE_ADDR_REG. If the bits remain set then the
     * minimum possible region size of 32bytes is supported */
    MPU_RBASE_ADDR_REG = 0xFFFFFFF0;   // 0B 1111 1111.....1110 0000
    min_region_sz = MPU_RBASE_ADDR_REG;

    /*Compute final base addr of region to config*/
    const uint32_t base_addr = ((uint32_t)0x20000000 + MAX_STACK );

    /*Config MPU_RBASE_ADDR_REG*/
    /*Set Address, VALID bit, and Region number to 0*/
	  MPU_RBASE_ADDR_REG = (base_addr | 1 << 4 | 0);

    /*Config MPU_RAS_REG*/
    MPU_RAS_REG = (0b000 << 24) | (0b000110 << 16) | (4 << 1) | 0x1;

    /*Config MPU_CTRL_REG*/
    MPU_CTRL_REG = (1U<<2) | (1U<<0);

    uint32_t fact_result;

    while(1)
    {
        fact_result = factorial(5);
    }
}

void HardFault_Handler(void)
{
    printf("HARDFAULT \n\r");
}

void MemManage_Handler(void)
{
    printf("MEMFAULT \n\r");
}