内存保护单元 (MPU) 支持
本页面包含:
简介
FreeRTOS提供官方内存保护单元 (MPU) 支持,适用于 ARMv7-M(Cortex-M3、Cortex-M4 和 Cortex-M7 微控制器)和
ARMv8-M(Cortex-M23 和 Cortex-M33 微控制器)内核:
-
有两个针对 ARMv7-M 内核的 FreeRTOS 移植,一个包括 MPU 支持,一个不包括。
-
只有一个 FreeRTOS 移植用于 ARMv8-M 内核,因为
MPU 支持是一个编译时间选项。
第三方维护 MPU 到其他微控制器内核的移植。
MPU 成本和收益
FreeRTOS MPU 移植首先能够使任务能够在特权模式或非特权模式下运行,然后限制对 RAM、可执行代码、外围设备和超出任务堆栈限制的内存等资源的访问,从而使微控制器应用程序更加强大和安全。 例如,防止代码从 RAM 执行将获得巨大的好处。这样做可以防止许多攻击向量,例如缓冲区溢出攻击或执行加载到 RAM 中的恶意代码。
使用 MPU 必然会使应用程序设计更加复杂,因为首先要确定 MPU 的内存区域限制并将其描述给 RTOS,其次 MPU 限制了应用程序任务可以做什么和不能做什么。
MPU 策略
创建一个将每个任务限制在各自内存区域的应用程序可能是最安全的,但其设计与实现也是最复杂的。 通常最好使用 MPU 来创建伪过程和线程模型——其中线程组可以共享内存空间。 例如,创建一个可供受信任的第一方代码访问的内存空间,再创建一个只供不受信任的第三方代码访问的内存空间。
其他示例
FreeRTOS 电子书的 LPC17xx 版包含关于使用 FreeRTOS-MPU 的章节,虽然其中的信息有些过时。
在 ARMv8-M 微控制器上使用 FreeRTOS
的博客文章提到了在 ARMv8-M 微控制器上使用 MPU 的方法。
FreeRTOS/Demo/CORTEX_MPU_Simulator_Keil_GCC 目录下的演示项目,
使用 Keil uVision 来构建和模拟 GCC 项目,提供了一个不需要任何特殊硬件的工作实例。
其他 FreeRTOS-MPU 示例项目包括 Nuvoton NuMaker-PFM-M2351 演示
和 NXP LPCXpresso55S69 演示 等。
[FreeRTOS-MPU 演示项目——位于 FreeRTOS/Demo/CORTEX_MPU_LPC1768_GCC_RedSuite 和
FreeRTOS/Demo/CORTEX_MPU_LM3Sxxxx_Rowley 目录中,
在 FreeRTOS V9.0.0 发布前就已经退役]
升级信息
已根据终端用户的反馈对 FreeRTOS MPU 移植进行了升级。 本节介绍升级到 FreeRTOS V10.6.1或更高版本所需的更改,
以及在此之前,升级到 FreeRTOS V10.6.0、V10.5.0、V10.4.6、V10.4.0 和 V10.3.0 或更高版本所需的更改。
FreeRTOS 版本 10.6.1 中的更改:
FreeRTOS V10.6.1 将运行时参数检查引入 mpu_wrappers_v2.c 文件中的函数。API 实现中已使用断言
执行了相同的检查。
我们感谢以下人士为这些更改提供的贡献:
- 中国安徽工业大学计算机科学与技术学院的 Lan Luo、Zixia Liu。
- 美国马萨诸塞大学洛厄尔分校计算机科学系的 Xinwen Fu。
- 中国东南大学计算机科学与工程学院的 Xinhui Shao、Yumeng Wei、Huaiyu Yan、Zhen Ling。
FreeRTOS 版本 10.6.0 中的更改:
FreeRTOS V10.6.0 引入了一个全新 MPU 包装函数,对非特权任务施加了额外限制。以下是更改列表
随新 MPU 包装函数引入:
- 内核对象句柄的不透明且可间接验证的整数:所有内核对象句柄(例如,队列句柄)现在都是
不透明整数。以前,对象句柄是原始指针。
- 任务上下文保存在任务控制块 (TCB) 中:当调度程序交换出任务时,任务的上下文现在保存在其 TCB 中。
以前,任务的上下文保存在其堆栈中。
- 系统调用在仅限特权的独立堆栈上执行:通过更高特权执行的 FreeRTOS 系统调用现在使用
仅限特权的独立堆栈。以前,系统调用使用调用任务的堆栈。
- 内存界限检查: 接受并取消引用指针的 FreeRTOS 系统调用现在验证调用任务是否具有所需权限
以访问指针引用的内存位置。
- 系统调用限制:以下系统调用不再可用于非特权任务:
- vQueueDelete
- xQueueCreateMutex
- xQueueCreateMutexStatic
- xQueueCreateCountingSemaphore
- xQueueCreateCountingSemaphoreStatic
- xQueueGenericCreate
- xQueueGenericCreateStatic
- xQueueCreateSet
- xQueueRemoveFromSet
- xQueueGenericReset
- xTaskCreate
- xTaskCreateStatic
- vTaskDelete
- vTaskPrioritySet
- vTaskSuspendAll
- xTaskResumeAll
- xTaskGetHandle
- xTaskCallApplicationTaskHook
- vTaskList
- vTaskGetRunTimeStats
- xTaskCatchUpTicks
- xEventGroupCreate
- xEventGroupCreateStatic
- vEventGroupDelete
- xStreamBufferGenericCreate
- xStreamBufferGenericCreateStatic
- vStreamBufferDelete
- xStreamBufferReset
此外,非特权任务不能再使用 vTaskSuspend 挂起除自身以外的任何任务。
我们感谢以下人员对这些增强功能的贡献:
- Meta Platforms, Inc. 的 David Reiss
- 中国东南大学计算机科学与工程学院的 Lan Luo、Xinhui Shao、Yumeng Wei、Zixia Liu、Huaiyu Yan 和 Zhen Ling
。
- 美国马萨诸塞大学洛厄尔分校计算机科学系的 Xinwen Fu。
- 美国科罗拉多大学博尔德分校的 Yueqi Chen、Zicheng Wang、Minghao Lin 和 Jiahe Wang。
FreeRTOS 10.5.0 版中的更改:
- FreeRTOS ARMv7-M (ARM Cortex-M3/4/7) 和 ARMv8-M (ARM Cortex-M23/33/55) 移植和内存保护单元 (MPU) 支持
不再能够使用 xTaskCreate 或 xTaskCreateStatic API 从非特权任务创建特权任务。另外,非特权任务
无法再调用以下 API:
- xTimerCreate
- xTimerCreateStatic
- xTimerPendFunctionCall
应用程序写入器需要在启动调度器之前或从一个特权任务中执行这些操作。
FreeRTOS 10.4.6 版中的更改:
-
用于 ARMv7-M MCU (ARM Cortex-M3/4/7) 的 FreeRTOS-MPU 现在包含新的配置选项
configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
。在 FreeRTOSConfig.h 中将这个常量设置为 0,
可以防止非特权应用程序任务使用 taskENTER_CRITICAL()
宏来创建临界区
。将该常量设置为 1,或者不定义它,
以保持与之前 FreeRTOS 内核版本的兼容性,可使特权和非特权任务创建临界区
。注意:建议将此常量定义为 0,以获得最高的安全性。因此,
如果此常量未定义,编译器会输出警告。
FreeRTOS 10.4.0 版中的更改:
FreeRTOS 10.3.0 版中的更改:
FreeRTOS-MPU 特定
FreeRTOS-MPU 功能
-
与标准 ARM Cortex-M3 和 Cortex-M4F 移植相兼容。
-
可以创建任务在特权模式或非特权模式下运行。非特权
任务只能访问自己的堆栈和最多三个用户可定义的内存区域(每个任务三个)。
创建任务时,将用户可定义的内存区域分配给任务,
如果需要,可以在运行时重新配置。
-
用户可定义内存区域可以单独参数化。
例如,某些区域可设置为只读,而其他区域可设置为不可执行
(从不执行,或简单设置为 ARM 术语中的 XN)等。
-
非特权任务之间没有共享数据内存,
但非特权任务可以使用标准队列和信号量机制将消息传递给彼此。 可通过使用用户可定义的内存区域明确创建共享内存区域,
但不推荐这样做。
-
特权模式任务可以将自身设置为非特权模式,不过一旦进入非特权模式,
就无法再设置回特权模式。
-
FreeRTOS 的 API 位于闪存中的一个区域,
只有在微控制器处于特权模式时才能访问(调用 API 函数会暂时切换到特权模式)。
-
由 RTOS 内核维护的数据(所有 FreeRTOS 源文件专有的非堆栈数据)
位于 RAM 中的一个区域,只有在微控制器处于特权模式时才能访问
。
-
只能在微控制器处于特权模式时可访问系统外围设备。 标准
外围设备(UART 等)可被任何代码访问,
但可以使用用户可定义的内存区域进行明确保护。
创建任务
FreeRTOS-MPU 移植可以有两种类型的任务:
-
特权任务:特权任务可以访问整个内存映射。
特权任务可通过使用 xTaskCreate()
或 xTaskCreateRestricted() API 函数创建。
-
非特权任务:非特权任务只能访问其堆栈。此外,
还可以授予它最多三个用户可定义内存区域的访问权限(每个任务三个)
。非特权任务只能使用
xTaskCreateRestricted() API 创建。
请注意,请勿使用 xTaskCreate() API 创建
非特权任务。
如果任务想要使用 MPU,则必须提供以下附加信息:
- 任务堆栈的地址。
- 最多三个用户可定义内存区域的起始参数、大小参数和访问参数。
因此,创建任务所需的参数总数相当大。 为了轻松创建
MPU 感知任务,FreeRTOS-MPU 会使用一个叫做
xTaskCreateRestricted() 的 API 函数。
这使得除一个参数外的所有参数都被定义在一个常量结构体中,
其中结构体作为单个参数传递 (通过引用)到 xTaskCreateRestricted() 中。
特权模式任务可以通过调用
portSWITCH_TO_USER_MODE() 以
将自身设置为非特权模式。 在非特权模式中运行的任务无法将自身设置为特权模式
。
可使用
vTaskAllocateMPURegions() 更改分配给任务的内存区域。 更多详情,
请参阅 xTaskCreateRestricted() 和 vTaskAllocateMPURegions() API 文档。
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.