ARM Cortex-M4 : MPU and unprivileged switching

46 views Asked by At

I am trying to use the MPU in an ARM Cortex-M4 device. The device was running without MPU and was in privileged mode. When I enable the MPU and try to switch to unprivileged mode there is a hard fault and MUNSTEKERR bis is set. I am not sure why this happened and how to solve this...

Here is my function to enable MPU:

#define MPU_RBAR_ADDR_Pos                   5U                                            /*!< MPU RBAR: ADDR Position */
#define MPU_RBAR_ADDR_Msk                  (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos)             /*!< MPU RBAR: ADDR Mask */
#define MPU_RBAR_VALID_Pos                  4U                                            /*!< MPU RBAR: VALID Position */
#define MPU_RBAR_VALID_Msk                 (1UL << MPU_RBAR_VALID_Pos)                    /*!< MPU RBAR: VALID Mask */
#define MPU_RBAR_REGION_Pos                 0U                                            /*!< MPU RBAR: REGION Position */
#define MPU_RBAR_REGION_Msk                (0xFUL /*<< MPU_RBAR_REGION_Pos*/)             /*!< MPU RBAR: REGION Mask */

#define MPU_AP_NOACCESS     0x0
#define MPU_AP_PRIVONLY     0x1
#define MPU_AP_USERREADONLY 0x2
#define MPU_AP_FULLACCESS   0x3
#define MPU_AP_READONLY     0x6
#define MPU_RASR_AP_NOACCESS     (MPU_AP_NOACCESS      << MPU_RASR_AP_Pos)              
#define MPU_RASR_AP_PRIVONLY     (MPU_AP_PRIVONLY      << MPU_RASR_AP_Pos)
#define MPU_RASR_AP_USERREADONLY (MPU_AP_USERREADONLY  << MPU_RASR_AP_Pos)
#define MPU_RASR_AP_FULLACCESS   (MPU_AP_FULLACCESS    << MPU_RASR_AP_Pos)
#define MPU_RASR_AP_READONLY     (MPU_AP_READONLY      << MPU_RASR_AP_Pos)

#define MPU_RASR_XN_Pos                    28U                                            /*!< MPU RASR: ATTRS.XN Position */
#define MPU_RASR_XN_Msk                    (1UL << MPU_RASR_XN_Pos)                       /*!< MPU RASR: ATTRS.XN Mask */
#define MPU_RASR_AP_Pos                    24U                                            /*!< MPU RASR: ATTRS.AP Position */
#define MPU_RASR_AP_Msk                    (0x7UL << MPU_RASR_AP_Pos)                     /*!< MPU RASR: ATTRS.AP Mask */
#define MPU_RASR_TEX_Pos                   19U                                            /*!< MPU RASR: ATTRS.TEX Position */
#define MPU_RASR_TEX_Msk                   (0x7UL << MPU_RASR_TEX_Pos)                    /*!< MPU RASR: ATTRS.TEX Mask */
#define MPU_RASR_S_Pos                     18U                                            /*!< MPU RASR: ATTRS.S Position */
#define MPU_RASR_S_Msk                     (1UL << MPU_RASR_S_Pos)                        /*!< MPU RASR: ATTRS.S Mask */
#define MPU_RASR_C_Pos                     17U                                            /*!< MPU RASR: ATTRS.C Position */
#define MPU_RASR_C_Msk                     (1UL << MPU_RASR_C_Pos)                        /*!< MPU RASR: ATTRS.C Mask */
#define MPU_RASR_B_Pos                     16U                                            /*!< MPU RASR: ATTRS.B Position */
#define MPU_RASR_B_Msk                     (1UL << MPU_RASR_B_Pos)                        /*!< MPU RASR: ATTRS.B Mask */
#define MPU_RASR_SRD_Pos                    8U                                            /*!< MPU RASR: Sub-Region Disable Position */
#define MPU_RASR_SRD_Msk                   (0xFFUL << MPU_RASR_SRD_Pos)                   /*!< MPU RASR: Sub-Region Disable Mask */

#define MPU_SIZE_64BYTES  0x05
#define MPU_RASR_SIZE_64BYTES  (MPU_SIZE_64BYTES  << MPU_RASR_SIZE_Pos)

#define MPU_RASR_ENABLE_TRUE  0x1
#define MPU_RASR_ENABLE_FALSE 0x0

#define MPU_CTRL_PRIVDEFENA_Pos             2U                                            /*!< MPU CTRL: PRIVDEFENA Position */
#define MPU_CTRL_PRIVDEFENA_Msk            (1UL << MPU_CTRL_PRIVDEFENA_Pos)               /*!< MPU CTRL: PRIVDEFENA Mask */
#define MPU_CTRL_ENABLE_Pos                 0U                                            /*!< MPU CTRL: ENABLE Position */
#define MPU_CTRL_ENABLE_Msk                (1UL /*<< MPU_CTRL_ENABLE_Pos*/)               /*!< MPU CTRL: ENABLE Mask */

void MPU_Registers_Init(uint32_t addr)
{
    MPU_Type *MpuReg = MPU;
    uint32_t base_addr = addr;     
    uint32_t region_number = 0x0;               // from 0~7 8 region available
   
    MPU->RBAR |= base_addr & MPU_RBAR_ADDR_Msk;
    MPU->RBAR |= ( 0x0u << MPU_RBAR_VALID_Pos) & MPU_RBAR_VALID_Msk;
    MPU->RBAR |= ( region_number << MPU_RBAR_REGION_Pos) & MPU_RBAR_REGION_Msk;

    uint32_t xn = 0x1u;                         // instruction fetches disabled  
    
    uint32_t tex = 0x000u;                      
    uint32_t c = 0x1u;                                                          
    uint32_t b = 0x0u;                          // no write-back
    uint32_t s = 0x1u;                          // shareable
    
    uint32_t srd = 0xFF;                        // disable Subregion
    
    MPU->RASR |= (xn << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk;
    
    MPU->RASR |= MPU_RASR_AP_USERREADONLY;              //p:RW up:RO    
    
    MPU->RASR |= (tex << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk;
    MPU->RASR |= (s << MPU_RASR_S_Pos) & MPU_RASR_S_Msk;
    MPU->RASR |= (c << MPU_RASR_C_Pos) & MPU_RASR_C_Msk;
    MPU->RASR |= (b << MPU_RASR_B_Pos) & MPU_RASR_B_Msk;
    MPU->RASR |= (srd << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk;
    
    MPU->RASR |= MPU_RASR_SIZE_64BYTES;
    MPU->RASR |= MPU_RASR_ENABLE_TRUE;
    
    MPU->CTRL |=  (0x01u << MPU_CTRL_PRIVDEFENA_Pos) & MPU_CTRL_PRIVDEFENA_Msk; 
    MPU->CTRL |=  (0x01u << MPU_CTRL_ENABLE_Pos) & MPU_CTRL_ENABLE_Msk;
}

and this is how I try to switch to unprivileged mode:

        uint32_t RegControl = __get_CONTROL();              
        __set_CONTROL( RegControl | CONTROL_nPRIV_Msk );

After the "__set_CONTROL" I get a hard fault and the CFSR shows MUNSTKERR and IACCVIOL:enter image description here

The address 0x20001900 is in RAM, in a big static uint8 array.

According to my test, the MPU it self works fine in privileged mode, and the privileged switching works find without MPU, but combining them together will cause some issue.

By the way, I also tried to switch to unprivileged mode first, then enable the MPU by svc call. And I got a similar issue, the difference is IACCVIOL is gone.enter image description here

0

There are 0 answers