查看: 4623|回复: 0

[分享] [痞子衡]Cortex-M内核存储保护单元MPU

[复制链接]
  • TA的每日心情
    开心
    7 天前
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3868

    主题

    7472

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39223
    最后登录
    2025-7-18
    发表于 2021-8-11 17:10:42 | 显示全部楼层 |阅读模式
    Cortex-M内核存储保护单元MPU


    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是ARM Cortex-M存储保护模块(MPU)。


    《ARM Cortex-M内核MCU开发那些事》的内核篇连载最早是 2017 年底开始写的,但只写了 7 篇就停更了,鸽了这么久实在不好意思。最近在支持 i.MXRT 客户的过程中,发现客户对 Cortex-M 的 MPU 功能不太了解,导致项目中出了内存非法访问的问题,借此机会,痞子衡将重启这个 Cortex-M 内核篇连载,为大家系统地讲解下MPU:


    备注:本篇是MPU上篇,主要讲述PMSAv6/7架构下的Cortex-M处理器MPU设计,适用Cortex-M0+/M3/M4/M7。


    一、MPU是什么?
    MPU 全称"Memory Protection Unit",中文叫“存储保护单元”,它是 Cortex-M 处理器内部的一个模块(注意:并不是所有 Cortex-M 版本都支持 MPU,并且在一些支持 MPU 的 Cortex-M 版本上,MPU 也是可选组件(要看具体MCU厂商是否实现))。


    让我们结合如下 Cortex-M 处理器(以 CM0+ 为例,其他版本类似)模块框图中来解释 MPU 作用,从框图中大家可以看到,MPU 介于 Core 和 Bus matrix 中间。Bus matirx 是 ARM 系统总线大管家,用以实现系统内多主(Core,DMA等)、多从(内部RAM,APB外设,外部总线等)的交联和仲裁,Core 通过 Bus matirx 可以访问到系统空间内的所有存储/外设资源,现在 MPU 挡在了 Core 和 Bus matirx 中间,这意味着从此 Core 对系统存储资源的访问需要经过 MPU 的权限控制与审核。
    11.png
    二、存储空间类型与属性
    MPU 对存储空间的访问权限控制主要包含:Strongly-ordered(是否严格有序)、Shareable(是否共享)、Cacheable(是否缓存)、Execute Never(是否可执行)等方面,不同的访问权限配置造就了系统里不同的存储空间类型与属性,这一切都是为了能够让存储资源被 Core 高效且可靠地访问(RTOS环境下比裸机程序下更需要可靠保证)。
    12.png
    Shareable/Cacheable/Execute Never 属性大家应该都了解,有必要特别提一下 Strongly-ordered 属性,因为不同属性的存储空间配置会给代码执行时内存访问指令的顺序方面造成了困扰,比如两个内存访问指令A1, A2,假定它们是同一主设备接口发出的,并且 A1 在程序代码里出现在 A2 之前,根据 A1/A2 不同的属性组合其实际执行结果如下,有些时候系统无法保证 A1 操作一定比 A2 操作先完成,这时候需要软件设计里手工插入内存屏障指令(ISB, DSB)来保证最终顺序。

    如果 MPU 模块不存在或者没有被使能,处理器系统 4GB 存储空间默认的属性如下(表中 XN 即 Execute Never;WT 即 Write-Throug;WBWA 即 Write-Back, write allocate):
    13.png
    14.png
    三、MPU功能配置
    MPU 模块是处理器内核自带的模块,其寄存器定义见 \CMSIS\Include\core_cm0plus/3/4/7.h 文件,具体寄存器功能解释这里就不展开了,可翻阅对应 ARMv6/7-M Architecture RM 或者 Cortex-M0+/3/4/7 Generic UG 手册找到具体解释。


    简单概括一下,MPU 最多支持 8/16 个主空间划分(MPU_RNR[REGION],REGION取值 0-7 或者 0-15),每个主空间可以自由设置其属性(MPU_RASR[XN/AP/TEX/S/C/B]),空间大小是可设的,最小粒度为 32bytes,空间之间也可以重叠(高序号空间属性会覆盖低序号空间属性)。当某个主空间分配的大小超过 256 bytes 时,这个主空间还可以被等分成 8 个子空间,每个子空间有独立的开关控制(MPU_RASR[SRD])。


    15.png
    MPU 模块最核心的寄存器是 MPU_RASR,其提供了存储空间具体访问权限配置,XN/AP/TEX/S/C/B 位域共同决定了最终权限,用户可根据项目实际需求进行配置。
    17.png
    上表中关于 Cache 策略的设置 AA/BB 定义如下:
        00 Non-cacheable
        01 Write-back, write and read allocate
        10 Write-through, no write allocate
        11 Write-back, no write allocate
    18.png
    四、MPU配置代码示例
    ARM 官方为 MPU 模块预实现了一些功能函数/宏定义,见 \CMSIS\Include\mpu_armv6/7.h 文件,其中最常用的是 ARM_MPU_RBAR 和 ARM_MPU_RASR 宏。


    如下是恩智浦 i.MXRT1170 的 MPU 示例配置代码,这是颗 Cortex-M7 内核的 MCU,内部有 2MB RAM,官方 MIMXRT1170-EVK 板卡为其外挂了 16MB 的 NOR Flash 和 64MB 的 SDRAM。


    代码中 Region2/3/4/5/6/8/9 是实际用户存储空间的配置,其他 Region0/1/7 是基本系统空间的配置,未定义空间的非法访问会产生 MemManage 或者 BusFault。
    1. void BOARD_ConfigMPU(void)
    2. {
    3.     /* Disable I cache and D cache */
    4.     SCB_DisableICache();
    5.     SCB_DisableDCache();

    6.     /* Disable MPU */
    7.     ARM_MPU_Disable();

    8.     //////////////////////////////////////////////////////////////////////////////////////
    9.     // 系统全部 4GB 空间先配置成 XN 属性的 Device
    10.     /* Region 0 setting: Instruction access disabled, No data access permission. */
    11.     MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U);
    12.     MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB);
    13.     //////////////////////////////////////////////////////////////////////////////////////
    14.     // 0x00000000 之后的1GB 空间配置成非 XN 属性的 Device
    15.     /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */
    16.     MPU->RBAR = ARM_MPU_RBAR(1, 0x00000000U);
    17.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB);

    18.     //////////////////////////////////////////////////////////////////////////////////////
    19.     // 0x00000000 之后的内部 RAM 空间配置(实际 2MB)
    20.     /* Region 2 setting: Memory with Normal type, not shareable, outer/inner write back */
    21.     MPU->RBAR = ARM_MPU_RBAR(2, 0x00000000U);
    22.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
    23.     /* Region 3 setting: Memory with Normal type, not shareable, outer/inner write back */
    24.     MPU->RBAR = ARM_MPU_RBAR(3, 0x20000000U);
    25.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
    26.     /* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back */
    27.     MPU->RBAR = ARM_MPU_RBAR(4, 0x20200000U);
    28.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_1MB);
    29.     /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */
    30.     MPU->RBAR = ARM_MPU_RBAR(5, 0x20300000U);
    31.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB);

    32.     //////////////////////////////////////////////////////////////////////////////////////
    33.     // 0x30000000 之后的外部 NOR Flash 空间配置(实际 16MB)
    34. #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)
    35.     /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back. */
    36.     MPU->RBAR = ARM_MPU_RBAR(6, 0x30000000U);
    37.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_16MB);
    38. #endif

    39.     //////////////////////////////////////////////////////////////////////////////////////
    40.     // 0x80000000 之后的外部 SDRAM 空间配置(最大 512MB,实际 64MB)
    41.     /* Region 7 setting: Memory with Device type, not shareable, non-cacheable. */
    42.     MPU->RBAR = ARM_MPU_RBAR(7, 0x80000000U);
    43.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
    44. #ifdef USE_SDRAM
    45.     /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back */
    46.     MPU->RBAR = ARM_MPU_RBAR(8, 0x80000000U);
    47.     MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB);
    48. #endif
    49. #if defined(__ICCARM__) || defined(__GNUC__)
    50.     extern uint32_t __NCACHE_REGION_START[];  // 来自链接文件里的定义
    51.     extern uint32_t __NCACHE_REGION_SIZE[];   // 来自链接文件里的定义
    52.     uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START;
    53.     uint32_t size          = (uint32_t)__NCACHE_REGION_SIZE;
    54. #endif
    55.     volatile uint32_t i = 0;
    56.     while ((size >> i) > 0x1U)
    57.     {
    58.         i++;
    59.     }
    60.     if (i != 0)
    61.     {
    62.         /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
    63.         assert(!(nonCacheStart % size));
    64.         assert(size == (uint32_t)(1 << i));
    65.         assert(i >= 5);

    66.         /* Region 9 setting: Memory with Normal type, not shareable, non-cacheable */
    67.         MPU->RBAR = ARM_MPU_RBAR(9, nonCacheStart);
    68.         MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, i - 1);
    69.     }

    70.     /* Enable MPU */
    71.     ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);

    72.     /* Enable I cache and D cache */
    73.     SCB_EnableDCache();
    74.     SCB_EnableICache();
    75. }
    复制代码
    附录一、MPU特性差异
    19.png



    qiandao qiandao
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-18 14:02 , Processed in 0.088702 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表