STM32的HAL库开发---内存保护(MPU)
一、内存保护单元(MPU)介绍
内存保护单元(memory protection unit),简称:MPU。
MPU的功能:代码访问保护、内存保护、外设保护
1、设置不同存储区域的存储器访问权限,访问权限可以是特权级或者用户级,或者是全可以,也就是全访问。
2、设置存储器(内存和外设)属性(可缓存、可缓冲、可共享)
可以理解为MPU就是一个管理员,管理权限,内核里边有很多个存储块,然后MPU多这些存储块进行管理访问权限,是特权级可以访问还是用户级可以访问,还是都可以访问,对应功能中的第一条。同时MPU管理访问内存块的规则和途径。
MPU优点:
① 阻止用户应用程序破坏操作系统使用的数据
② 阻止一个任务访问其他任务的数据区,从而隔离任务
③ 把关键数据区域设置为只读,从根本上解决被破坏的可能
④ 检测意外的存储访问,如堆栈溢出、数组越界等
⑤ 将SRAM或RAM空间定义为不可执行,防止代码注入攻击
内核地址映射:
MPU可配置保护8/16个内存区域,每个区域最小要求256字节,且每个区域还可配置为8个子区域(大小一样)。这里以H7为例子,分为16个区域,其中16个区域可能会有重叠和嵌套,重叠或嵌套下,重叠部分按着优先级高的内存区配置规则执行,其中编号越小的,优先级越高。除了这16个区域,还有一个背景区,背景区对这16个区域的地址空间有一个默认的设置。
MPU设置内存区域的访问权限 :
配置好MPU,不得访问定义外的地址空间,也不得访问未经授权的区域,否则属于非法访问,会触发错误异常。例如如果配置了一块区域只读,在对这块区域进行写,就会触发错误异常。
MPU配置内存区域的访问属性:三种内存类型
1、Normal memory:ROM、FLASH、SRAM
CPU以最高效的方式加载和存储字节、半字和字, CPU对于这种内存区的加载或存储不一定要按照程序代码的顺序执行
2、Device memory:外设
加载和存储要严格按照次序进行,确保寄存器按照正确顺序设置
3、Strongly ordered memory
程序完全按照代码顺序执行,CPU会等待当前加载存储执行完毕后才执行下一条指令,导致性能下降。
其中第一中性能最强,然后是第二种,最差的是第三种。
三种内存类型对应的情景:
CPU通过Cache与内存进行交互,Cache的频率与CPU频率相同,其中Memory就是SRAM,而SRAM的频率只有CPU的一半,通过Cache可以实现同步访问,可以配置是否使用Buffer缓存。对于Device Memory 必须使用Buffer缓冲。而Strongly Ordered Memory没有Buffer,性能最差。
可共享:对于H7的每条总线上都有多个Master和Slave,且同一个Slave可以多个Master进行访问 。CPU可以访问SRAM1,同时DMA也可以访问SRAM1,而如果CPU把数据同步到Cache里边,但是Cache没有把数据同步到SRAM里边,这时候DMA去访问SRAM,数据就不统一,所以需要数据共享。
二、Cache简介
Cache(高级缓存)是提升STM32性能的关键一步。Cache只在F7、H7系列有。M7内核芯片做了一级Cache支持,Cache分为数据缓存D-Cache和指令缓存I-Cache。
由于SRAM只有CPU主频的一半,所以使用Cache加速访问。数据缓存D-Cache是解决CPU加速访问SRAM
Cache支持4种基本操作:1,使能;2,禁止; 3,清空; 4,无效化
CPU与SRAM有两种方式,第一种是CPU直接访问SRAM,第二种是CPU通过Cache访问SRAM,还有就是DMA可以直接访问SRAM。
读操作:
CPU要读取的SRAM区数据在Cache中已经加载好,叫读命中(Cache hit); 如果Cache里面没有,这就是读Cache Miss。
写操作:
CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,这就叫写命中(Cache hit);如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。
保证cache有足够高的命中率,尽量少的cache miss,读/写速度会有比较大的提高。
CPU读Cache:
1、如果是Cache hit ,则内核可以直接从Cache里边读数据。
2、如果是Cache mis,存在两种方式,第一种是read through,直接从内存中读出,不用cache。第二种是read allocate,把数据从内存加载到cache,再从cache读取 。
CPU写Cache:
1、如果是Cache hit ,存在两种方式。第一种是Wrte through,直接写到内存中并同时放到cache里面内存和cache同步更新。第二种是write back,数据更新时只写入cache,只在数据被替换出cache时被修改的cache数据才会写入内存,写入速度快。
如果当CPU把数据放到Cache里边,在数据被替换出Cache之前,DMA访问SRAM,就会出现数据不一致。
2、如果是Cache mis,存在两种方式,第一种是write allocate,先把要写的数据载入Cache里面,对Cache写之后,才更新到SRAM里边。第二种是no write allocate,直接写入内存,不用cache。
数据不一致问题:
设置共享属性:Cache相当于没有开启。
软件进行Cache维护:
clean清空,Cache已经变化,SRAM数据未更新,DMA搬运数据前,将Cache相对应数据更新到SRAM,调用clean函数,SCB_CleanDCache / SCB_CleanInvalidateDCache 。
invalidate 无效化:SRAM数据已变化,Cache未更新 。DMA搬运数据后,cache数据无效,需从SRAM中获取。调用函数SCB_InvalidateDCache / SCB_CleanInvalidateDCache 。
三、MPU相关寄存器介绍
1、MPU_TYPE寄存器
这个寄存器是只读的,IREGION永远是0,因为MPU是固定,设置好的。DREGION是MPU支持的数量。
2、MPU_CTRL寄存器
PRIVDEFENA:设置成0,未定义区域不可以访问,会报错误。设置成1,可以访问region外的区域。
3、MPU_RNR寄存器:用于选择下一个要配置的region。
配置任何一个region前,都需要在MPU内选中这个region,即把region号写入MPU_RNR。
4、 MPU_RBAR寄存器:
5、MPU_RASR寄存器
AP 相关位控制数据的访问权限(访问许可),通常只需要设置全访问。
值 | 特权级下的许可 | 用户级下的许可 | 描述 |
0b000 | 禁止访问 | 禁止访问 | 所有访问都会产生取消权限错误 |
0b001 | RW | 禁止访问 | 只支持特权访问 |
0b010 | RW | RO | 非特权写入会产生权限错误 |
0b011 | RW | RW | 全访问 |
0b100 | n/a | n/a | n/a |
0b101 | RO | 禁止访问 | 仅支持特权读 |
0b110 | RO | RO | 仅可通过特权或非特权读(只读) |
0b111 | RO | RO | 仅可通过特权或非特权读(只读) |
TEX用来设置Cache策略:
四、MPU相关HAL库驱动介绍
一般操作是先将MPU失能,然后进行MPU参数配置,最后再使能MPU。
难点:如何让配置的内存区最大限度发挥性能
1、void HAL_MPU_Enable (uint32_t MPU_Control)函数,操作PRIVDEFENA位,该位为0,禁止背景区,访问任何未使能MPU区域均会造成内存异常MemFault ;该位为1,使能背景区,特权级下可以正常访问任何未使能MPU区域。
2、void HAL_MPU_Disable (uint32_t MPU_Control)函数,失能MPU功能。
3、区域配置函数,需要传递一个结构体。
五、MPU基本配置步骤
1、void HAL_MPU_Disable(),禁止MPU。
2、通过调用HAL_MPU_ConfigRegion()函数去设置,配置某个区域的MPU保护参数
3、void HAL_MPU_Enable();,使能MPU
4、void MemManage_Handler(void),编写MemManage中断服务函数。
MPU属于内核外设,可以通过DEBUG的内核外设进行查看。
六、总结
通过配置mpu内存保护,被保护的地址如果再随机更改,就会发生内存错误,进入MemManage_Handler中断服务函数。可以使用HAL库,这个是内核的,可以先了解了解。