linux 内核内存机制之e820(linux启动时,利用e820读取物理内存信息)
前言:
我们在进入linux 内存管理学习的时候,我们首先要知道,操作系统首先要在启动的时候把目前机器上有多少内存要了解清楚,内存是怎么布局的,是被怎么用的。否则你学习内存管理就成了无本之源。操作系统初始化自身所需的最重要的关键信息之一就是机器上可用 物理内存的映射。从根本上说,操作系统获取该信息的最佳方式是使用 BIOS。由于我们经常关注的是大型服务器,内存很大,但是往往嵌入式设备或单片机等领域内存是很小的,反而提升了解决问题的复杂性。所以内核会很多版本,甚至兼容性处理等。
下面分析基于内核的日志文件的输出,内核输出日志信息就包括了内核在启动时,是按照一定的次序在进行检测、配置等。
[root@aozhejin]$dmesg >kernel.log #保存文件来分析
一、linux启动和bios的E820
这里注意,前提你机器采用的是传统的BIOS模式启动,这里不讨论UEFI或其他类启动模式。
1、wiki的解释如下:
https://en.wikipedia.org/wiki/E820
1.1 e820是基于x86的计算机系统的bios 向操作系统或引导加载程序报告内存映射的工具的简写。
linux 内核通过调用 bios的 int 15h 中断来访问它,方法是将EAX 寄存器设置为十六进制值 E820(eax=E820)
。它会报告哪些内存地址范围可用,哪些保留供 BIOS 使用。 BIOS-e820 通常是引导linux内核首先报告的内容,也可以使用dmesg命令查看。
1.2 BIOS 功能:INT 0x15,EAX = 0xE820
到目前为止,检测 PC 内存的最佳方法是调用BIOS的 INT 0x15, EAX = 0xE820 命令。此功能适用于 2002 年以来制造的所有 PC,以及在那之前的大多数现有 PC。它是唯一可以检测 4G 以上内存区域的 BIOS 功能。它旨在成为最终的内存检测 BIOS 功能。
你可以查看 这里 看到更多的的bois int 0x15 eax=...的功能
2、内核源码中的注解
E:\linux内核\E:\linux内核\linux-3.12.37\arch\x86\kernel\e820.c
e820 is shorthand to refer to the facility by which the BIOS of x86-based computer systems It is accessed via the int 15h call, by setting the AX register to value E820 in hexadecimal. It reports which memory address ranges are usable and which are reserved for use by the BIOS.
翻译过来和上面是一样的
The e820_saved is directly saved after the BIOS-provided memory map is copied
e820_saved结构体会保存bios提供内存映射
3、内核启动日志中bios提供的物理ram映射信息(dmesg命令查看或查看/var/log/dmesg)
会分两步
第一步: 内核调用中断,读取bios检测到的物理ram映射地址,下面就是读取后处理的输出
/*********************************************************************************************
//start_kernel 函数定义在:E:\linux内核\linux-3.12.37\init\main.c(汇编启动.S调用) //setup_arch 函数定义在:E:\linux内核\linux-3.12.37\arch\x86\kernel\setup.c //setup_memory_map 函数定义在: E:\linux内核\linux-3.12.37\arch\x86\kernel\e820.c 内核函数调用链 start_kernel ----------->setup_arch ------------------>setup_memory_map 函数打印输出 **************************************************************************************************/ //bios提供的物理ram映射 [ 0.000000] e820: BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable 634kb [ 0.000000] BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved 4kb [ 0.000000] BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved 143kb [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bfecffff] usable 3069MB [ 0.000000] BIOS-e820: [mem 0x00000000bfed0000-0x00000000bfefefff] ACPI data [ 0.000000] BIOS-e820: [mem 0x00000000bfeff000-0x00000000bfefffff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000bff00000-0x00000000bfffffff] usable 1g [ 0.000000] BIOS-e820: [mem 0x00000000f0000000-0x00000000f7ffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec0ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fffe0000-0x00000000ffffffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000043fffffff] usable
计算内存地址大小方法1
0x00000000bfecffff-0x0000000000100000=BFDCFFFF (转成十进制) =3218931711(字节)/1024/1024=3069MB
计算内存地址大小方法2
方法2: 输入linux命令,下面得到的是MB大小
[root@aozhejin /]#echo $((0x0000000100000000/1024/1024))
上面我们的内容18GiB内存的服务器,其“可用”内存介于4GiB(0x100000000)和~18GiB(0x43fffffff)之间:
说明:
Usable(可用): 已经被映射到物理内存的物理地址。 |
第二步: (第一步之后还会利用 drivers/firmware/dmi_scan.c 进行SMBIOS检测工作)
内核读到这些信息后,将其保存在e820map结构体中。
linux-3.12.37\arch\x86\kernel\e820.c: 源码如下: |
第三步、继续
[ 0.000000] e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[ 0.000000] e820: remove [mem 0x000a0000-0x000fffff] usable
[ 0.000000] e820: last_pfn = 0x440000 max_arch_pfn = 0x400000000
参考资料:
https://wiki.osdev.org/Detecting_Memory_(x86)#Getting_an_E820_Memory_Map
https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt
https://www.kernel.org/doc/html/v5.6/x86/boot.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2022-03-15 UUID