当前位置: 首页 > web >正文

从零到一: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  // 设置DACRb __turn_mmu_onENTRY(__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


http://www.xdnf.cn/news/16902.html

相关文章:

  • gitlab+jenkins的ci/cd部署
  • win11 命令禁用客户体验改善计划
  • 区块链概述
  • 云计算k8s集群部署配置问题总结
  • ARM Cortex-M 处理器的应用
  • Hive SQL (HQL) 编辑指南
  • vscode cursor配置php的debug,docker里面debug
  • 20250801在Ubuntu24.04.2LTS下编译firefly_itx_3588j的Android12时解决boot.img过大的问题
  • django的数据库原生操作sql
  • PHP在现代Web开发中的应用与优势分析
  • ACS-电机控制Buffer-任意路径规划(PVSPLINE绘制圆形)
  • OCC任务新SOTA!华科提出SDGOCC:语义深度双引导的3D占用预测框架(CVPR 2025)
  • Shader开发(六)什么是着色器
  • SQL数据库连接Python实战:疫情数据指挥中心搭建指南
  • STM32 使用 RTC 实现实时时钟功能
  • 【BFS】P7555 [USACO21OPEN] Maze Tac Toe S|普及+
  • Java Map和Set
  • Redis 初识Redis
  • 校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档)
  • 逻辑回归在银行贷款审批中的应用:参数选择与实践
  • 《人形机器人的觉醒:技术革命与碳基未来》——类人关节设计:柔性驱动革命之液压人工肌肉
  • 【C#学习Day14笔记】泛型、集合(数组列表Arraylist、列表list)与字典
  • 利用 AI 在 iPhone 上实现 App 文本情绪价值评估(上)
  • 数据结构学习基础和从包装类缓存到泛型擦除的避坑指南
  • 九联UNT403HS_海思MV320处理器_安卓9-优盘强刷刷机包
  • 代码随想录算法训练营第三十八天
  • 【机器学习与数据挖掘实战 | 医疗】案例20:基于交叉验证和LightGBM算法的糖尿病遗传风险预测
  • 数据结构 ArrayList与顺序表
  • SELinux 核心概念与访问控制机制解析
  • conda issue