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

从零到一: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.dtcms.com/a/310741.html

相关文章:

  • 代码随想录算法训练营三十三天|动态规划part06
  • [Linux入门] Linux 防火墙技术入门:从 iptables 到 nftables
  • 一文了解 `package.json` 和 `package-lock.json`文件
  • Mysql group by
  • 查看主板信息的3种方法
  • 修改DeepSeek翻译得不对的V语言字符串文本排序程序
  • 【ESP32 IDF】LVGL驱动触摸屏
  • AI Agent 视角:可执行程序的二进制格式,是一场「结构化语言」与「智能解析」的双向奔赴
  • 知识图谱的学习
  • 脚本统计MongoDB集合表数据量
  • 思途JSP学习 0801
  • 函数 dirfd 详解
  • 26考研|高等代数:欧几里得空间
  • TwinCAT3示例项目1
  • Redis学习18-分布式锁
  • 深拷贝与浅拷贝的定义
  • 机器学习特征工程----常见的特征构建与转换方法
  • dify 升级1.7.1 插件无法下载依赖
  • 分区管控与高效协同:EtherCAT转EtherCAT网关赋能纺织生产
  • c++-reverse_iterator
  • 什么是 Redis?从基础概念到技术本质的全面解析
  • 微信小程序页面间通信的实现方式
  • 升级的MS1836C HD转CVBS/S-Video转换器
  • WooCommerce 与 ERP 系统集成解决方案
  • Agents-SDK智能体开发[1]之入门
  • 智能客服系统实战:多轮对话与知识库检索完整实现
  • DL环境捉虫
  • Python从入门到精通——第四章 程序流程控制
  • 第五届智能通信与计算国际学术会议(ICICC 2025)
  • 电子合同管理台账功能详解