STM32 MPU内存保护单元

本文详细介绍了STM32H7微控制器中的MPU(内存保护单元)的工作原理和配置,包括内存区域的划分、优先级、权限设置以及RASR、RNR、RBAR等寄存器的作用。同时,文章讨论了Cache的配置和一致性问题,如Write-through、Write-back策略,并提供了初始化流程示例。
摘要由CSDN通过智能技术生成

先说明一下MPU,MPU有很多含义,我们常见的有:

MPU:Memory Protection Unit,内存保护单元(本文描述的内容);

MPU:Microprocessor Unit,微处理器;

MPU-6050 陀螺仪 跟这个就更是差了十万八千里了

所以请不要搞混

MPU

MPU,即内存保护单元,可以设置不同存储区域的存储器访问特性(如只支持特权访问全访问)和存储器属性(如可缓存、可缓冲、可共享),对存储器(主要是内存和外设)提供保护,从而提高系统可靠性

通过这些规则可以实现如下功能

  • 防止不受信任的应用程序访问受保护的内存区域。
  • 防止用户应用程序破坏操作系统使用的数据。
  • 通过阻止任务访问其它任务的数据区。
  • 允许将内存区域定义为只读,以便保护重要数据。
  • 检测意外的内存访问。

也就是内存保护、外设保护和代码访问保护 设置一段内存是只读,还是只允许高权限访问,还是禁止访问等

MPU可以保护的区域为内存映射区 memory map

内存映射区就是 32 位的 CM7 内核整体可以寻址的 0 到 2^32 -1 共计 4GB 的寻址空间。通过这些地址可以访 问 RAM、Flash、外设等。下面是内存映射的轮廓图,IC 厂家使用时,再做细分,添加相应的硬件功能

在这里插入图片描述

也就是说 MPU可以保护我们的保护内存区域(SRAM 区)不受非法干扰,也可以保护我们的外设区(比如 FMC)

MPU 区域(region)

STM32H7 的 MPU 提供多达 16 个可编程保护区域(region)每个区域最小要求 256 字节,序号范围是 0 到 15, 每个区域(region)还可以被进一步划分为更小的子区域(sub region),每个区域(region)都有自己的可编程起始地址、大小及设置。

这些内存区可以嵌套和重叠,所以这些区域在嵌套或者重叠的时候有个优先级的问题。MPU 可以配置的 16 个内存区的序号范围是 0 到 15,序号15 的优先级最高,以此递减,还有默认区 default region,也叫作背景区,序号-1,即背景区的优先级最低。这些优先级是固定的

MPU 功能必须开启才会有效,默认条件下,MPU 是关闭的

MPU在执行其功能时,是以“region区域”为单位的。一个region其实就是一段连续的地址,只是它们的位置和范围都要满足一些限制(对齐方式,最小容量等)

MPU 区域(region)优先级

MPU 定义的区域(region)还可以相互交迭。如果某块内存落在多个区域(region)中,则访问属性和权限将由编号最大的 region 来决定。比如,若 3 号 region 与 5 号 region 交迭,则交迭的部分受 5 号 region 控制

比方说5号区域(region)内存是只读模式, 3 号 region内存是读写模式 那么重叠的部分就变成了只读模式,如果对其写入数据则会报错

在这里插入图片描述

MPU背景区

MPU在Region区域之外,还允许启用一个背景区域(即没有MPU 设置的其他所有地址空间),上面图片的空白存储区域。背景区域只允许特权访问。在启用 MPU 后,就不得再访问定义之外的地址区间,也不得访问未经授权的区域(region),否则,将以“访问违例”处理,触发 MemManage 异常

具体的我们在寄存器中讲解,你就会有一个清晰的了解。


MPU 设置是由 CTRL、RNR、RBAR 和 RASR 等寄存器控制的,其中最主要的就是RASR寄存器,下面我们来一一介绍

1.MPU 控制寄存器(CTRL),该寄存器只有最低三位有效

在这里插入图片描述

  • PRIVDEFENA 位用于设置是否开启背景区域(region),通过设置该位为 1 即可打开背景区
  • HFNMIENA 位用于控制是否在 NMI 和硬件 fault
  • ENABLE 位,则用于控制是否使能 MPU

如果PRIVDEFENA 设置为0 那么就只能访问MPU的设置的内存区域,如果访问其他地址就会报错

2.MPU 区域编号寄存器(RNR)在这里插入图片描述
该寄存器只有低 8 位有效 可以读写

