下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

使用内存保护单元的好处

目前你用来阅读这篇文章的设备依赖处理器的内存管理单元 (MMU) 对每个运行中的应用程序执行沙箱处理。如果用户设备不具备防止错误访问甚至恶意访问错误内存的能力(无论是操作系统数据还是其他任务数据),则用户设备将成为漏洞和安全漏洞的雷区。

涉及嵌入式项目时,您所用的内存保护单元 (MPU) 可以提供许多同等优势。通过MPU,用户通常可以特权模式或非特权模式运行,并使用一组“区域”来确定当前执行的代码是否有权限访问代码和数据。每个区域都是一个连续的内存块,具有该内存的一组权限;既有特权访问权限,也有非特权访问权限。特权代码通常可访问设备的大部分(如果并非全部)内存,而非特权代码则只能访问小得多的子集。

这些区域在应用程序的整个运行期间不必相同。MPU可以根据每项任务修改区域;当任务变为运行状态时,每个任务都可配置其独特的区域集。这允许您只授权有需要的任务访问代码和数据。在每次上下文切换期间,使用 MPU 的嵌入式操作系统将对各任务的区域和特权级别进行管理。

全局区域和任务 MPU 区域示例

图 1:全局区域和任务 MPU 区域示例。 点击放大。

图 1 显示了两个不同任务在使用 MPU 时如何查看系统内存。共有两个全局 MPU 区域,其中一个在闪存开始时,另一个在 RAM 开始时。任务 1 获授权执行访问任务 2 无法访问的部分闪存代码。相反,任务2则获授权执行访问闪存内的不同代码集。如果任务 1 试图在此处执行任务 2 的任何代码,则会生成 MPU 错误,反之亦然。

虽然任务 1 和任务 2 均含有 MPU 覆盖 RAM 中相同内存范围的区域,但二者并未获得相同权限。任务 1 只能读取区域内的数据,而任务 2 可以读取和写入。在任务 2 作为特定数据源而任务 1 使用这些数据但绝无数据修改权限的情境中,这种方式可能行之有效。

FreeRTOS 在其多个 ARM Cortex 端口(M3、M4、M23 和 M33)以及其 Aurix Tricore 和 Xtensa ESP32 端口中提供 MPU 支持。与 FreeRTOS 类似的安全关键系统 SAFE RTOS 在所有可用的平台上都支持 MPU。

为什么使用 MPU?

在嵌入式项目中使用 MPU 可降低顿挫感、省时省钱。对于开发人员而言,MPU 的最大好处在于开发初期便能够捕获漏洞。及早发现漏洞可显著缩短开发时间。在项目后期修复代码漏洞可以减少文档及测试代码所需的返工。另一方面,尽早修复漏洞将减少项目后期阶段代码中的错误数量。由于不太可能同时存在多个漏洞,所以此举将简化识别修复剩余漏洞的过程。这样帮助您把握和跟上进度,防止发生意外延误。

MPU 是如何实现这一点的?保护与当前执行代码无关联的所有数据是最为行之有效的方法。可以仅使用两个 RTOS 任务(任务 A 和任务 B)来举一个简单的例子。任务 A 和任务 B 不应彼此交互,但存在一个漏洞 ,其中任务 A 可能意外写入任务 B 偶尔使用的某些数据。覆盖此数据对任务 A 的正确操作无影响。但任务 B 尝试使用损坏的数据时,任务 B 可能出现异常故障。如果并未配置 MPU 来防止任务 A 写入任务 B 的数据 ,则开发人员可能需要很长时间才能跟踪到此错误。如果该错误细微不易察觉,或者任务 B 很少使用该数据,那么这一问题将会极难解决。但如果使用 MPU ,错误写入操作即刻出现异常,进而可以确定哪一行代码导致故障。

由于用户可以设置 MPU 区域,防止非特权代码访问 0x0 内存,因此, MPU 甚至可以在某些架构上帮助用户检测空指针偏移。

在您的应用程序中,一组设计良好的 MPU 区域可以显式保护重要的内存区域,以防止特定的问题。例如将缓冲区定位在 MPU 区域的末端来防止缓冲区溢出。用户还可以将任务栈放置在任何非特权代码无法访问的区域。设置完成后,每个任务必须使用它们自己的某个 MPU 区域,明确通过自行授权获得对其堆栈的访问权限。如果使用 MPU,用户须真正思考应用程序的结构,以便在任务之间明确分离数据,形成稳健性强且可维护的代码库。

何时不必使用 MPU?

以下两种情况下, 您不会在处理器上使用MPU :简单项目和性能关键项目。第一种情况比较直观:使用 MPU 复杂性增加,可能不利于极简应用程序。您无需设置覆盖您的闪存、RAM 和外围设备的 MPU 区域,您的 blinky 演示也可能成功。

如果用户需要处理器中的各项性能发挥到极致,那么因使用 MPU 而产生的系统开销,可能会影响用户使用。由于每项任务均需要多个待编程的 MPU 区域,因此,MPU 的 FreeRTOS 端口中的任务上下文切换例程更长。当正在切换上下文时,RTOS 必须对各项任务 MPU 区域进行编程,同时执行例如堆叠使用过的寄存器等常规任务。此外,由于内核代码和数据受 MPU 保护,因此所有内核函数调用均须受包装函数保护。此包装函数仅在调用内核函数之前,提高处理器的权限级别,随即还原权限并返回。这一过程不仅会增加运行代码所需时间,还可能增加任务所需堆栈大小。任务的控制块还须在其 MPU 区域存储信息,并且在某些安全关键 RTOS 的情况下例如 SAFERTOS,则也将存储此数据的镜像。

用户还应注意,使用 MPU 可能会比较难,有时甚至会令人很沮丧。应用程序设计需要更多时间,因为设计人员必须为每项任务考虑 MPU 区域。这些区域中的错误(例如区域长度不正确、权限不正确或未正确链接应用程序的数据)可能会令调试变得困难。

了解有关 MPU 使用方法的更多信息

虽然短期内学习使用 MPU 可能困难重重,并且在用户代码中添加了少量虚耗,但这些优势较为明显。FreeRTOS 在 ARMv7-M(Cortex-M3、Cortex-M4 和 Cortex-M7 微控制器)和 ARMv8-M(Cortex-M23 和 Cortex-M33 微控制器)核心上提供官方 MPU 支持。请参阅更多有关 FreeRTOS 内存保护支持 的信息。

如欲了解有关 MPU 的更多信息,WITTENSTEIN 高完整性系统通过其 YouTube 频道,提供极有帮助的 “内存保护”应用说明以及丰富的辅助视频

本博客由 WITTENSTEIN 高完整性系统 SAFERTOS 项目工程师供稿。SAFE RTOS 是一个安全关键的预先认证的实时操作系统,与 FreeRTOS 共享功能模型。您可访问 SAFERTOS 查阅各类白皮书,包括如何从 FreeRTOS 升级到 SAFERTOS 的详细示例。

标签

内存保护单元 mpu Safertos

作者简介

Adam Lewis 是 WITTENSTEIN 高完整性系统 SAFERTOS®开发团队的嵌入式工程师。
查看此作者的文章
FreeRTOS 论坛 获得来自专家的行业领先支持,并与全球同行合作。 查看论坛
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.