一、MPU简介
cortex-m3和cortex-m4处理器支持一种名为MPU的特性。MPU是一种可编程的部件,用于定义不同存储区域的存储器访问权限(如只支持特权访问或全访问)和存储器属性(如可缓冲、可缓存)。cortex-m3和cortex-m4处理器中的MPU支持多达8个可编程存储器的区域,每个都具有自己可编程的起始地址、大小及设置,另外还支持一种背景区域特性。MPU可以提高嵌入式系统的健壮性,可以使系统更加安全:
①避免应用任务破坏其他任务或OS内核使用的栈或数据存储器
②避免非特权任务访问对系统可靠性和安全性很重要的外设
③将SRAM或RAM空间定义为不可执行的,防止代码注入攻击。
还可以利用MPU定义其他存储器属性,如可被输出到系统级缓存单元或存储器控制器的可缓存性。若存储器访问和MPU定义的访问权限冲突,或者访问的存储器位置未在已编程的MPU区域中定义,则传输会被阻止且触发一次错误异常。触发的错误异常处理可以是MemManage错误或HardFault异常,实际情况取决于当前的优先级及MemManage错误是否使能。然后异常处理就可以确定系统是否应该复位或只是OS环境中的攻击任务。在使用MPU前需要对其进行设置和使能,若未使能MPU,处理器会认为MPU不存在。若MPU区域可以出现重叠,且同一个存储器位置落在两个MPU区域中,则存储器访问属性和权限会基于编号最大的那个区域。例如,若某传输的地址位于区域1和区域4定义的地址范围内,则会使用区域4的设置。
MPU设置方法有多种:
对于没有OS的系统,MPU可以被编程为静态配置。该配置可用于以下功能:
①将RAM/SRAM区域设置为只读,避免重要数据被意外破坏。
②将栈底部的一部分RAM/SRAM空间设置为不可访问,以检测栈溢出。
③将RAM/SRAM区域设置为XN,避免代码注入攻击。
④定义可被系统级缓存(2级)或存储器控制器使用的存储器属性配置。
对于具有嵌入式OS的系统,在每次上下文切换时都可以配置MPU,每个应用任务都有不同的MPU配置。这样可以:
①定义存储器访问权限,使得应用任务只能访问分配给自己的栈空间,因此可以避免因为栈泄漏而破坏其他栈。
②定义存储器访问权限,使得应用任务只能访问有限的外设
③定义存储器访问权限,使得应用任务只能访问自己的数据或自己的程序数据(设置起来可能会有些麻烦,因为多数情况下OS和程序代码是一起编译的,因此数据在存储器映射中也可能是混在一起的)。
如果需要的话,具有嵌入式OS的系统还可以使用静态配置的。
二、MPU寄存器
MPU中存在多个寄存器。这些寄存器位于系统控制空间(SCS)。CMSIS-Core头文件为MPU寄存器定义了一个数据结构体,方便对这些寄存器的访问。下表对这些寄存器进行了总结:
地址 | 寄存器 | CMSIS-Core符号 | 功能 |
---|---|---|---|
0xE000ED90 | MPU类型寄存器 | MPU->TYPE | 提供MPU方面的信息 |
0xE000ED94 | MPU控制寄存器 | MPU->CTRL | MPU使能/禁止和背景区域控制 |
0xE000ED98 | MPU区域编号寄存器 | MPU->RNR | 选择待配置的MPU区域 |
0xE000ED9C | MPU基地址寄存器 | MPU->RBAR | 定义MPU区域的基地址 |
0xE000EDA0 | MPU区域属性和大小寄存器 | MPU->RASR | 定义MPU区域的属性和大小 |
0xE000EDA4 | MPU别名1区域属性和大小寄存器 | MPU->RBAR_A1 | MPU->RBAR的别名 |
0xE000EDA8 | MPU别名1区域属性和大小寄存器 | MPU->RASR_A1 | MPU->RASR的别名 |
0xE000EDAC |