HAL库源码移植与使用之MPU(限于f7,h7系列)

内存保护单元(memory protection unit),简称:MPU。

MPU可以理解为一个内存管家,他可以把你的内存保护起来,也可以分配权限,限制你对内存空间的操作

它可以设置不同存储区域的存储器访问权限(特权级、用户级),设置存储器(内存和外设)属性(可缓存、可缓冲、可共享)

① 阻止用户应用程序破坏操作系统使用的数据

② 阻止一个任务访问其他任务的数据区,从而隔离任务

③ 把关键数据区域设置为只读,从根本上解决被破坏的可能

④ 检测意外的存储访问,如堆栈溢出、数组越界等

⑤ 将SRAM或RAM空间定义为不可执行,防止代码注入攻击

如果你对内存的操作超过权限就会进入中断MemManage去执行中断服务函数

CPU通过Cache这个高级缓存区就是mpu的具体机制 

 TEX若为0/1会进入不同的权限设置模式

 

 Cache(高级缓存)是提升STM32性能的关键一步。

M7内核芯片做了一级Cache支持,Cache分为数据缓存D-Cache和指令缓存I-Cache。

Cache支持4种基本操作:1,使能;2,禁止; 3,清空; 4,无效化

代码解析:

原理是定义一个在地址0x2002000的数组,然后把这个数组设成不准写入,再写入该数组进入中断MemManage去执行中断服务函数

main.c

#include "stdlib.h"
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/MPU/mpu.h"


#if !(__ARMCC_VERSION >= 6010050)   /* 不是AC6编译器,即使用AC5编译器时 */
uint8_t mpudata[128] __attribute__((at(0X20002000)));  /* 定义一个数组 */
#else
uint8_t mpudata[128] __attribute__((section(".bss.ARM.__at_0X20002000"))); /* 定义一个数组 */
#endif

int main(void)
{
    uint8_t key = 0;
    uint8_t t = 0; 
    
    sys_cache_enable();                 /* 打开L1-Cache */
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(240, 2, 2, 4); /* 设置时钟, 480Mhz */
    delay_init(480);                    /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    led_init();                         /* 初始化LED */
    key_init();                         /* 初始化按键 */
    printf("\r\n\r\nMPU closed!\r\n");  /* 提示MPU关闭 */
    mpu_memory_protection();
    
    while (1)
    {
        key = key_scan(0);

        if (key == WKUP_PRES)           /* 使能MPU保护数组 mpudata */
        {
            mpu_set_protection(0X20002000, MPU_REGION_SIZE_128B, MPU_REGION_NUMBER0, MPU_INSTRUCTION_ACCESS_ENABLE, MPU_REGION_PRIV_RO_URO,
                               MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_BUFFERABLE);  /* 只读,禁止共用,禁止cache,允许缓冲 */
            
            printf("MPU open!\r\n");    /* 提示MPU打开 */
        }
        else if (key == KEY0_PRES)      /* 向数组中写入数据,如果开启了MPU保护的话会进入内存访问错误! */
        {
            printf("Start Writing data...\r\n");
            sprintf((char *)mpudata, "MPU test array %d", t);
            printf("Data Write finshed!\r\n");
        }
        else if (key == KEY1_PRES)      /* 从数组中读取数据,不管有没有开启MPU保护都不会进入内存访问错误! */
        {
            printf("Array data is:%s\r\n", mpudata);
        }
        else 
        {
            delay_ms(10);
        }

        t++;

        if ((t % 50) == 0) 
        {
            LED0_TOGGLE();      /* LED0取反 */
        }
    }
}

mpu.c 

#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/MPU/mpu.h"


/**
 * @brief       设置某个区域的MPU保护
 * @param       baseaddr: MPU保护区域的基址(首地址)
 * @param       size:MPU保护区域的大小(必须是32的倍数,单位为字节)
 * @param       rnum:MPU保护区编号,范围:0~15,最大支持16个保护区域
 * @param       de:禁止指令访问;0,允许指令访问;1,禁止指令访问
 * @param       ap:访问权限,访问关系如下:
 *   @arg       0,无访问(特权&用户都不可访问)
 *   @arg       1,仅支持特权读写访问
 *   @arg       2,禁止用户写访问(特权可读写访问)
 *   @arg       3,全访问(特权&用户都可访问)
 *   @arg       4,无法预测(禁止设置为4!!!)
 *   @arg       5,仅支持特权读访问
 *   @arg       6,只读(特权&用户都不可以写)
 *   @note      详见:STM32H7编程手册.pdf,4.6.6节,Table 91.
 * @param       sen:是否允许共用;0,不允许;1,允许
 * @param       cen:是否允许cache;0,不允许;1,允许
 * @param       ben:是否允许缓冲;0,不允许;1,允许
 * @retval      0, 成功; 1, 错误;
 */
