❄️ 我的个人专栏: 
《智能软件工程AI4SE》
《嵌入式面试总结》
《嵌入式处理器架构解析》
《嵌入式与虚拟化》
《嵌入式软件测试》
🌟 Simplicity is the ultimate sophistication

摘要:本文从硬件结构、工作机制、功能差异和应用场景四个维度,对 MMU 与 MPU 进行深度对比。MMU 负责虚拟地址到物理地址的转换,以页为粒度提供细粒度保护,并支持缺页机制,是 Linux 等复杂操作系统的硬件基础;MPU 仅提供确定性的区域级内存保护,适合实时控制和功能安全场景。文章还解释了 Linux 运行在 MCU 上的原理,包括 uClinux 变体以及现代高端 MCU 集成 MMU 或采用异构多核架构的方案,并给出了实际项目选型建议。

1. 引言

在嵌入式开发中,MMU(Memory Management Unit,内存管理单元)和 MPU(Memory Protection Unit,内存保护单元)是两个经常被提及但又容易混淆的概念。很多开发者会有这样的疑问:同样是做内存保护,为什么有的芯片用 MMU,有的芯片用 MPU?为什么 Linux 通常跑在带 MMU 的处理器上,而现在一些 MCU 也能跑 Linux?

本文将从硬件结构、工作机制、功能差异和应用场景四个维度,对 MMU 与 MPU 进行深度对比,并解释 Linux 运行在 MCU 上究竟依赖什么。

2. 基本概念

2.1 什么是 MMU

MMU 是位于 CPU 和物理内存之间的硬件单元,负责完成虚拟地址到物理地址的转换,并在此基础上提供内存访问权限控制。MMU 的核心组件包括页表(Page Table)、TLB(Translation Lookaside Buffer,转换后备缓冲器)以及页表遍历逻辑。

MMU 以页(Page)为粒度管理内存,常见页大小为 4KB、16KB 或 64KB。操作系统通过维护页表,为每个进程建立独立的虚拟地址空间,从而实现进程间内存隔离和按需分页。

2.2 什么是 MPU

MPU 是一种相对简单的内存保护硬件,它不负责地址转换,只负责检查 CPU 发出的每个访问请求是否落在允许的地址区域内。MPU 以区域(Region)为粒度进行配置,每个区域由起始地址、长度和访问权限属性组成。

MPU 通常出现在不带 MMU 的 MCU 上,例如 ARM Cortex-M 系列处理器。它提供的是保护能力,而不是地址映射能力。

3. 工作机制对比

3.1 地址转换能力

MMU 最核心的功能是地址转换。CPU 发出的虚拟地址经过 MMU 查询页表后,转换为物理地址再访问内存。这一机制带来了三个关键能力:

  • 虚拟地址空间扩展:物理内存有限时,可以通过磁盘或 Flash 交换页,使进程看到比物理内存更大的地址空间。
  • 进程隔离:每个进程拥有独立的虚拟地址空间,进程 A 无法直接访问进程 B 的物理内存。
  • 内存共享与重定位:同一物理页可以映射到多个虚拟地址,方便共享库和内存映射文件。

MPU 不具备地址转换能力。CPU 发出的地址就是物理地址,MPU 只负责检查该地址是否落在已配置的合法区域内,以及访问类型(读、写、执行)是否被允许。

3.2 保护粒度

MMU 的保护粒度是页,通常为 4KB。操作系统可以针对每一页设置独立的权限属性,粒度非常细。例如,代码段所在的页可以设置为只读可执行,数据段所在的页设置为可读写但不可执行。

MPU 的保护粒度是区域,区域大小通常要求是 2 的幂次,且对齐到区域大小。一个典型的 Cortex-M 处理器支持 8 到 16 个 MPU 区域,每个区域可以覆盖从 32 字节到 4GB 的范围。由于区域数量有限,MPU 的保护粒度通常比 MMU 粗。

3.3 缺页处理

MMU 支持缺页异常机制。当进程访问的虚拟页尚未映射到物理内存时,MMU 触发缺页异常,操作系统在异常处理程序中从磁盘或 Flash 加载对应页,并更新页表后重新执行指令。这是虚拟内存和按需分页的基础。

MPU 不支持缺页机制。MPU 区域在系统初始化时静态配置,运行过程中一般不会动态调整。访问未配置区域或越权访问时,MPU 直接触发硬件异常(如 HardFault),由异常处理程序决定如何处理。

4. 硬件开销与实时性

4.1 硬件复杂度

