一、介绍 MAL(MPU Abstract Layer),即mpu抽象层。是RT-Thread自主研发的,支持安全的内存访问。 用户代码可以任意的访问任务、外地的内存(内存任务的访问权限、野区等),需要引起异常、被占用、硬件等问题。提高这种稳定性、成熟性的系统稳定性、安全性。MAL 组件需求下产生。
1.1 功能 温泉自然保护,自然溢出 区域内存,被调用的其他任务的实际任务 MoM 支持为快速设置不同区域的内存访问,mpu 切换切换
1.2 内存权限 内存支持以下6种访问权限: no access:等级都没有读写权限 特权访问:只有特权级具有读写权限 非特权级只读:特权级有读写权限,非特权级只读 完全访问权限:等级都拥有读写权限 特权级访问权限,非特权级没有读写权限 只读权限:任何等级只有读权限
1.3 工作原理 不同架构的芯片,MPU可设置不同的区域。 cortex-m3 保护芯片,用户共有8个区域,系统配置占用5个,可配置区域为1个,区域2个:
对于cortex-m4/m7芯片,共有16个区域,系统配置占用5个,用户可配置区域为8个,保护区域2个:
FLASH region、Internal SRAM、External SRAM、Pripherals:系统配置,BSP制作者需要根据当前BSP配置进行初始化。 Thread Stack region:当线程第一次调度时,组件层会设置区域的底部(只读)2个区域的保护区域(只读),当线程尝试修改自己的访问权限时,会立即触发。 PROTEC区域区域:设置区域区域,该区域可以部署此区域,即AR区域可以通过托管区域的部署,不受区域限制。 USER CONFIGURABLE AREA region:用户自定义区域配置。设置当前线程的内存访问权限,该设置对其他线程类型。
1.4 框架图
1.5 数据流图
1.6 目录结构 MAL 组件目录结构如下所示: 马尔代夫 ├───文档 │ └───figures // 文档使用图片 ├───inc // 头文件目录 ├───src // 源文件目录 ├───port // 不同架构下的 MPU 对应 MAL 的移植文件 │ LICENSE // 组件许可证 │ README.md // 铝制品使用说明 │ Kconfig // 提供配置选项 └───SConscript // 工程建设脚本
2.MAL API MAL API如下所示,点击此处查看API参数详解。 /*提供给应用层用户调用的API */ rt_err_t rt_mpu_attach ( rt_thread_t thread, void * addr, size_t size, rt_uint32_t attribute); rt_err_t rt_mpu_attach_table ( rt_thread_t线程, struct mpu_regions *regions); rt_err_t rt_mpu_delete(rt_thread_t线程,rt_uint8_t区域); rt_err_t rt_mpu_refresh ( rt_thread_t thread, void *addr, size_t size, rt_uint32_t attribute, rt_uint8_t region); rt_err_t rt_mpu_enable_protect_area(rt_thread_t线程,void *addr,size_t大小,rt_uint32_t属性); rt_err_t rt_mpu_disable_protect_area(rt_thread_t线程,rt_uint8_t区域); rt_err_t rt_mpu_insert ( rt_thread_t thread, void *addr, size_t size, rt_uint32_t属性, rt_uint8_t region); rt_err_t rt_mpu_get_info ( rt_thread_t线程, rt_uint32_t类型, void *arg); void rt_mpu_exception_sethook ( rt_thread_t线程, rt_err_t (*hook)( void * addr, rt_uint32_t属性)); void rt_mpu_table_switch(rt_thread_t线程); /*支持移植调用的 API */ rt_err_t rt_mpu_ops_register ( struct rt_mpu_ops *ops); /*用于 BSP 移植调用的 API */ rt_err_t rt_mpu_init ( struct rt_mal_region *tables); rt_err_t rt_mpu_exception_handler ( rt_thread_t线程, void * addr, rt_uint32_t属性);
3.移植MAL MAL 移植分为几个层次的移植:架构层移植,和 BSP 层移植。 架构层移植:架构移植位于MAL组件的端口文件夹下,以xxx_mal.c命名,如arm架构移植文件命名为arm_mal.c,适用于所有arm架构。 BSP层移植:BSP移植文件位于具体的bsp中,主要工作是初始化处理MPU,完成MPU异常。
4.使用MAL
4.1 开启 MAL 组件 在工程目录下,打开env工具,使 MPU 抽象层:
开启mpu抽象层:开启mal组件 开启线程堆栈保护:开启关闭保护,默认开启 开启mpu抽象层调试日志:开启mal组件调试日志 设置硬件使用的 mpu 区域数:设置硬件占用的区域数: 设置 mpu 区域编号:设置 mpu 总的区域设置
4.2 示例:设置线程保护区域 其他设置内存区域,只有当前线程具有访问权限,禁止访问。 #include < rtthread.h > #include < rtdevice.h > #include < board.h > _ _ _ # ifdef RT_USING_MAL #包括 < mal.h > # endif #define THREAD_PRIORITY 25 #define THREAD_MEMORY_SIZE 1024 uint8_t thread_stack [ THREAD_MEMORY_SIZE ] __attribute__((aligned(THREAD_MEMORY_SIZE))); uint8_t thread1_stack[THREAD_MEMORY_SIZE] __attribute__((aligned(THREAD_MEMORY_SIZE))); uint8_tprotect_memory [THREAD_MEMORY_SIZE] __attribute__((aligned(THREAD_MEMORY_SIZE))); 结构rt_thread tid = { 0 }; 结构rt_thread tid1 = { 0 }; 静态 void thread1_entry ( void *param) { 而( 1 ) { 保护内存[ 0 ] = 1; rt_thread_mdelay ( 1000 ); } } 静态 rt_err_t mpu1_thread_handle ( void *addr, rt_uint32_t属性) { rt_kprintf ( "错误内存地址:%p
" ,addr); rt_thread_detach ( rt_thread_self ()); rt_schedule (); 返回RT_EOK; } int main (无效) { rt_thread_init (&tid, " mpu " , thread1_entry, RT_NULL, thread_stack, THREAD_MEMORY_SIZE, THREAD_PRIORITY, 20 ); { rt_mpu_enable_protect_area (&tid,protect_memory, THREAD_MEMORY_SIZE, RT_MPU_REGION_PRIVILEGED_RW); /*设置保护区域*/ rt_thread_startup (&tid); } rt_thread_init (&tid1, " mpu1 " , thread1_entry, RT_NULL, thread1_stack, THREAD_MEMORY_SIZE, THREAD_PRIORITY, 20 ); { rt_mpu_exception_sethook (&tid1, mpu1_thread_handle); rt_thread_startup (&tid1); } 而( 1 ) { rt_thread_mdelay ( 500 ); } } 当线程mpu1访问区域protect_memory时,会触发内存异常中断。继续正常运行。
4.3 示例:设置场景区域 只针对正面操作,避免对某块区域进行读写: #include < rtthread.h > #include < rtdevice.h > #include < board.h > _ _ _ # ifdef RT_USING_MAL #包括 < mal.h > # endif #define THREAD_PRIORITY 25 #define THREAD_MEMORY_SIZE 1024 uint8_t thread_stack [ THREAD_MEMORY_SIZE ] __attribute__((aligned(THREAD_MEMORY_SIZE))); uint8_tprotect_memory [THREAD_MEMORY_SIZE] __attribute__((aligned(THREAD_MEMORY_SIZE))); 结构rt_thread tid = { 0 }; 静态 void thread1_entry ( void *param) { 而( 1 ) { 保护内存[ 0 ] = 1; rt_thread_mdelay ( 1000 ); } } 静态 rt_err_t mpu_thread_handle ( void *addr, rt_uint32_t属性) { rt_kprintf ( "错误内存地址:%p
" ,addr); rt_thread_detach ( rt_thread_self ()); rt_schedule (); 返回RT_EOK; } int main (无效) { rt_thread_init (&tid, " mpu " , thread1_entry, RT_NULL, thread_stack, THREAD_MEMORY_SIZE, THREAD_PRIORITY, 20 ); { rt_mpu_attach (&tid,protect_memory, THREAD_MEMORY_SIZE, RT_MPU_REGION_NO_ACCESS); rt_mpu_exception_sethook (&tid, mpu_thread_handle); rt_thread_startup (&tid); } 而( 1 ) { rt_thread_mdelay ( 500 ); } } 当线程mpu访问内存区域protect_memory时,会触发 mpu 异常。在线程 mpu 异常钩子函数中,杀掉 mpu 线程,使系统继续正常运行:
原作者:liukangcc
|