概述
关注+星标公众号,不错过精彩内容
转自 | 麦克泰技术
MPU(Memory Protection Unit,内存保护单元)在 Cortex-M内核中是可选模块,带MPU的微控制器允许内存映射(包括Flash、RAM和外围设备)细分为若干区域,分别给每个区域分配不同的访问权限。
FreeRTOS-MPU是FreeRTOS针对MPU实现的一个安全版本,支持ARMv7-M(Cortex-M3, Cortex-M4 和 Cortex-M7)和ARMv8-M (Cortex-M23和Cortex-M33) 内核的微控制器。
针对ARMv7-M的FreeRTOS移植存在两个版本,一个支持MPU,一个不支持。针对ARMv8-M只有一个移植版本,通过编译开关控制是否支持MPU。
FreeRTOS通过将任务分为特权和非特权运行模式和限制对RAM、外设、可执行代码、任务堆栈内存的访问,使得应用更健壮和安全。例如,防止代码从RAM中执行可以获得巨大的好处,因为这样做可以防止许多攻击向量,如缓冲区溢出漏洞或加载到RAM中的恶意代码的执行。
使用MPU必然会使应用程序设计更加复杂,首先必须确定MPU的内存区域限制并向RTOS进行描述,其次MPU限制应用程序任务可以做什么和不能做什么。
MPU的策略
创建一个将每个任务限制在其自己的内存区域的应用程序可能是最安全的,但它也是设计和实现最复杂的。通常最好使用一个MPU来创建一个伪进程和线程模型——允许线程组共享内存空间。例如,创建一个可被可信的第一方代码访问的内存空间,以及一个仅可被不可信的第三方代码访问的内存空间。
FreeRTOS-MPU特性
兼容ARM Cortex-M3和Cortex-M4F标准移植。
可以创建以特权模式或非特权模式运行的任务。非特权任务只能访问它们自己的堆栈和最多三个用户可定义的内存区域(每个任务三个)。用户可定义内存区域是在创建任务时分配给任务的,如果需要,可以在运行时重新配置。
用户可定义的内存区域可以单独参数化。例如,一些区域可能被设置为只读,而另一些区域可能被设置为不可执行(在ARM术语中简称为XN),等等。
非特权任务之间不共享数据内存,但非特权任务可以使用标准队列和信号量机制相互传递消息。可以通过使用用户可定义的内存区域显式地创建共享内存区域,但是不建议这样做。
特权模式任务可以将自己设置为非特权模式,但一旦进入非特权模式,它就不能再将自己设置为特权模式。
FreeRTOS API位于Flash的一个区域,该区域只能在微控制器处于特权模式(调用API函数导致临时切换到特权模式)时访问。
内核维护的数据位于RAM的一个区域,只有在微控制器处于特权模式时才能访问。
系统外设只能在微控制器处于特权模式时访问。任何代码都可以访问标准外设(UART等),但是可以使用可定义的内存区域显式地对其进行保护。
FreeRTOS-MPU可以创建两种类型的任务:
特权任务:特权任务可以访问整个内存映射。特权任务可以使用xTaskCreate()或xTaskCreateRestricted() API函数来创建。
非特权任务:非特权任务只能访问它的堆栈。此外,可以授予它最多三个用户可定义内存区域的访问权限(每个任务三个)。非特权任务只能使用xTaskCreateRestricted()创建。注意,xTaskCreate()不能用于创建非特权任务。
如果一个任务想要使用MPU,那么必须提供以下附加信息:
????任务堆栈的地址。
????最多三个用户可定义内存区域的开始、大小和访问参数。
因此,创建任务所需的参数总数非常大。为了使创建MPU任务更容易, xTaskCreateRestricted()使用了一个名为xTaskParameters的参数结构体,通常定义为结构常量存储在Flash中,并将该结构地址作为单个参数传递给xTaskCreateRestricted()。
typedef struct xTASK_PARAMTERS
{
TaskFunction_t pvTaskCode;
const signed char * const pcName;
unsigned short usStackDepth;
void * pvParameters;
UBaseType_t uxPriority;
portSTACK_TYPE * puxStackBuffer;
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
} TaskParameters_t;
typedef struct xMEMORY_REGION
{
void *pvBaseAddress; /* 起始地址 */
unsigned long ulLengthInBytes; /* 长度 */
unsigned long ulParameters; /* 访问属性 */
} MemoryRegion_t;
分配给任务的内存区域可以使用vTaskAllocateMPURegions()来更改。
预定义区域和用户可定义区域
区域0~4被内核配置为可用的运行环境,其中:
????运行状态的任务可以访问它自己的栈,但是所有其他的RAM只有当运行在特权模式时才可以访问。
????只有当在特权模式下运行时,才能访问内核和系统外设所在的Flash内存区域。
????Flash内存(除了内核所在的内存)和所有非系统外设(例如UART和模拟输入)都可以被特权和用户模式任务访问。
内核在每次上下文切换期间都会重新配置MPU,因此每个任务可以不同地定义其余三个区域。
区域起始地址和大小限制
MPU硬件强加了两个规则,区域起始地址和大小定义必须遵守:
1、区域大小必须是32字节到4G(包括)之间的二进制的2次方。例如,32字节、64字节、128字节、256字节等等都是有效的区域大小。
2、起始地址必须是区域大小的倍数。例如,一个配置为65536字节长的区域必须从能被65536整除的地址开始。
FreeRTOS-MPU API
1、xTaskCreateRestricted()是xTaskCreate()的扩展版本,用于创建执行权限受限或者内存访问权限受限的任务。
xTaskCreateRestricted()需要xTaskCreate()使用的所有参数,加上四个额外的参数来定义三个任务特定的MPU区域和一个堆栈缓冲区。如果在普通函数参数列表中使用这个数量的参数会很麻烦,而且可能会大量使用堆栈空间。xTaskCreateRestricted()将一个指向xTaskParameters结构的指针作为其两个参数之一,第二个参数用于向创建的任务传递句柄,与xTaskCreate()参数相同。如果不需要任务句柄, pxCreatedTask可以设置为NULL。
portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition,
xTaskHandle *pxCreatedTask );
2、vTaskAllocateMPURegions()定义一组内存保护单元(MPU)区域,供受MPU限制的任务使用。如果创建任务时没有分配MPU区域,可以在运行时使用vTaskAllocateMPURegions()函数重新分配。
void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify,
const MemoryRegion_t * const xRegions );
3、特权模式任务可以调用portSWITCH_TO_USER_MODE()将自己设置为非特权模式。在非特权模式下运行的任务不能设置为特权模式。
------------ END ------------
●专栏《嵌入式工具》
●专栏《嵌入式开发》
●专栏《Keil教程》
●嵌入式专栏精选教程
关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。
点击“阅读原文”查看更多分享。
最后
以上就是生动篮球为你收集整理的FreeRTOS MPU使系统更健壮!的全部内容,希望文章能够帮你解决FreeRTOS MPU使系统更健壮!所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复