uint8_t mpu_set_protection(uint32_t baseaddr, uint32_t size, uint32_t rnum, uint8_t de, uint8_t ap, uint8_t sen, uint8_t cen, uint8_t ben)
{
    MPU_Region_InitTypeDef mpu_region_init_handle;           /* MPU初始化句柄 */
    HAL_MPU_Disable();                                       /* 配置MPU之前先关闭MPU,配置完成以后在使能MPU */

    mpu_region_init_handle.Enable = MPU_REGION_ENABLE;       /* 使能该保护区域 */
    mpu_region_init_handle.Number = rnum;                    /* 设置保护区域 */
    mpu_region_init_handle.BaseAddress = baseaddr;           /* 设置基址 */
    mpu_region_init_handle.Size = size;                      /* 设置保护区域大小 */
    mpu_region_init_handle.SubRegionDisable = 0X00;          /* 禁止子区域 */
    mpu_region_init_handle.TypeExtField = MPU_TEX_LEVEL0;    /* 设置类型扩展域为level0 */
    mpu_region_init_handle.AccessPermission = ap;            /* 设置访问权限 */
    mpu_region_init_handle.DisableExec = de;                 /* 是否允许指令访问 */
    mpu_region_init_handle.IsShareable = sen;                /* 是否允许共用 */
    mpu_region_init_handle.IsCacheable = cen;                /* 是否允许cache */
    mpu_region_init_handle.IsBufferable = ben;               /* 是否允许缓冲 */
    HAL_MPU_ConfigRegion(&mpu_region_init_handle);           /* 配置MPU */
    
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);                  /* 开启MPU */
    return 0;
}

/**
 * @brief       设置需要保护的存储块
 * @note        必须对部分存储区域进行MPU保护,否则可能导致程序运行异常
 *              比如MCU屏不显示,摄像头采集数据出错等等问题
 * @param       无
 * @retval      无
 */
void mpu_memory_protection(void)
{
    /* 保护整个DTCM,共128K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */
    mpu_set_protection(0x20000000, MPU_REGION_SIZE_128KB, MPU_REGION_NUMBER1, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);

    /* 保护整个AXI SRAM,共512K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */
    mpu_set_protection(0x24000000, MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER2, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);

    /* 保护整个SRAM1~SRAM3,共288K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */
    mpu_set_protection(0x30000000, MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER3, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);

    /* 保护整个SRAM4,共64K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */
    mpu_set_protection(0x38000000, MPU_REGION_SIZE_64KB, MPU_REGION_NUMBER4, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);

    /* 保护MCU LCD屏所在的FMC区域,,共64M字节,允许指令访问,禁止共用,禁止cache,禁止缓冲 */
    mpu_set_protection(0x60000000, MPU_REGION_SIZE_64MB, MPU_REGION_NUMBER5, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_NOT_BUFFERABLE);

    /* 保护SDRAM区域,共64M字节,允许指令访问,禁止共用,允许cache,允许缓冲 */
    mpu_set_protection(0XC0000000, MPU_REGION_SIZE_64MB, MPU_REGION_NUMBER6, MPU_INSTRUCTION_ACCESS_ENABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);

    /* 保护整个NAND FLASH区域,共256M字节,禁止指令访问,禁止共用,禁止cache,禁止缓冲 */
    mpu_set_protection(0X80000000, MPU_REGION_SIZE_256MB, MPU_REGION_NUMBER7, MPU_INSTRUCTION_ACCESS_DISABLE,
                       MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_NOT_BUFFERABLE);
}

/**
 * @brief       MemManage错误处理中断
 *   @note      进入此中断以后,将无法恢复程序运行!!
 *
 * @param       无
 * @retval      无
 */
void MemManage_Handler(void)
{
    LED1(0);                            /* 点亮LED1(GREEN LED) */
    printf("Mem Access Error!!\r\n");   /* 输出错误信息 */
    delay_ms(1000);
    printf("Soft Reseting...\r\n");     /* 提示软件重启 */
    delay_ms(1000);
    NVIC_SystemReset();                 /* 软复位 */
}



  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广药门徒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值