MMU 需要维护页表、TLB 和遍历逻辑,硬件复杂度显著高于 MPU。页表本身占用内存,TLB 未命中时还需要硬件遍历多级页表,这会引入额外的访问延迟。

MPU 硬件结构简单,只需要一组区域比较器即可实现。它不占用额外内存,也不存在 TLB 未命中的问题,访问延迟几乎可以忽略。

4.2 实时性影响

对于硬实时系统,MMU 的 TLB 未命中和缺页处理会带来不可预测的延迟,这是实时操作系统(RTOS)通常避免使用 MMU 的原因之一。即使使用 MMU,也需要通过页表锁定(Page Table Locking)等方式减少不确定性。

MPU 的访问检查是确定性的,每次访问都在固定周期内完成,不会产生额外延迟,因此非常适合硬实时场景。这也是 Cortex-M 系列 MCU 普遍集成 MPU 而非 MMU 的重要原因。

5. 功能对比总结

对比维度MMUMPU
地址转换支持虚拟地址到物理地址转换不支持,直接使用物理地址
保护粒度页,通常 4KB区域,2 的幂次大小
区域数量由页表项决定,数量大通常 8 到 16 个
缺页机制支持,可触发缺页异常不支持
硬件复杂度高,需要页表和 TLB低,仅需区域比较器
访问延迟TLB 未命中时延迟增大确定性延迟
典型应用Linux、Android、应用处理器RTOS、MCU、功能安全场景

6. Linux 跑在 MCU 上靠的是什么

6.1 Linux 对 MMU 的依赖

Linux 内核在设计上深度依赖 MMU 提供的虚拟内存机制。进程地址空间隔离、写时复制(Copy-on-Write)、内存映射文件、按需分页等核心功能都建立在 MMU 之上。没有 MMU,Linux 的进程模型和内存管理模型将无法正常工作。

因此,传统观点认为 Linux 只能运行在带 MMU 的处理器上。早期的 ARM 应用处理器(如 Cortex-A 系列)都集成了 MMU,而 Cortex-M 系列 MCU 只有 MPU,无法运行标准 Linux。

6.2 无 MMU 的 Linux 变体

实际上,Linux 内核有一个针对无 MMU 处理器的变体,称为 uClinux(Micro Controller Linux)。uClinux 去掉了对虚拟内存的依赖,所有进程共享同一个物理地址空间,进程间通过内存保护区域(MPU)进行隔离。

uClinux 可以运行在带 MPU 的 MCU 上,但存在一些限制:

  • 没有独立的虚拟地址空间,进程间隔离能力较弱。
  • 无法使用写时复制,fork 的实现方式不同。
  • 内存碎片管理更复杂,需要特殊的内存分配策略。

6.3 现代 MCU 上的 Linux 方案

近年来,随着 MCU 性能的提升,一些高端 MCU 开始集成 MMU。例如,部分 Cortex-M55 和 Cortex-M85 系列处理器通过可选配置支持 MMU,或者通过协处理器方式提供地址转换能力。这使得在这些 MCU 上运行标准 Linux 成为可能。

此外,还有一种常见方案是异构多核架构:在一个芯片上同时集成 Cortex-A 核(带 MMU,运行 Linux)和 Cortex-M 核(带 MPU,运行 RTOS)。两者通过共享内存和核间通信机制协作,兼顾复杂应用和实时控制的需求。

7. 选型建议

在实际项目选型时,可以从以下几个角度判断该选 MMU 还是 MPU:

  • 是否需要运行 Linux 或大型操作系统:需要则必须选带 MMU 的处理器。
  • 是否对实时性有硬性要求:硬实时场景优先选择带 MPU 的 MCU,避免 MMU 带来的不确定性。
  • 是否需要进程级内存隔离:多进程复杂应用需要 MMU,单进程裸机或 RTOS 场景用 MPU 即可。
  • 成本和功耗约束:MMU 硬件复杂度高,成本和功耗通常高于 MPU。

8. 总结

MMU 和 MPU 虽然都涉及内存保护,但设计目标和实现机制截然不同。MMU 提供虚拟地址转换和细粒度页级保护,是 Linux 等复杂操作系统的硬件基础;MPU 提供简单确定性的区域保护,适合实时控制和功能安全场景。

Linux 跑在 MCU 上,本质上取决于 MCU 是否具备 MMU 或是否接受 uClinux 的受限模型。随着嵌入式处理器的发展,MMU 与 MPU 的边界正在逐渐模糊,未来将出现更多兼顾虚拟内存和实时性的混合方案。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