从零到一:Linux内核MMU启动与虚拟内存体系建立全流程详解



从零到一:Linux内核MMU启动与虚拟内存体系建立全流程详解

作者:嵌入式Jerry

📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统
🎥 更多学习视频请关注 B 站:嵌入式Jerry


一、什么是MMU与虚拟内存?(原理入门)

1.1 MMU(Memory Management Unit)

  • MMU 是CPU内存管理单元,作用是把“进程/内核看到的虚拟地址”映射到真实的物理内存地址。
  • 只有开启MMU,才能实现“虚拟内存”、“内存保护”、“多进程隔离”等高级特性。

1.2 虚拟内存

  • “虚拟内存”指每个进程、内核都看到独立的虚拟地址空间,但底层映射到同一套物理内存,由MMU+操作系统动态维护和转换。
  • 优势:简化编程、提升安全性、支持内存隔离和扩展。

在这里插入图片描述

二、MMU/虚拟内存是在什么时候建立的?

2.1 不是Bootloader/SPL阶段

  • Bootloader(如U-Boot)、SPL 仅负责加载内核到内存,地址一般是物理地址,不启用MMU

2.2 内核启动阶段才建立

  • 内核被加载到RAM后,体系结构相关启动汇编(head.S)负责建立初步页表、设置相关寄存器,并启动MMU,真正切换到虚拟地址空间。
  • 随后跳转到 start_kernel(),内核和所有后续代码都运行在虚拟地址空间。

三、启动流程总览(以ARM/ARM64为例)

  1. SPL/Bootloader

    • 加载内核到RAM的某个物理地址,不启用MMU。
  2. 内核启动汇编(head.S)

    • 建立最基础的页表(identity mapping/映射内核空间)。
    • 设置TTBR、DACR、SCTLR等MMU关键寄存器。
    • 执行汇编指令开启MMU。
    • 跳转到虚拟地址空间下的C入口——start_kernel()
  3. start_kernel()

    • 内核开始各子系统的初始化,正式使用虚拟地址、支持多进程和内核空间隔离。

四、核心代码详解(以ARM为例)

4.1 head.S 源码关键片段讲解

文件位置:arch/arm/kernel/head.S(32位),arch/arm64/kernel/head.S(64位)

4.1.1 建立初步页表(节选伪码)
bl  create_idmap_page_table     // 建立物理-虚拟一一映射
bl  enable_mmu                  // 使能MMU(见下文)
adrp    x0, __start_kernel
br      x0                      // 跳转到C语言主入口
4.1.2 enable_mmu/ __turn_mmu_on 解释
// 伪码节选
__enable_mmu:
    // 配置对齐、缓存、页表等
    mcr p15, 0, r4, c2, c0, 0  // 设置TTBR0,页表基址
    mcr p15, 0, r5, c3, c0, 0  // 设置DACR
    b __turn_mmu_on

ENTRY(__turn_mmu_on)
    mcr p15, 0, r0, c1, c0, 0  // 写入SCTLR控制寄存器,M位=1打开MMU
    // ... 汇编不可再跟踪 ...
    br r13                      // 跳转到start_kernel的虚拟地址
重点解释:
  • TTBR(Translation Table Base Register):页表基址寄存器,告诉MMU去哪里查虚拟地址到物理地址的映射关系。
  • DACR(Domain Access Control Register):域访问权限。
  • SCTLR(System Control Register):控制MMU开关(M位=1)。
  • br r13:切换到虚拟地址空间下的C语言主入口。

4.2 start_kernel()后的虚拟内存使用

  • start_kernel()开始,内核所有C代码都用虚拟地址
    例如全局变量、函数栈、模块装载、进程地址空间、内核空间、用户空间等都已按虚拟内存体系分区。
  • 用户进程创建时,系统为每个进程分配独立的虚拟地址空间,MMU确保互不干扰。

五、用户空间与内核空间如何建立?(虚拟内存分区)

5.1 地址空间划分

  • 用户空间:每个进程独有的03GB(32位)/0128TB(64位)虚拟空间。
  • 内核空间:所有进程共享的高地址部分(如3GB~4GB),只内核态可访问。

不同架构划分细节略有差异,但本质一样:MMU+内核页表实现空间隔离、保护与资源管理

