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

phys_pud_init、phys_pmd_init、phys_pte_init

phys_pud_init

phys_pud_init是 x86 架构 Linux 内核中,负责在 PUD(Page Upper Directory,页上级目录)层级填充页表项的核心函数,其实现原理是一套精密的内存映射“流水线”。

它的工作,可以看作是在__kernel_physical_mapping_init的统筹下,作为“分包商”承接并处理一个具体的物理地址区间,为其建立或更新内存映射。

核心实现逻辑:分层填充

该函数从虚拟地址的角度出发,遍历指定 PUD 页表中的每一个条目,为每一个需要映射的物理地址范围选择最高效的方式建立映射。

关键设计演进与细节

  1. 引入init参数phys_pud_init新增了init参数,用于在启动早期内存热插拔等运行时场景之间进行区分。这允许内核在修改页表时,根据场景选择不同的同步策略,例如避免在启动初期进行耗时操作或改变锁的使用方式。

  2. 1GB 大页拆分时的 Bug 修复:当函数需要将一个已存在的 1GB 大页拆分为 2MB 小页时,会触发一个警告。原因是拆分前未清除旧的 PUD 条目,而后续的set_pud_safe()函数会检测到冲突并报出WARN_ON_ONCE。修复方法是在拆分前增加pud_clear(pud)调用,清除旧的大页映射条目,使新的 PMD 页表能顺利链接。

  3. KASLR 支持:在内核地址空间随机化(KASLR)引入时,phys_pud_init曾被修正。由于 KASLR 使得PAGE_OFFSET不再是 PUD 对齐的,原先直接对物理地址使用pud_index的逻辑会失效。修正方法是在计算 PUD 索引前,先将物理地址通过__va转换为虚拟地址,以确保pud_index总能得到正确的结果。

异常处理与内存空洞

函数内部还会检查区间内是否存在内存空洞(非 RAM 区域)。若检测到,它会清除对应的 PUD 条目,保证映射的精确性,防止内核访问到不应映射的物理地址。

phys_pmd_init

phys_pmd_init是 x86 架构 Linux 内核在启动阶段,负责在PMD(页中间目录)层级建立物理内存直接映射的核心函数。它的作用可以看作是前序phys_pud_init工作的“分包商”,专门处理一个具体的物理地址区间,并决策使用2MB 大页还是4KB 标准页来完成映射,以平衡性能与内存效率。

核心实现逻辑:PMD 层级的映射决策

phys_pmd_init的实现原理是一个高度结构化的遍历过程。它在给定的 PMD 页表中,从当前物理地址paddr对应的条目开始,逐项处理,直到超出目标区间paddr_end

其核心决策树如下:

  1. 遍历与边界检查:函数遍历 PMD 页表。如果当前地址paddr已经达到或超过终点paddr_end,则停止映射,并清除该条目(set_pmd_init(pmd, __pmd(0), init))。一个早期的补丁确保了这项清理操作只在after_bootmem之前执行,避免破坏已建立的映射。

  2. 处理已存在的映射:如果 PMD 条目已经存在(!pmd_none(*pmd)):

    • 若已是大页:检查page_size_mask。如果允许 2MB 大页,则直接复用该映射,统计页面数量并继续。

    • 若不是大页:意味着这是更精细的 4KB 页表。此时会调用phys_pte_init递归处理下一级 PTE,以处理已有映射。

  3. 建立新映射:对于空的 PMD 条目,根据条件选择映射方式:

    • 使用 2MB 大页映射:如果地址按 2MB 对齐且page_size_mask允许,则设置 PMD 条目为 2MB 大页映射。注:该条目不经过 PTE,直接指向物理内存。

    • 降级为 4KB 小页映射:如果条件不满足(例如地址不对齐,或调试配置禁用大页),则调用alloc_low_page分配一个 PTE 页表,然后调用phys_pte_init填充该表,最后将 PMD 条目指向这个新分配的 PTE 页表。

关键特性与演进

  • init参数init参数用于区分启动早期内存热插拔等运行时场景,允许在不同场景下采取不同的同步或策略行为。例如,在热插拔场景下,可能不需要像启动时那样强制清除越界的 PMD 条目。

  • TLB 一致性保证:当需要将一个已有的 2MB 大页拆分为 4KB 小页时,为了避免违反 Intel 的 TLB 应用规范(即改变页面大小时,新旧转换在页框和属性上不能有差异),代码会使用新页面的保护属性,并继承原大页的保护位。