在配置一个区域(region)之前,必须先在 MPU 内选中这个区域,我们可以通过将区域编号写入 MPU_RNR 寄存器来完成这个操作。该寄存器只有低 8 位有效,不过由于 STM32H7最多只支持 16 个区域,所以,实际上只有最低 4 位有效(0~15)。在配置完区域编号以后,我们就可以对区域属性进行设置了。

也就是设置要配置那个一内存区域(region)

3. MPU 区域属性和容量寄存器(RASR)
在这里插入图片描述
该寄存器是一个32位的寄存器 其中31:29位 27位 23:22位保存,没有作用

  • XN(28位):用于控制是否允许从此区域提取指令,如果 XN=1,说明禁止从区域提取指令,即这块内存区禁止执行程序代码,如果设置XN=0,则允许提取指令 即这块内存区可以执行程序代码
  • AP 位(bit[26:24]),用于控制Region区域内数据的访问权限(访问许可)三位就对应8中情况

具体设置如下:
在这里插入图片描述

注意: 下面的TEX,C,B 和 S 都是设置Cache高速缓存的,正常使用MPU是做内存保护,用上面的AP位即可,如果没有用到Cache,下面的配置有个了解即可,在HAL库配置的时候直接禁止,不会有任何影响

如果对Cache不了解,具体可看:STM32H7—高速缓存Cache(一)

TEX,C,B 和 S 的定义如下,这仅关注 TEX = 000 和 001,其它的 TEX 配置基本用不到。
在这里插入图片描述

  • C位:用于使能或者禁止Cache
  • B位:用于配合C位实现Cache下是否使用缓冲
  • S位:用于位用于控制存储器的共享特性,S=1,则二级存储器不可以缓存(Cache),如果设
    置 S=0,则可以缓存(Cache),一般我们设置该位为 0 即可。

按照配置的不同,总共可以分成以下四种:
在这里插入图片描述

read/write-through/back/allocate的区别:
一、CPU读Cache

  1. Read through:直接从内存区读取数据
  2. Read allocate:先把数据读取到Cache中,再从Cache中读取数据

二、CPU写Cache
若hit命中,有两种处理方式:

  1. Write-through:在数据更新时,把数据同时写入Cache和存储区
    操作简单,但是写入速度慢
  2. Write-back:只有在数据被替换出缓存时,被修改的缓存数据才会被写到后端存储。
    写入速度快,但是一旦更新后的数据未被写入时出现断电,则数据无法找回

若miss,有两种处理方式:

  1. Write allocate:先把要写的数据载入到Cache中,写Cache,然后再通过flush的方式写入到内存>中。
  2. No-write allocate:并不将写入位置读入缓存,直接把要写的数据写入到内存中。

什么叫hit/miss:

一、读操作
如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命 中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。
二、写操作
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。

  • SRD位: 用于控制内存区的子区域,一共有8bit,一个bit控制一个子区域,一般都开启
  • RegionSIZE位:配置Region内存区域的大小,最小为32位 可以为32kb 64kb 128kb等等

4. MPU 基地址寄存器(RBAR)
在这里插入图片描述

  • ADDR: Region内存区的首地址

注意一定要保证首地址跟内存区的大小(RegionSIZE位)对齐,例如,我们定义某个 region 的容量(RegionSIZE位)是 64KB,那么它的基址(ADDR)就必须能被 64KB 整除,也就是这个地址对 64KB,即 0x00010000 求余数等于 0,比如0X0001 0000、0X0002 0000、0X0003 0000 等都可以被整除

  • VALID 区域编号是否覆盖,如果为1的话将会重新修改ADDR Region内存区的编号
  • REGION 段(bit[3:0]) : 新编号,四位地址对应(0~15)

Region内存区的编号在初始化的时候就设置完成,所以一般VALID位设置为0

关于MPU一些基本原理和寄存器就先探讨到这里,下一篇我们来看下HAL库里MPU的配置以及如何使用。

STM32H7内存默认映射和属性

在这里插入图片描述

STM32H7 FMC地址

在这里插入图片描述

H7的cache配置

Cortex-M7内核的L1 Cache由多行内存区组成,我们的H7是分为 16Kbytes 的 I-Cache 和 D-Cache
每行有32字节,每行都配有一个地址标签。数据缓冲DCache是每4行为一组,称为4-way set associative。而指令缓冲区ICache是2行为一组,2-way set 这样节省地址标签,不用每个行都标记一个地址

  • 以16 KBytes 的 D-Cache 来计算,一共128 个组(sets), 512 个缓冲行(lines),每个缓冲行 32 个字节

首先来看下H7的默认内存地址映射范围:

在这里插入图片描述

