文章目录
S32K14x - MPU
1. 前言
MPU(Memory Protection Unit),用于内存保护。现在很多的产品使用了操作系统,有宏内核、微内核、混合内核等设计,因此对于内存保护极为重要。在运行APP的时候,如果不小心篡改了内核数据,则会导致系统瘫痪,APP与APP之间如果篡改了数据,也有可能让APP不能正常运行。想象一下,如果此时你动态地安装一个APP到你的单片机中,这个APP中存在野指针的访问操作,那么当你这个APP加载成功并运行的时候,一访问这个野指针,那么整个系统就瘫痪了,我们可不能让一颗"老鼠屎"坏了一锅粥,因此使用MPU内存保护单元来限制这些非法的内存操作,将内存划分设置访问权限,当某个APP出现非法操作的时候,我们就可以知道是谁在捣乱,就可以单独卸载、禁止运行这个"老鼠屎"。
2. 工作原理
2.1 S32K14x 系统框图
如上图所示,内核(①)访问内存(③),需要通过总线(DCODE/ICODE/System)进行数据传输,期间需要经过交叉开关(②),从上图可以看到,(②)中可以看到有MPU模块"卡"
在内存访问之前(到这里可以先猜测MPU是根据总线上的信息对访问进行合法性判断,因为指令信息包含地址、操作符)。
从上图可以看到,针对DMA以及QSPI也是纳入保护范围。
S32K146访问MPU的资源分布如上图所示。
2.2 MPU模块
如上图所示,输入信号有两部分组成:Address Phase Signal(地址信号)、Internal Peripheral Bus(内部外设总线),地址信号我理解是2.1中所说的总线信息(对指定地址的读/写等),内部外设总线获取到的是用户设置的信息(内存范围、访问权限等),将两部分信息通过Access Evaluation Macro模块进行判断,判断分为两部分:命中判断
、特权违反判断
。
2.2.1 Access Evaluation Macro
Access Evaluation Macro模块判断流程如上图所示,该判断的输入
由(Address、Start address、end address、access - r/w/x)组成,经过一系列判断最终输出
错误信息、操作权限。
2.2.1.1 Hit determination(命中判断)
① 命中条件:
region_hit = ((addr[31:5] >= RGDn_Word0[SRTADDR]) & (addr[31:5] <= RGDn_Word1[ENDADDR])) & RGDn_Word3[VLD]
(地址 >= 起始地址 && 地址 <= 结束地址 && 区域描述符有效)
② 命中条件(with peocess id)
pid_hit = ~RGDn_Word2[MxPE] | ((current_pid | RGDn_Word3[PIDMASK]) == (RGDn_Word3[PID] | RGDn_Word3[PIDMASK]))
(每个Region中可以包含多个master,通过pid可以实现对多个master进行访问控制)
master逻辑控制ID如下图所示:
2.2.1.2 Privilege violation determination(特权违反判断)
系统指令与用户设置的权限进行比较,各此操作允许访问权限如上图所示。
保护区域重叠优先级该如何决定?
重叠区域的权限使用or运算,允许访问(1)覆盖拒绝访问(0)。
2.2.2 错误
- 如果未在任何区域描述符中命中该访问,则会报告一个保护错误
- 如果访问命中单个区域描述符,并且该区域表示违反保护,则报告保护错误
- 如果访问击中多个(重叠)区域,并且所有区域都出现违反保护的信号,则报告保护错误
每一组Slave port
都会有如下的一组错误寄存器:
① 错误地址寄存器:
② 错误详细信息寄存器:
2.2.4 MPU使用
- 配置内存保护地址范围
- 配置访问权限
- 配置Valid位
这里我是直接使用S32DS-Components的mpu_pal抽象库和图形化配置界面,参考自带的demo工程,这里不再赘述
mpu 初始化:
MPU_Init(&mpu_pal1_Instance, MPU_PAL_REGION_CFG_CNT0, mpu_pal1_RegionConfig0);
mpu region 使能/禁用:
MPU_EnableRegion(&mpu_pal1_Instance, 1, true); // 使能
MPU_EnableRegion(&mpu_pal1_Instance, 1, false); // 禁用
当触发故障后,会触发HardFault
3. 遗留问题
-
MPU Region 使能/禁用逻辑:按照手册上说,当Valid位启用时,区域描述符才会有效(如下图所示),但是当我调用
MPU_EnableRegion
并且传入参数为true的时候,Valid被置1,这个时候我去从不可读区域读取数据,并没有产生错误标志以及进入HardFault,但是当我传入false时,Vaild被置0,这个时候重复上述操作能够触发错误标志且进入HardFault,此部分与我所理解相反。
已解决:
在设置地址的时候,原本是设置成0x6000,但是S32DS自动配置成了0x6001F,导致与后面的区域重叠,在区域重叠下,由于后面的区域为可读权限,导致权限被覆盖,因此造成了上面的乌龙😄。此处感谢@mfketggo的提醒。 -
MemManage 无法触发:出现错误的内存访问操作时,如果开启了MemManage,那么应该不会触发HardFault而是触发MemManageFault,但是当我执行如下代码使能MemManage后,还是触发的HardFault,MemManage并没有起效。
/** Peripheral S32_SCB base address */ #define S32_SCB_BASE (0xE000E000u) /** Peripheral S32_SCB base pointer */ #define S32_SCB ((S32_SCB_Type *)S32_SCB_BASE) S32_SCB->SHCSR |= (1 << 16);
后来我将BusFault也使能,发现竟然会触发BusFault如下图所示,且故障原因是BFARVALID和PRECISERR:
已解决:
根据NXP的FAE回复芯片设计如此,无法触发mm,只能触发bf,此处感谢@mfketggo的分享。
参考资料:
S32K-RM.pdf - NXP
Cortex-M3/4内核手册