5.2 虚拟地址到物理地址映射

  • 通过页表维护虚拟页 → 物理页关系,支持按需分配、内存保护、页交换(swap)。
  • 用户进程和内核空间的页表映射相互隔离(部分特殊区域有共享/映射需求,如内核的高端映射区)。

六、易混/常见问题解析

  1. 虚拟内存不是物理内存大,MMU是关键硬件支撑,依赖于OS建立页表。
  2. MMU启动在内核启动早期完成,C代码的主入口(start_kernel)之前,汇编完成。
  3. 内核空间和用户空间的虚拟地址,虽然在每个进程中都能访问到,但映射到的物理内存和访问权限完全不同。
  4. 不同平台head.S实现细节不同,但基本原理一致。
  5. 没有MMU和虚拟内存,系统无法安全支持多进程、内存保护、用户/内核隔离。

七、项目中常见场景与技术盲区

  • 驱动开发中误用物理/虚拟地址,导致DMA出错、无法访问用户空间内存。
  • 启动优化时,误以为bootloader/SPL已建虚拟内存,实际要等内核完成MMU初始化才可用。
  • 调试时看到C语言启动堆栈地址很高,本质是虚拟内存空间下的映射,不等于物理RAM。
  • 移植新平台时,head.S和页表初始化经常是适配难点。

八、一句话总结

MMU启动和虚拟内存体系的建立,是Linux多进程隔离、安全、稳定运行的基石。它是在内核启动早期由架构汇编代码(head.S)完成,start_kernel()起,所有代码都在虚拟空间下运行。彻底理解流程、机制和实现细节,是嵌入式、驱动、内核工程师不可或缺的基本功!


喜欢本文,欢迎收藏、点赞、关注“嵌入式Jerry”。更多内核、虚拟内存与驱动开发干货持续更新!
京东正版推荐:《Yocto项目实战教程》 https://item.jd.com/15020438.html


### 如何在 Windows 系统中安装 PythonQt Designer 并配置环境 #### 安装 PyQt6 和 Qt Designer 为了在 Windows 上使用 Qt Designer,可以通过 `pip` 命令安装最新的 PyQt6 模块。PyQt6 是一个用于创建图形用户界面 (GUI) 应用程序的工具包,并附带了 Qt Designer 工具。 运行以下命令可以完成 PyQt6 及其相关组件的安装: ```bash pip install pyqt6-tools ``` 此命令会自动下载并安装必要的依赖项,其中包括 Qt Designer[^1]。 #### 配置路径以便访问 Qt Designer 安装完成后,通常可以在以下目录找到 Qt Designer 文件(具体位置取决于 Python 解释器的位置): - **对于标准安装**:`C:\Users\<用户名>\AppData\Local\Programs\Python\<版本号>\Lib\site-packages\pyqt6_tools` - 或者通过脚本启动:`python -m pyqt6_designer`. 如果希望直接从文件资源管理器或桌面快捷方式打开 Qt Designer,则需将其可执行文件所在路径添加到系统的环境变量 PATH 中。操作方法如下: 1. 打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设置。 2. 单击“环境变量”,在“系统变量”部分找到名为 “Path”的条目并编辑它。 3. 添加上述提到的设计工具所在的完整路径至列表末尾。 这样处理之后,在任意 CMD 终端窗口输入 designer.exe 就能调用该应用程序。 #### 测试安装成功与否 验证是否正确设置了所有内容的一个简单办法就是尝试加载设计模式本身或者利用 PyQT 创建一个小项目来看看能否正常渲染 UI 元素。下面给出一段简单的例子展示如何载入由设计师保存下来的 .ui 文件并通过 python 运行起来: ```python from PyQt6 import uic import sys from PyQt6.QtWidgets import QApplication, QMainWindow class MyUI(QMainWindow): def __init__(self): super(MyUI,self).__init__() # 加载 ui 文件 uic.loadUi('your_ui_file.ui', self) if __name__ == '__main__': app = QApplication(sys.argv) window = MyUI() window.show() try: sys.exit(app.exec()) except SystemExit: pass ``` 以上代码片段假设存在一个叫做 'your_ui_file.ui' 的文件位于当前工作目录下,它是之前通过 Qt Designer 构建出来的界面布局定义文档。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值