嵌入式技术论坛
直播中

石玉兰

7年用户 1417经验值
私信 关注
[经验]

一文解读RT-Thread MPU抽象层的相关知识

一、介绍
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

更多回帖

发帖
×
20
完善资料,
赚取积分