其中,WT 表示 Write-through(透写),WB 表示 Write-back(回写),WA 表示 Write-allocate(写分配),没有明确标注 WA 的就是 RA(读分配)。XN 的意思是 Execute-Never, 其含义为如果相应的地址空间是 XN,是绝不允许执行代码的。

存储器类型为 Normal 的才能使用 cache,并且 TCM 接口是 not cacheable 的。

在H7中 Cache 的配置是通过 MPU 来设置的,通常只用到下几种方式。

Cache 相关操作的函数在 cmsis/include/core_cm7.h 头文件中声明从函数名中可以知道,包括四种 cache 操作:enable、disable、clean 和 invalidate。

在这里插入图片描述
当然还有三个不常用的函数:

void SCB_InvalidateDCache_by_Addr(uint32_t *addr, int32_t dsize);

void SCB_CleanDCache_by_Addr(uint32_t *addr, int32_t dsize);

void SCB_CleanInvalidateDCache_by_Addr(uint32_t *addr, int32_t dsize);

下面我们来看一下这些函数。

SCB_EnableICache() 

使能指令I-Cache,系统上电后优先初始化即可

SCB_DisableICache() 

禁止指令I-Cache。

SCB_InvalidateICache()

使 I-cache 无效,无效化Invalid是将Cache Line标记为无效,即删除操作。

SCB_EnableDCache()

此函数使能数据D-Cache,系统上电后优先初始化即可

SCB_DisableDCache()

禁止数据D-Cache。

SCB_InvalidateDCache()

使 D-Cache 无效,无效化Invalid是将Cache Line标记为无效,即删除操作。

SCB_CleanDCache()

Clean 清空所有的 cache-line,即将 dirty 的 cache-line 全部写到 cache line 对应的真实的物理地址中

所谓的 drity 属性,即写操作时, 更新了相应的 cache-line,但是没有更新到真实的物理地址,而这个 clean 的动作, 就是将 cache 中的内容更新到真实的物理地址中。

SCB_CleanInvalidateDCache()

此函数是前面两个函数SCB_InvalidateDCache和SCB_CleanDCache的二合一。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。

SCB_InvalidateDCache_by_Addr()

根据地址信息无效其对应的 cache-line。

SCB_CleanDCache_by_Addr()

根据地址信息 clean 其对应的 cache-line。

SCB_CleanInvalidateDCache_by_Addr()

根据地址信息 clean 并 invalidate 其对应的 cache-line。

一共就这么多,大部分都是对D-Cache的操作,正常使用的时候,直接调用函数进行初始化就行

  SCB_EnableICache();//使能I-Cache
  SCB_EnableDCache();//使能D-Cache   

但是对于Cache的一致性问题,比方说DMA操作等引起的一致性错误等

1.CPU写数据到内存

当CPU有写物理内存的指令时,CPU 会先去更新相应的 cache-line(Write-back 策略)缓存,在没有 clean 的情况下,会导致其对应的实际物理内存中的数据并没有被更新,如果这个时候有其它的 Host(如 DMA)访问这段内存时,就会出现问题(由于实际物理内存并未被更新,和 D-cache 中的不一致),这就是所谓的 cache 一致性的问题。
在这里插入图片描述

2.CPU从内存读取数据

第二种情况是 DMA 更新了某段物理内存(DMA 和 cache 直接没有直接通道),而这个时候CPU 再读取这段内存的时候,由于相对应地址的 cache-line 已经被缓存了,导致CPU 读到的是 cache-line 中的数据,而非被 DMA 更新过的实际物理内存的数据。
在这里插入图片描述
为了防止这种问题,保证数据的一致性,我们设置了 D Cache 的强制透写功能(Write Through)

强制透写(Write Through): CPU 每次操作 Cache 里面的数据,同时也会更新到 SRAM 里面,不需要再发送clean操作,保证D Cache 和 SRAM 里面数据一致。

在这里插入图片描述
需要将SCB->CACR寄存器的第一位置1 就可以开启强制透写

SCB->CACR|=1<<2;   //强制D-Cache透写

那也就得到了Cache的初始化流程:

//使能CPU的L1-Cache
void Cache_Enable(void)
{
    SCB_EnableICache();//使能I-Cache
    SCB_EnableDCache();//使能D-Cache   
	SCB->CACR|=1<<2;   //强制D-Cache透写,如不开启,实际使用中可能遇到各种问题	
}

这样带来的好处就是可以保证D Cache 和SRAM里面数据的一致性,坏处就是会损失一定的性能(每次都要回写数据),如果大家想自己控制 D Cache 数据的回写,以获得最佳性能,则可以关闭 D Cache 透写模式

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值