news 2026/4/18 15:53:23

直接映射区的 MMU 处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
直接映射区的 MMU 处理

在讲解 MMU 处理逻辑前,先理清两个基础概念:

  • 直接映射区:内核将物理内存的前半部分(通常是0~896MB,即ZONE_DMA+ZONE_NORMAL)直接映射到虚拟地址空间的PAGE_OFFSET(x86 下是0xC0000000,ARM64 下是0xFFFF000000000000)开始的区域,物理地址和虚拟地址满足虚拟地址 = 物理地址 + PAGE_OFFSET
  • MMU 的核心作用:硬件层面完成虚拟地址 → 物理地址的转换,依赖页表(Page Table)实现,直接映射区的核心是让 MMU 能通过 “固定偏移” 的页表快速完成地址转换。

内核启动:构建直接映射区的页表

内核在start_kernel()之前的汇编 / 初始化阶段,会为直接映射区构建多级页表(x86_64 是 4 级:P4D→PUD→PMD→PTE;ARM64 是 4/5 级);

关键细节

  • 直接映射区的页表项(PTE)是静态构建的,物理地址和虚拟地址的偏移是固定值(PAGE_OFFSET),因此页表项的物理地址部分只需 “物理页框号(PFN)” 即可,无需动态计算。
  • 页表项的属性位(MMU 关注的核心):
    • PTE_P(Present):标记页有效,MMU 可访问;
    • PTE_RW(Read/Write):内核态可读写;
    • PTE_US(User/Supervisor):仅内核态可访问(用户态不可见);
    • PTE_PCD/PTE_PWT:缓存属性(直接映射区默认开启缓存,提升访问效率)。

MMU 必须遍历页表(硬件层面的硬性规则)

MMU 是硬件单元,它的核心工作机制就是通过遍历多级页表完成虚拟地址到物理地址的转换,这是 x86/ARM64 等架构的硬性规则,不会因为 “地址有固定偏移” 而改变:

  • 即使你知道直接映射区的 VA 和 PA 满足PA = VA - PAGE_OFFSET(软件层面的计算),但 MMU 硬件无法识别这个逻辑,它只能严格按照页表的索引规则去查找物理地址。
  • 举个通俗例子:你知道 “100 号房间 = 1 号楼层 + 99”,但酒店的门禁系统(MMU)不会认这个公式,必须刷房卡(查页表)才能开门。

为什么 “看起来像没遍历页表”?

你之所以会有这个疑问,本质是内核做了两层关键优化,让 “页表遍历” 的开销几乎可以忽略,甚至在软件层面能绕开遍历:

1. 硬件层面:TLB(快表)缓存页表转换结果

MMU 内置了 TLB(Translation Lookaside Buffer),这是页表转换结果的高速缓存:

  • 第一次访问直接映射区的某个虚拟地址时,MMU 会遍历页表完成转换,并将 “VA→PA” 的映射结果缓存到 TLB 中。
  • 后续访问同一段地址(或相邻地址)时,MMU 直接从 TLB 中读取转换结果,无需再次遍历页表(TLB 访问耗时仅 1~2 个时钟周期,远快于遍历多级页表)。
  • 直接映射区是内核最常访问的内存区域,TLB 命中率极高,因此实际的页表遍历操作极少发生。

2. 软件层面:直接地址计算(绕开 MMU 遍历)

内核代码中,经常直接用__pa(virt_addr)__va(phys_addr)宏计算地址,而不是依赖 MMU 的页表遍历:

// 示例:软件层面直接计算地址,无需触发MMU页表遍历 unsigned long virt_addr = (unsigned long)kmalloc(4096, GFP_KERNEL); phys_addr_t phys_addr = __pa(virt_addr); // 直接计算:phys_addr = virt_addr - PAGE_OFFSET // 反向计算 unsigned long virt_addr2 = __va(phys_addr); // virt_addr2 = phys_addr + PAGE_OFFSET
  • 这种方式仅适用于直接映射区(0~896MB 物理内存),因为只有这部分内存满足 “固定偏移” 规则。
  • 对于高端内存(>896MB),内核无法直接计算,必须通过 Fixmap/kmap 等机制构建页表,让 MMU 遍历页表完成转换。

