MPU抽象层设计与使用方法

内存保护单元
内存保护单元是一个可编程的设备,用来指定一块特定内存区域的访问权限,比如读,写,和从该区域执行代码的权限。内存保护单元可以增加系统的健壮性,预防一些黑客的攻击。armv7-m和armv8-m都提供了内存保护单元,简称mpu(memory protection unit)。risc-v也提供了相似的功能,简称pmp(physical memory protection)。
项目进展
目前对armv7-m和armv8-m架构实现了初步的支持。框架通用的代码在components/mp目录下,硬件相关的代码存放在libcpu,并提供了两个简单的例程。
功能简介
rt-thread操作系统的任务和内核使用同一个地址空间,全部运行在特权级。所有代码默认对任何内存都有读,写,和执行的权限。使用mpu框架可以给特定的内存区域设置更低的权限,如只读权限。mpu框架可以被用来实现以下的功能:
把关键数据或代码设置成只读,防止它们被破坏
任务隔离,设定特定地址只能由特定的任务访问
检测栈溢出
把数据区域设置为不可执行,防止栈溢出攻击
使用方法
menuconfig配置
通过menuconfig进入rt-thread components->memory protection配置相关选项
rt_using_mem_protection:开启mpu抽象层
rt_using_hw_stack_guard:使用mpu检测栈溢出。具体实现原理是在任务栈顶和栈底各设置一个mpu区域,权限设置为不可访问。如果发生栈溢出,代码访问了mpu保护的地址,会触发异常
num_mem_regions:硬件支持的mpu区域数量
num_exclusive_regions:使用rt_mem_protection_add_exclusive_region函数配置的内存区域数量
num_configurable_regions:各任务可以通过rt_mem_protection_add_region函数配置的内存区域数量
内存区域配置
mpu抽象层提供了以下的api来配置任务对内存区域的权限:
rt_err_t rt_mem_protection_add_region(rt_thread_t thread, rt_mem_region_t *region):添加内存区域
rt_err_t rt_mem_protection_delete_region(rt_thread_t thread, rt_mem_region_t *region):删除内存区域
rt_err_t rt_mem_protection_update_region(rt_thread_t thread, rt_mem_region_t *region):更新内存区域配置
内存区域的特性由rt_mem_region_t结构体定义:
typedef struct {
void start; / 起始地址 /
rt_size_t size; / 区域大小 /
rt_mem_attr_t attr; / 区域特性 */
} rt_mem_region_t;
其中attr可通过以下宏来定义,使用这样定义的代码在任何处理器架构下都是通用的:
rt_mem_region_p_rw_u_rw:可读写
rt_mem_region_p_ro_u_ro: 只读
rt_mem_region_p_na_u_na:不可访问
rt_mem_region_p_rwx_u_rwx:可读写,执行
rt_mem_region_p_rx_u_rx:只读,可执行
通常程序需要定义一块内存区域只能由一个特定的任务访问。允许访问该内存区域的任务可以调用以下函数实现这个功能:
rt_err_t rt_mem_protection_add_exclusive_region(void *start, rt_size_t size):添加内存区域
rt_err_t rt_mem_protection_delete_exclusive_region(void *start, rt_size_t size):删除内存区域
初始化
使用mpu抽象层之前需要在board.h文件定义固定的mpu区域数量:
#define num_static_regions 2
在board.c文件定义固定的mpu区域特性:
rt_mem_region_t static_regions[num_static_regions] = {
/* flash region, read only */
{
.start = (void )stm32_flash_start_adress,
.size = (rt_size_t)stm32_flash_size,
.attr = rt_mem_region_p_rx_u_rx,
},
/ sram regin, no execute */
{
.start = (void *)stm32_sram_start_address,
.size = (rt_size_t)stm32_sram_size,
.attr = rt_mem_region_p_rw_u_rw,
},
};
任何代码进行内存访问,都要遵守这些区域的配置。可以用固定的mpu区域,把代码段配置为只读,可执行,把数据段配置成可读写,不可执行。
另外必须确保配置的mpu区域数量满足以下的关系:
如果开启了rt_using_hw_stack_guard:num_static_regions + num_configurable_regions + num_exclusive_regions + 2 <= num_mem_regions
如果没有开启rt_using_hw_stack_guard:num_static_regions + num_configurable_regions + num_exclusive_regions <= num_mem_regions
异常检测
程序可以注册钩子函数,用来检测内存异常:
rt_err_t rt_hw_mp_exception_set_hook(rt_hw_mp_exception_hook_t hook)
hook函数会在发生内存异常时被调用。函数声明如下:
typedef void (*rt_hw_mp_exception_hook_t)(rt_mem_exception_info_t *)
rt_mem_exception_info_t结构体根据处理器机构定义,对于arm架构,提供以下用来诊断内存异常的信息:
typedef struct {
rt_thread_t thread; /* 触发异常的线程 */
void addr; / 发生异常的地址 /
rt_mem_region_t region; / 地址对应的内存区域 /
rt_uint8_t mmfsr; / memmanage status寄存器的值 */
} rt_mem_exception_info_t;

如何让示波器为工程师而生
基于Cadence设计方法的高速PCB设计
微控制器的下一步是什么?
UDE2023盛大开幕,鸣响半导体显示产业华丽乐章
焊接机器人工作站由哪些部分构成?各有什么作用?
MPU抽象层设计与使用方法
英特尔酷睿I7 VS AMD R7鹿死谁手?酷睿I7让用户看到实力!
异构计算时代,RISC-V架构发展应该更大胆一些
工业用红外测温仪用什么传感器测温度更好
“慧眼”识人,传统工业机器人也能人机协作!
高侧电流检测的测量:集成电路和原则-High-Side Cu
ATCS PLC在机床控制中的应用
苹果新款iPad 发布后 iPad Air 2 预计将停产成为历史
AMD两款新U被曝 都来自一台原型笔记本
Broadcom上季度营收92.95亿美元,同比增长4%
2018年内存行业将推动半导体收入达4510亿美元 较比去年增长7.5%
Infineon推出超低电容及四线 ESD5V3U4U-HD
Intel展示新一代酷睿 基于10nm工艺打造2019年末推出
MAX15090/MAX15090B热插拔方案在阻性负载低压应用中的应用
6A RGB LED Driver Reference De