This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM2634: ARM MPU example how to setup

Part Number: AM2634

Hi,

I'm trying to find an example for how to setup and use MPU. The SDK documentation gives the details of how to setup a MPU region, but how do I setup privilege's for accessing functions. Can you provide a simple example code where there is a global variable at a specific MPU protected region and 3 functions where one function has read/write access, one function has only read access and one function has no read and write access.

Regards,

Harsha

  • Hi Harsha,

    Please find the file -

    /*
     *  Copyright (C) 2018-2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    
    #include <stdio.h>
    #include <kernel/dpl/DebugP.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    MpuP_RegionConfig temp_function = {
        .baseAddr = 0x70080000,
        .size = MpuP_RegionSize_1K,
        .attrs.isEnable = 1,
        .attrs.isCacheable = 1,
        .attrs.isBufferable = 0,
        .attrs.isSharable = 1,
        .attrs.isExecuteNever = 1,
        .attrs.tex = 0,
        .attrs.accessPerm = 0,
        .attrs.subregionDisableMask = 0
    };
    
    uint8_t variable_function[1024] __attribute__((section(".data.test_function"))) = {0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    
    extern void MpuP_setRegionAsm(uint32_t regionId, uint32_t regionBaseAddr,
                  uint32_t sizeAndEnble, uint32_t regionAttrs);
    
    void MpuP_setRegionLocalFunction(uint32_t regionNum, void * addr, uint32_t size, MpuP_RegionAttrs *attrs)
    
    {
        uint32_t baseAddress, sizeAndEnable;
        uintptr_t key;
        uint32_t value = size;
    
        DebugP_assertNoLog( regionNum < 16U);
    
        /* size 5b field */
        value = (value & (uint32_t)0x1F);
    
        /* If N is the value in size field, the region size is 2N+1 bytes. */
        sizeAndEnable = ((uint32_t)(attrs->subregionDisableMask & (uint32_t)0xFF) << (uint32_t)8)
                      | ((uint32_t)(value            & (uint32_t)0x1F) << (uint32_t)1)
                      | ((uint32_t)(attrs->isEnable &  (uint32_t)0x1) << (uint32_t)0);
    
        /* align base address to region size */
        baseAddress = ((uint32_t)addr & ~( (1U <<((uint64_t)value+1U))-1U ));
    
        /* get region attribute mask */
        uint32_t regionAttrs =
              ((uint32_t)(attrs->isExecuteNever & (uint32_t)0x1) << (uint32_t)12)
            | ((uint32_t)(attrs->accessPerm     & (uint32_t)0x7) << (uint32_t)8)
            | ((uint32_t)(attrs->tex            & (uint32_t)0x7) << (uint32_t)3)
            | ((uint32_t)(attrs->isSharable     & (uint32_t)0x1) << (uint32_t)2)
            | ((uint32_t)(attrs->isCacheable    & (uint32_t)0x1) << (uint32_t)1)
            | ((uint32_t)(attrs->isBufferable   & (uint32_t)0x1) << (uint32_t)0);
    
        key = HwiP_disable();
    
        MpuP_setRegionAsm(regionNum, baseAddress, sizeAndEnable, regionAttrs);
    
        HwiP_restore(key);
    }
    
    void function_a(void)
    {
        /* Disable MPU */
        temp_function.attrs.isEnable = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
        /* Change the Access Permission */
        temp_function.attrs.accessPerm = 3;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
        /* Enable MPU */
        temp_function.attrs.isEnable = 1;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        DebugP_log("Function A\r\n");
        /* Testing the Read Access */
        DebugP_log("Variable Function Data %x\r\n", variable_function[0]);
        /* Testing the Write Access */
        variable_function[0] = 0xFF;
        /* Testing the Read Access again to prevent optimization */
        DebugP_log("Variable Function Data %x\r\n", variable_function[0]);
    
        /* Disable MPU */
        temp_function.attrs.isEnable = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Revert the Access Permission */
        temp_function.attrs.accessPerm = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Enable MPU */
        temp_function.attrs.isEnable = 1;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    }
    
    void function_b(void)
    {
        /* Disable MPU */
        temp_function.attrs.isEnable = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Revert the Access Permission */
        temp_function.attrs.accessPerm = 6;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Enable MPU */
        temp_function.attrs.isEnable = 1;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        DebugP_log("Function B\r\n");
        DebugP_log("Variable Function Data %x\r\n", variable_function[0]);
        /* Writing will lead to abort, so commented */
        //variable_function[0] = 0xAA;
    
        /* Disable MPU */
        temp_function.attrs.isEnable = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Revert the Access Permission */
        temp_function.attrs.accessPerm = 0;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    
        /* Enable MPU */
        temp_function.attrs.isEnable = 1;
        MpuP_setRegionLocalFunction(4, (void *)temp_function.baseAddr, temp_function.size, (MpuP_RegionAttrs *)&temp_function.attrs.isEnable);
    }
    
    void function_c(void)
    {
        DebugP_log("Function C\r\n");
        /* Reading will lead to abort, so commented */
        //DebugP_log("Variable Function Data %x\r\n", variable_function[0]);
        /* Writing will lead to abort, so commented */
        //variable_function[0] = 0xCC;
    }
    
    void hello_world_main(void *args)
    {
        /* Open drivers to open the UART driver for console */
        Drivers_open();
        Board_driversOpen();
        //DebugP_log("Hello World!\r\n");
    
        /* A Function which can read and write the variable */
        function_a();
    
        /* A Function which can read the variable */
        function_b();
    
        /* A Function which cannot access the variable */
        function_c();
    
        Board_driversClose();
        Drivers_close();
    }
    
    

    The MPU settings for the same are also mentioned here -

    Hope it helps.

    Best Regards,
    Aakash

  • Hi Aakash,

    Thank you very much for your immediate response and sorry for my delayed reply. From your example code I understand how to setup and use the MPU's. I just have one question: 

    Please let me know if my understanding is right?

    When accessing a protected region every time I have to do the following:

    1. Disable MPU

    2. Change the Access Permission (to get access)

    3. Enable MPU 

    And right after accessing I should again:

    1. Disable MPU

    2. Change the Access Permission (revert the access)

    3. Enable MPU 

    Is this how I should generally work with MPU's also is it necessary to perform the 2nd part i.e. revert the access? What happens if I do not revert the access?

    Your help is very much appreciated.

    Regards,

    Harsha

  • Hi Aakash,

    I tried the above example but it seems to fail. Please let me know what I have been doing wrong here.

    /*
     *  Copyright (C) 2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdio.h>
    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/MpuP_armv7.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    
    /*
     * This is an empty project provided for all cores present in the device.
     * User can use this project to start their application by adding more SysConfig modules.
     *
     * This application does driver and board init and just prints the pass string on the console.
     * In case of the main core, the print is redirected to the UART console.
     * For all other cores, CCS prints are used.
     */
    MpuP_RegionConfig localMpuRegionConfig = {
                                          .baseAddr = 0x70080000,
                                          .size = MpuP_RegionSize_1K,
                                          .attrs = {
                                              .isEnable = 1,
                                              .isCacheable = 1,
                                              .isBufferable = 0,
                                              .isSharable = 1,
                                              .isExecuteNever = 1,
                                              .tex = 0,
                                              .accessPerm = MpuP_AP_ALL_BLOCK,
                                              .subregionDisableMask = 0x0u
                                          },
                                        };
    
    uint8_t secure_variable[1024] __attribute__((section(".data.secure_variable"))) = {0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    
    void access_permission_set(uint16_t perm)
    {
        /* Disable MPU */
        localMpuRegionConfig.attrs.isEnable = 0;
        localMpuRegionConfig.attrs.isCacheable = 0;
        MpuP_setRegion(6, (void *)localMpuRegionConfig.baseAddr, localMpuRegionConfig.size, (MpuP_RegionAttrs *)&localMpuRegionConfig.attrs);
        /* Change the Access Permission */
        localMpuRegionConfig.attrs.accessPerm = (uint8_t)perm;
        MpuP_setRegion(6, (void *)localMpuRegionConfig.baseAddr, localMpuRegionConfig.size, (MpuP_RegionAttrs *)&localMpuRegionConfig.attrs);
        /* Enable MPU */
        localMpuRegionConfig.attrs.isEnable = 1;
        localMpuRegionConfig.attrs.isCacheable = 1;
        MpuP_setRegion(6, (void *)localMpuRegionConfig.baseAddr, localMpuRegionConfig.size, (MpuP_RegionAttrs *)&localMpuRegionConfig.attrs);
    }
    
    void function_a(void)
    {
        access_permission_set(MpuP_AP_ALL_RW);
    
        DebugP_log("Function A\r\n");
        /* Testing the Read Access */
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
        /* Testing the Write Access */
        secure_variable[0] = 0xFF;
        /* Testing the Read Access again to prevent optimization */
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
    
        access_permission_set(MpuP_AP_ALL_BLOCK);
    }
    
    void function_b(void)
    {
        access_permission_set(MpuP_AP_ALL_R);
    
        DebugP_log("Function B\r\n");
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
        /* Writing will lead to abort, so commented */
        secure_variable[0] = 0xAA;
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
    
        access_permission_set(MpuP_AP_ALL_BLOCK);
    }
    
    void function_c(void)
    {
        DebugP_log("Function C\r\n");
        /* Reading will lead to abort, so commented */
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
        /* Writing will lead to abort, so commented */
        secure_variable[0] = 0xCC;
        DebugP_log("Variable Function Data %x\r\n", secure_variable[0]);
    }
    
    
    void empty_main(void *args)
    {
        /* Open drivers to open the UART driver for console */
        Drivers_open();
        Board_driversOpen();
    
        function_a();
        function_b();
        function_c();
    
        DebugP_log("All tests have passed!!\r\n");
    
        while(1)
        {
    
        }
    
        Board_driversClose();
        Drivers_close();
    }
    

    MPU config in syscfg

    Output on uart terminal:

    Function b and c should have triggered an abort but neither does.

    Further  

    Regards,

    Harsha

  • Hi ,

    Can you share your map file ? Is your .data.secure_variable aligned to 1K memory ? MPU only aligns the memory to the size of the region so the .data.secure_variable should be at 0x70080000.

    If the above one is okay then, can you read out the CPR15 registers in the debugger to share more information ? Also please do this experiment after each access_permission_set call done in Function B/C ?

    Best Regards,
    Aakash

  • Hi Aakash,

    Thank you, I had forgotten to change the name of the section in the code where I'm assigning the secure_variable.

    Now the example works.

    Thank you for your support.

    Regards,

    Harsha