痞子衡嵌入式:ARM Cortex-M内核那些事(9.1)- 存储保护(MPU - PMSAv6/7)
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是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 的权限控制与审核。
二、存储空间类型与属性
MPU 对存储空间的访问权限控制主要包含:Strongly-ordered(是否严格有序)、Shareable(是否共享)、Cacheable(是否缓存)、Execute Never(是否可执行)等方面,不同的访问权限配置造就了系统里不同的存储空间类型与属性,这一切都是为了能够让存储资源被 Core 高效且可靠地访问(RTOS环境下比裸机程序下更需要可靠保证)。
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):
三、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])。
MPU 模块最核心的寄存器是 MPU_RASR,其提供了存储空间具体访问权限配置,XN/AP/TEX/S/C/B 位域共同决定了最终权限,用户可根据项目实际需求进行配置。
上表中关于 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
四、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。
void BOARD_ConfigMPU(void)
{
/* Disable I cache and D cache */
SCB_DisableICache();
SCB_DisableDCache();
/* Disable MPU */
ARM_MPU_Disable();
//////////////////////////////////////////////////////////////////////////////////////
// 系统全部 4GB 空间先配置成 XN 属性的 Device
/* Region 0 setting: Instruction access disabled, No data access permission. */
MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB);
//////////////////////////////////////////////////////////////////////////////////////
// 0x00000000 之后的1GB 空间配置成非 XN 属性的 Device
/* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */
MPU->RBAR = ARM_MPU_RBAR(1, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB);
//////////////////////////////////////////////////////////////////////////////////////
// 0x00000000 之后的内部 RAM 空间配置(实际 2MB)
/* Region 2 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(2, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
/* Region 3 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(3, 0x20000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
/* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(4, 0x20200000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_1MB);
/* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(5, 0x20300000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB);
//////////////////////////////////////////////////////////////////////////////////////
// 0x30000000 之后的外部 NOR Flash 空间配置(实际 16MB)
#if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)
/* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back. */
MPU->RBAR = ARM_MPU_RBAR(6, 0x30000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_16MB);
#endif
//////////////////////////////////////////////////////////////////////////////////////
// 0x80000000 之后的外部 SDRAM 空间配置(最大 512MB,实际 64MB)
/* Region 7 setting: Memory with Device type, not shareable, non-cacheable. */
MPU->RBAR = ARM_MPU_RBAR(7, 0x80000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
#ifdef USE_SDRAM
/* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(8, 0x80000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB);
#endif
#if defined(__ICCARM__) || defined(__GNUC__)
extern uint32_t __NCACHE_REGION_START[]; // 来自链接文件里的定义
extern uint32_t __NCACHE_REGION_SIZE[]; // 来自链接文件里的定义
uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START;
uint32_t size = (uint32_t)__NCACHE_REGION_SIZE;
#endif
volatile uint32_t i = 0;
while ((size >> i) > 0x1U)
{
i++;
}
if (i != 0)
{
/* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
assert(!(nonCacheStart % size));
assert(size == (uint32_t)(1 << i));
assert(i >= 5);
/* Region 9 setting: Memory with Normal type, not shareable, non-cacheable */
MPU->RBAR = ARM_MPU_RBAR(9, nonCacheStart);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, i - 1);
}
/* Enable MPU */
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
/* Enable I cache and D cache */
SCB_EnableDCache();
SCB_EnableICache();
}
附录一、MPU特性差异
处理器版本 | 存在MPU | 最大主保护区域(k) | 主保护区域可重叠 | 子保护区域 | 三组Alias空间 | |
---|---|---|---|---|---|---|
Cortex-M0/1 | 无 | N/A | N/A | N/A | N/A | |
Cortex-M0+ | 有 | 8个 | 支持 | k*8个 | 不支持 | |
Cortex-M3/4 | 有 | 8个 | 支持 | k*8个 | 支持 | |
Cortex-M7 | 有 | 8/16个 | 支持 | k*8个 | 支持 | |
Cortex-M23 | 有 | 8个 | 不支持 | 不支持 | 不支持 | |
Cortex-M33/35P | 有 | 8个 | 不支持 | 不支持 | 支持 | |
Cortex-M55 | 有 | 4/8/12/16个 | 不支持 | 不支持 | 支持 |
至此,ARM Cortex-M存储保护模块(MPU)痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。
痞子衡嵌入式:ARM Cortex-M内核那些事(9.1)- 存储保护(MPU - PMSAv6/7)的更多相关文章
- 痞子衡嵌入式:ARM Cortex-M内核那些事(6)- 系统堆栈机制
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是ARM Cortex-M堆栈机制. 今天给大家分享的这篇依旧是2016年之前痞子衡写的技术文档,花了点时间重新编排了一下格式.前面痞子衡 ...
- 痞子衡嵌入式:ARM Cortex-M调试那些事(1)- 4线协议标准(JTAG)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式调试里的接口标准JTAG. 在结束<ARM Cortex-M文件那些事>系列文章之后,痞子衡休整了一小段时间,但是讲课的 ...
- 痞子衡嵌入式:ARM Cortex-M文件那些事(1)- 源文件(.c/.h/.s)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的source文件. 众所周知,嵌入式开发属于偏底层的开发,主要编程语言是C和汇编.所以本文要讲的source文件主要指的就是 ...
- 痞子衡嵌入式:ARM Cortex-M文件那些事(3)- 工程文件(.ewp)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的project文件. 前面两节课里,痞子衡分别给大家介绍了嵌入式开发中的两种典型input文件:源文件(.c/.h/.s). ...
- 痞子衡嵌入式:Ethos-U55,ARM首款面向Cortex-M的microNPU
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是ARM Ethos-U55. ARM 前几天刚发布了 Cortex-M 家族最新一款内核 - Cortex-M55 以及首款面向 Cor ...
- 痞子衡嵌入式:链接函数到8字节对齐地址或可进一步提升i.MXRT内核执行性能
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT上进一步提升代码执行性能的经验. 今天跟大家聊的这个话题还是跟痞子衡最近这段时间参与的一个基于i.MXRT1170的大项目有 ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM内核下
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(1)之执行在不同CM内核下. 文接上篇 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计&g ...
- 痞子衡嵌入式:盘点国内RISC-V内核MCU厂商
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是国内RISC-V内核MCU厂商. 虽然RISC-V风潮已经吹了好几年,但2019年才是其真正进入主流市场的元年,最近国内大量芯片公司崛起 ...
- 痞子衡嵌入式:盘点国内RISC-V内核MCU厂商(2020年发布产品)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是国内RISC-V内核MCU厂商(2020). 虽然RISC-V风潮已经吹了好几年,但2019年才是其真正进入主流市场的元年,最近国内大量 ...
随机推荐
- OSPF多区域原理与配置
OSPF多区域原理与配置 目录 一.OSPF多区域生成 1.1.生成OSPF多区域的原因 二.OSPF的三种通信量 2.1.域内通信量 2.2.域间通信量 2.3.外部通信量 三.OSPF的路由器类型 ...
- Linkerd 2.10(Step by Step)—设置服务配置文件
Linkerd 2.10 系列 快速上手 Linkerd v2.10 Service Mesh 腾讯云 K8S 集群实战 Service Mesh-Linkerd2 & Traefik2 部署 ...
- Jenkins CI&CD 自动化发布项目实战(上篇)
Jenkins CI&CD 自动化发布项目实战(上篇) 作者 刘畅 时间 2020-11-28 实验环境 centos7.5 主机名 ip 服务配置 软件 gitlab 172.16.1.71 ...
- 41、解决du与df统计不一致的解决方法
41.1.案例说明: 通过df -hT和du -sh /.du -h --max-depth=1 /命令 发现磁盘的使用不量不一致,使用'df -hT'命令查看磁盘的使用量要 比使用'du -sh / ...
- Linux云计算-03_必备基础命令
Linux系统启动默认为字符界面,一般不会启动图形界面,所以对命令行的熟练程度能更加方便.高效的管理Linux系统. 本章介绍Linux系统必备命令各项参数及功能场景,Linux常见命令包括:cd.l ...
- PostgreSQL角色问题
角色 PostgreSQL使用角色的概念管理数据库访问权限. 根据角色自身的设置不同,一个角色可以看做是一个数据库用户,或者一组数据库用户. 角色可以拥有数据库对象(比如表)以及可以把这些对象上的权限 ...
- 机器学习Sklearn系列:(三)决策树
决策树 熵的定义 如果一个随机变量X的可能取值为X={x1,x2,..,xk},其概率分布为P(X=x)=pi(i=1,2,...,n),则随机变量X的熵定义为\(H(x) = -\sum{p(x)l ...
- ARTS第六周
第六周.后期补完,太忙了. 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有 ...
- CF1458D Flip and Reverse[题解]
Flip and Reverse 题目大意 给定一个 \(01\) 字符串,有机会进行若干次操作,对于每一次操作: 选择该字符串的子串,要求是该子串内包含数量相同的 \(0\) , \(1\) 字符. ...
- VBA:考场场标打印
Function pda(x) a = x If Len(a) = 1 Then ab = "00" & a ElseIf Len(a) = 2 Then ab = &qu ...