phys_pmd_init通过这套决策机制,将上层(PUD)传递下来的、粒度更粗的映射请求(1GB 或 2MB),在 PMD 层级进一步细化为更精确的 2MB 大页或 4KB 小页映射,是构建高效、精确的内核直接映射的关键一环。

phys_pte_init

phys_pte_init是 x86 内核启动过程中,负责在PTE(页表项)层级建立物理内存直接映射的最终执行者。它处理的是最细粒度的4KB 标准页的映射,是整个页表填充流水线的最后一环。

实现原理

phys_pte_init的实现原理是一个简单的遍历和填充过程。它接收一个 PTE 页表(pte_page),将其覆盖的物理地址区间[paddr, paddr_end)内的每一个页表项逐个映射到对应的物理页。

关键设计细节

  • 返回值的一致性phys_pte_init返回的paddr_last表示已映射的最后一个物理地址。这个返回值被上层函数用于追踪映射进度。一个重要的补丁修正了该函数返回值的一致性:在遇到已存在映射时,它也会更新paddr_last,使其行为与上层phys_*_init函数保持一致。这确保了在混合使用新映射和复用已有映射时,kernel_physical_mapping_init能够获得正确的进度信息。

  • 对已有映射的处理:当函数发现某个 PTE 条目已经被映射时,它会选择复用该条目,而不是覆盖或重建。代码注释提到,Xen 虚拟化环境对此有特殊要求,例如可能需要特殊的映射属性。

  • 页表计数:函数在映射完成后会调用update_page_count(PG_LEVEL_4K, pages)更新内核维护的 4KB 页表项计数,便于后续统计和调试。

phys_pte_init作为页面映射流水线的最后一级,通过逐个填充 PTE 条目,完成了从物理地址到虚拟地址的 4KB 粒度映射,是内核直接映射区的基石。

http://www.cnnetsun.cn/news/4251797.html

相关文章:

  • NVIDIA GPU环境搭建与排错实战:驱动、CUDA、Docker和NIM
  • 数字电源赋能LED驱动:从PFC到LLC的效率革命
  • 响应渲染 render(render/ 包)
  • Open-Spec i.MX6 UL DAQ板卡:从硬件选型到Linux驱动实战指南
  • AI服务器内存优化实战:从显存估算到系统排查
  • 跨境ETF套利策略实战:从均值回复原理到Python回测全解析
  • linux.ubtun02
  • 智能体框架定制开发的常见反模式
  • VBA宏实现Excel/WPS批量提取与插入工作表
  • Windows 11设置应用状态不同步:界面与真实配置不一致的排查与修复
  • DeepSeek Harness 源码分析
  • PLC编程框架实战:状态机与模块化设计,轻松搞定变频器RS485通信
  • 基于Spark的电信用户行为分析系统的设计与实现(源码+文档+部署讲解等)
  • 你的 assert 去哪儿了?——Python 优化模式下“隐身”的断言与致命的生产环境陷阱
  • 供应链优化实战:基于机器学习的动态定价与库存补货决策模型
  • 机器人技术栈详解:从执行器到具身智能的落地指南
  • 准确率九成上线亏了12万,补完AWS机器学习入门才懂反向传播调优
  • 基于matlab的枸杞数量识别(GUI界面)【源码57期】
  • 多角色对话 AI 配音,短剧旁白轻松制作
  • 小公司Android开发4年,如今终于熬出头了!费时8个月,入职阿里涨薪14K
  • java-工具-Webservice wsdl解析
  • 虚拟电厂总体规划建设方案【附全文阅读】
  • 0 基础大学生如何入局网络安全?学习路线、避坑、就业全梳理
  • 阿里、腾讯、美团春招真题“惨遭”泄露,Github上标星66.3K
  • 告别复制粘贴式降级:纳米AI鸿蒙版导出word格式为何绕不开“AI 导出鸭”
  • 【项目编号:project19227】Spring Boot 宠物寄养平台实战:预约、健康监测与寄养人员协同
  • dm8临时表空间使用率查询-达梦数据库
  • MySQL DQL 数据查询
  • 2026年度国自然申报全流程要点梳理与避错指南
  • 大模型算法岗常见面试题100道(值得收藏)