大页映射:减少页表遍历的层级

内核会将直接映射区的连续物理内存映射为大页(如 x86_64 的 2MB/1GB 页):

  • 普通 4KB 页需要遍历 4 级页表(P4D→PUD→PMD→PTE);
  • 1GB 大页只需遍历 1 级页表(P4D)即可找到物理地址,大幅减少 MMU 遍历的层级和耗时。
  • 大页还能减少 TLB 缓存的条目数,提升 TLB 命中率(比如 1GB 大页只需 1 个 TLB 条目,而 4KB 页需要 262144 个)。

直观对比:直接映射区的地址转换流程

场景MMU 行为开销
首次访问某虚拟地址遍历多级页表 → 缓存到 TLB较高(单次)
后续访问同虚拟地址直接查 TLB → 无需遍历页表极低
软件层面计算地址完全绕开 MMU,直接通过偏移计算
大页映射的地址访问遍历更少层级的页表 → 缓存到 TLB较低

关键宏 / 函数(辅助 MMU 处理直接映射区)

宏 / 函数作用
__va(phys_addr)物理地址转直接映射区虚拟地址(VA = PA + PAGE_OFFSET
__pa(virt_addr)直接映射区虚拟地址转物理地址(PA = VA - PAGE_OFFSET
pgd_offset_k()获取内核虚拟地址对应的 PGD(页全局目录)项地址
flush_tlb_all()刷新 MMU 的 TLB(快表),确保页表修改生效

总结

  1. 硬件层面:MMU 访问直接映射区时必须遍历页表(这是 MMU 的核心工作机制),但 TLB 会缓存转换结果,让后续访问无需遍历。
  2. 软件层面:内核可通过__pa/__va宏直接计算地址,绕开 MMU 的页表遍历(仅适用于直接映射区)。
  3. 优化手段:大页映射减少页表遍历层级、TLB 提升缓存命中率,让直接映射区的 MMU 处理开销几乎可以忽略。
  4. 内核通过大页、地址宏(__va/__pa)等优化手段,降低 MMU 地址转换的开销,提升直接映射区的访问效率。
  5. 直接映射区的页表属性默认开启缓存、仅内核可访问,MMU 依赖页表项的权限位控制地址访问的合法性。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 21:02:01

计算机Java毕设实战-基于SpringBoot的微企业人事管理系统基于springboot的企业人事管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/4/18 8:37:23

GoReSym技术揭秘:二进制解析与符号提取实战指南

GoReSym技术揭秘:二进制解析与符号提取实战指南 【免费下载链接】GoReSym Go symbol recovery tool 项目地址: https://gitcode.com/gh_mirrors/go/GoReSym 在软件开发与逆向分析领域,如何高效提取二进制文件中的关键元数据一直是技术难点。GoReS…

作者头像 李华
网站建设 2026/4/18 8:35:35

数字炼金术:币圈项目包装的造神狂欢与价值祛魅

引言:当代码成为新的魔法书 在区块链的狂想曲中,项目包装早已超越技术范畴,演变为一场融合心理学、行为经济学与叙事艺术的数字炼金术。有人用23页白皮书虚构“下一代互联网基础设施”,募资5000ETH;有人通过伪造NASA气…

作者头像 李华
网站建设 2026/4/18 8:29:37

1.4 Agent的眼睛耳朵 语言与多模态怎么喂信息

1.4 Agent 的「眼睛耳朵」:语言 + 多模态怎么喂信息 本节学习目标 理解 Agent 如何通过「感知」获取环境信息,并区分不同感知渠道。 掌握文本、语音、图像等多模态输入在 Agent 中的角色与常见用法。 能设计「把环境信息整理成模型可用的输入」的简单方案。 一、感知在 Agen…

作者头像 李华