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

一、linux内存管理学习(1):物理内存探测

目录

1、内存探测

1.1、e820__memory_setup

1.2、parse_setup_data

1.3 总结

2、物理内存整理

2.1、parse_early_param

2.2、e820__reserve_setup_data

2.3、e820_add_kernel_range

2.4、 e820__end_of_ram_pfn


1、内存探测
1.1、e820__memory_setup
e820__memory_setup --> e820__memory_setup_default --> append_e820_table                // 将BIOS提供的原始E820内存映射表复制到内核安全区域--> e820__update_table(e820_table);  //更新内核的E820内存映射表--> memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));--> e820__print_table

该流程主要内容:

(1)从 BIOS 获取原始 E820 表

(2)构建三份内存表:

  • ​e820_table​:主表,供内核内存管理使用。
  • ​e820_table_kexec​:为 kexec​ 热重启保留,确保新内核看到一致的物理布局。
  • ​e820_table_firmware​:备份原始 BIOS 数据,用于调试或回退。

(3)打印内存布局

[    0.000000] BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000001ffdffff] usable
[    0.000000] BIOS-e820: [mem 0x000000001ffe0000-0x000000001fffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
1.2、parse_setup_data
parse_setup_data --> e820__memory_setup_extended--> early_memremap        // 映射物理地址到内核虚拟地址空间--> __append_e820_table   // 将扩展条目追加到内核 E820 表--> e820__update_table    // 合并/优化内存表(处理重叠或相邻区域)--> memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));  // 备份更新后的内存表memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));--> early_memunmap        // 解除早期内存映射--> e820__print_table("extended");  // 打印扩展后的内存布局

主要内容:

(1)在早期启动阶段(页表未完全初始化时),将物理地址 phys_addr 临时映射到内核虚拟地址空间,以访问扩展的 E820 数据

(2)将扩展条目追加到内核主表 e820_table,不进行合并(保留原始信息)

(3)合并相邻/重叠区域,解决冲突(如高优先级类型覆盖低优先级类型)

(4)释放临时映射,避免内存泄漏

(5)打印扩展后的完整内存布局,前缀为 "extended",示例:

[    0.000000] extended physical RAM map:
[    0.000000] extended: [mem 0x00000000-0x0009ffff] usable
[    0.000000] extended: [mem 0x00100000-0x3fffffff] reserved
1.3 总结

第一部分整体调用流程:

start_kernel()--> setup_arch()--> e820__memory_setup()          // 处理前 128 条目--> parse_setup_data()            // 遍历 setup_data 链表--> e820__memory_setup_extended()  // 处理扩展条目

目的:解决BIOS/引导加载程序struct boot_params​ 中 e820_table​ 仅能容纳 128 个内存条目的问题

解决方案:超出部分通过 SETUP_E820_EXT​ 节点(struct setup_data​ 链表)传递,传递后将数据合并到e820_table,经e820__update_table整理后更新到e820_table_kexec/firmware

2、物理内存整理
2.1、parse_early_param
parse_early_param()--> parse_early_options(cmdline)--> parse_args(..., do_early_param)--> 对每个参数调用 parse_one()--> 若匹配 early 标记,调用 do_early_param()--> 执行 p->setup_func(val)(如 early_mem("512M"))

整个流程是解析早期启动参数(early param)的过程,涉及内核命令行参数(cmdline)的解析和相应处理函数的执行

(1)在 do_early_param()​ 中,内核通过以下步骤匹配并执行回调:

  • 遍历注册表:扫描 __setup_start​ 到 __setup_end​ 之间的所有参数(由链接脚本生成)。
  • 匹配参数名:比较 cmdline​ 中的参数(如 mem=512M​)与注册的 str​ 字段。
  • 执行回调:若匹配且标记为 early​,则调用 setup_func(val)​,传入参数值(如 512M​)。

(2)linux使用early_param​ 宏(定义于 include/linux/init.h​),将参数名与处理函数绑定,并标记为 EARLY​ 属性,例如:

early_param("mem", early_mem); // 注册 "mem=" 参数,回调函数为 early_mem

展开后生成一个 struct obs_kernel_param​ 结构体,存入 .init.setup​ 段(通过链接脚本聚合),即__setup_start​ 到 __setup_end​ 之间的段

(3)因此,针对下面的代码:

early_param("mem", parse_memopt);

若命令行中有 ‘mem= ’ 字段,便会调用parse_memopt回调函数,进行内存大小重新调整

2.2、e820__reserve_setup_data
e820__reserve_setup_data --> e820__range_update--> e820__update_table--> e820__print_tablee820__finish_early_params--> e820__update_table --> e820__print_table

保留bootloader传递的setup_data内存区域,并更新内存映射表

在完成早期启动参数(如 mem=xxx)解析后,对内存映射表进行最终规范化,并打印调试信息

2.3、e820_add_kernel_range
e820_add_kernel_range --> e820__mapped_all --> e820__range_remove --> e820__range_addstatic void __init e820_add_kernel_range(void)
{// 计算内核的物理地址范围(从 _text 到 _end)u64 start = __pa_symbol(_text);       // 内核代码起始物理地址u64 size = __pa_symbol(_end) - start; // 内核占用的总大小// 检查是否已被正确标记为 RAMif (e820__mapped_all(start, start + size, E820_TYPE_RAM))return; // 如果已经是 RAM,直接返回// 报警:内核区域未被标记为 RAMpr_warn(".text .data .bss are not marked as E820_TYPE_RAM!\n");// 修复步骤:// 1. 移除该范围内的所有现有内存条目(无论类型)e820__range_remove(start, size, E820_TYPE_RAM, 0);// 2. 重新添加为 E820_TYPE_RAMe820__range_add(start, size, E820_TYPE_RAM);
}
  • 背景:BIOS 或 bootloader 提供的 E820 内存映射表可能不准确,有时会错误地将内核代码和数据所在的内存区域标记为“保留”或“不可用”(如 E820_TYPE_RESERVED​)。例如:用户通过 memmap=exactmap​ 或 memmap=xxM$yyM​ 手动排除内核所在的内存区域。
  • 目的:强制将内核的代码段(.text​)、数据段(.data​)和未初始化数据段(.bss​)标记为 E820_TYPE_RAM​,避免内核因运行在“非 RAM”区域而崩溃。
2.4、 e820__end_of_ram_pfn

这段代码主要用于 确定系统物理内存的边界(以页帧号 pfn​ 表示)

e820__end_of_ram_pfn    // 计算系统中可用物理内存(E820_TYPE_RAM)的最后一页的页帧号(last_pfn)。--> e820_end_pfn

函数主要功能:

(1)确定物理内存边界:通过遍历 E820 表,计算可用 RAM 的最大页帧号(last_pfn​)。

(2)区分低端/高端内存(32/64 位):

  • 32 位:直接调用 find_low_pfn_range()​。
  • 64 位:根据物理内存是否超过 4GB 动态设置 max_low_pfn​,last_pfn​ 和 max_low_pfn​ 是内核内存管理的关键参数,用于初始化页表、伙伴系统等。
           MAX_ARCH_PFN (架构支持最大值)│▼e820_end_pfn() → last_pfn│┌───────┴───────┐▼               ▼max_low_pfn       max_pfn(低端内存边界)    (实际物理内存上限)│               │▼               ▼32位: find_low_pfn_range()  64位: high_memory = __va(max_pfn)物理地址空间
┌───────────────────────┐
│      Low Memory       │ ◄─max_low_pfn (直接映射区)
│  (0x00000000-3FFFFFFF)│
├───────────────────────┤
│      High Memory      │ ◄─动态映射
│  (>=0x40000000)       │
└───────────────────────┘物理地址空间
┌───────────────────────┐
│   Low Memory (<4GB)   │ ◄─max_low_pfn
├───────────────────────┤
│   High Memory (≥4GB)  │ ◄─high_memory = __va(max_pfn)
└───────────────────────┘
http://www.dtcms.com/a/331061.html

相关文章:

  • 京东商品列表API开发指南
  • OpenCV对椒盐处理后的视频进行均值滤波处理
  • Opencv 边界填充 图像运算 阈值处理 和图像平滑处理
  • 文件上传接口接收不到文件入参
  • 题解:P4777 【模板】扩展中国剩余定理(EXCRT)
  • Qt项目查找依赖库打包
  • IDEA、Pycharm、DataGrip等激活破解冲突问题解决方案之一
  • Springboot项目重启后Session依旧存在
  • Python包性能优化与并发编程:构建高性能应用的核心技术(续)
  • 轻量级开源全文搜索引擎:Manticore Search 入门介绍
  • C++基础(①入门教程)
  • 本地jar导入到本地仓科和远程仓库
  • Maven学习笔记
  • 92、23种设计模式-单例模式
  • 项目日志框架与jar中日志框架冲突 解决
  • 《多级缓存架构设计与实现全解析》
  • 自动化测试|持续集成Git使用详解
  • label studio 服务器端打开+xshell端口转发设置
  • 01数据结构-最短路径Dijkstra
  • 【数据结构入门】
  • 移动机器人底盘在高校科研中的AI智能教育应用
  • (第十五期)HTML文本格式化标签详解:让文字更有表现力
  • Flutter GetX 全面指南:状态管理、路由与依赖注入的最佳实践
  • SpringMVC请求与响应
  • 三坐标测量仪:从机械精密到智能协同的技术
  • flutter 开发 鸿蒙 App
  • gitee_配置自动部署vue项目
  • Uniapp 获取系统信息:uni.getSystemInfo 与 uni.getSystemInfoSync
  • vs2022 opencv环境配置(使用相对地址-将依赖都放入项目中)
  • spring boot配置es