B01 —— BIOS 给操作系统的第一份地图:e820 内存映射表
金句:计算机启动时,操作系统第一个要解决的问题是——内存有多大、都在哪里。
开机后操作系统的第一个问题
计算机加电后,BIOS(UEFI)首先完成硬件初始化,然后操作系统开始启动。操作系统第一个要解决的问题是:物理内存有多大、在哪里、哪些区域可以用。
启动顺序:
1. CPU 复位 → 执行 BIOS/UEFI(从 0xFFFF0 开始)
2. BIOS 执行 POST(Power-On Self-Test)→ 枚举内存设备
3. BIOS 读取 SPD → 知道每个 DIMM 的容量和速度
4. BIOS 构建 e820 内存映射表
5. BIOS 把控制权交给操作系统(bootloader)
6. 操作系统读取 e820 表 → 建立自己的内存管理
e820 表是 BIOS 和操作系统之间的"第一份合同"。什么是 e820
e820 是 x86 架构的 BIOS 内存映射表,以 INT 15h 中断的 E820h 功能提供给操作系统。
e820 的全称:
INT 15h, AX = E820h - "Get System Memory Map"
为什么叫 e820:
- 功能号是 E820h(0xE820)
- 调用这个中断,能获取完整的物理内存布局
返回的数据结构(SMAP):
Offset Size Description
------ ---- -----------
0x00 4B Base Address(内存区域起始地址,64-bit)
0x08 8B Length(内存区域长度,64-bit)
0x10 4B Type(内存区域类型)
Type 取值:
1 = AddressRangeMemory (可用物理内存)
2 = AddressRangeReserved (保留/被外设占用)
3 = ACPI Reclaim Memory (ACPI 表,可以回收使用)
4 = ACPI NVS Memory (ACPI NVS,不可覆盖)
其他 = 保留/不可用e820 表的实际例子
用 dmesg 查看 e820 映射(Linux):
$ dmesg | grep -i "e820" | head -20
[ 0.000000] e820: BIOS-provided physical RAM map:
[ 0.000000] e820: 0x0000000000000000 - 0x000000000009ffff (640 KB)
[ 0.000000] e820: 0x0000000000100000 - 0x00000000bf79e000 (1918 MB)
[ 0.000000] e820: 0x00000000bf79e000 - 0x00000000bf7de000 (240 KB)
[ 0.000000] e820: 0x00000000bf7de000 - 0x00000000c0000000 (4224 KB)
[ 0.000000] e820: 0x00000000c0000000 - 0x00000000fe000000 (960 MB)
[ 0.000000] e820: 0x00000000fe000000 - 0x00000000ff000000 (16 MB)
[ 0.000000] e820: 0x00000000ff000000 - 0x00000000fff00000 (15 MB)
[ 0.000000] e820: 0x000000fff00000 - 0x000000ffff0000 (64 KB)
解析:
0x0000000000000000 - 0x000000000009ffff (640 KB) = 传统 640KB 区域(Type 1,可用)
0x0000000000100000 - 0x00000000bf79e000 (1918 MB) = 主内存区域(Type 1,可用)
0x00000000c0000000 - 0x00000000fe000000 (960 MB) = MMIO 区域(Type 2,保留)
0x00000000fe000000 - 0x00000000ff000000 (16 MB) = 固件区(Type 2,保留)
0x00000000fff00000 - 0x00000000ffff0000 (64 KB) = BIOS ROM(Type 2,保留)
总共 4GB 地址空间(0x0 ~ 0xFFFFFFFF)
其中约 2.6GB 是可用物理内存,1.4GB 是 MMIO 保留区为什么需要 e820:MMIO 区域的存在
e820 最重要的作用是告诉操作系统:哪些地址是给外设用的,不能当作 DRAM。
MMIO(Memory-Mapped I/O)和 DRAM 的区别:
DRAM(物理内存):
地址 0x10000000 ~ 0x17FFFFFF = 128MB DDR 内存
→ CPU 访问这个地址,内存控制器会读写 DRAM 颗粒
MMIO(外设寄存器):
地址 0xE0000000 ~ 0xEFFFFFFF = PCIe BAR 或集成显卡显存
→ CPU 访问这个地址,内存控制器会把这个请求发到 PCIe 总线
→ 外设寄存器响应,但 DRAM 颗粒不被访问
BIOS 的职责:
- 扫描 PCIe 总线,发现有哪些外设
- 给每个外设分配 MMIO 地址范围(BAR 地址)
- 把这些范围记录在 e820 里(Type=2,保留)
操作系统读取 e820:
→ 知道 0xE0000000 ~ 0xEFFFFFFF 不能用于内存分配
→ 把这段地址从物理页分配器中排除e820 的构建过程
e820 是怎么生成的:
1. BIOS 读取 SPD(Serial Presence Detect)
→ 知道每个 DIMM 的容量(例如:8GB DDR4 × 2 = 16GB)
→ 构建"可用内存"条目(Type=1)
2. BIOS 枚举 PCIe 外设
→ 读取每个设备的 BAR(Base Address Register)
→ 决定 MMIO 地址范围
→ 添加"保留"条目(Type=2)
3. BIOS 分配 ACPI 地址
→ ACPI tables 放在固定地址(通常是 0xE0000000 以下)
→ ACPI Reclaim Memory(Type=3)和 ACPI NVS(Type=4)
4. BIOS 添加固件区域
→ BIOS ROM 在 0xFFFE0000 ~ 0xFFFFFFFF(64KB)
→ SMM(System Management Mode)区域
最终 e820 是一个连续的"内存段"列表。在代码中访问 e820
Linux 内核中的 e820 处理:
// arch/x86/include/asm/e820.h
struct e820_entry {
__u64 addr; // 起始地址
__u64 size; // 大小
__u32 type; // 类型
};
每次启动时,Linux 调用:
e820__memory_setup() // 构建 e820
e820__reserve_memory() // 标记保留区域
e820__print_table() // 输出到 dmesg// 用 INT 15h E820 读取内存映射的例子(x86 汇编)
mov ax, 0e820h // AH = 0xE820, AL = 0xE820
mov edx, 534d4150h // EDX = 'SMAP'(签名)
mov di, buffer // ES:DI = 输出缓冲区
int 15h // 调用 BIOS 中断
jc error // 如果 CF=1,出错
// 返回的 buffer 格式:
// 偏移0:Base Address Low (4B)
// 偏移4:Base Address High (4B)
// 偏移8:Length Low (4B)
// 偏移12:Length High (4B)
// 偏移16:Type (4B)
// 偏移20:AcpiUid (4B,扩展用)
next_entry:
mov ax, 0e820h
mov di, buffer
int 15h
jnz done // EAX=0 表示没有更多条目为什么 32 位系统只显示 4GB 内存
32 位系统的内存寻址限制:
32 位地址最大寻址:2^32 = 4GB
e820 里的 4GB 地址空间分配:
0x00000000 ~ 0xBFFFFFFF:DRAM(最高 3GB 可用)
0xC0000000 ~ 0xFFFFFFFF:MMIO(固件/显卡/PCIe,1GB)
所以即使插了 4GB 内存,32 位系统只能用到 ~2.5~3GB
其他被 MMIO 占用(地址空间被 MMIO "偷走"了)
PAE(Physical Address Extension):
- IA-32 提供了 PAE 模式(36-bit 物理地址)
- 可以访问最多 64GB 内存
- 但每个进程仍然只能用 4GB 虚拟地址空间
- 这就是为什么 32 位 Windows 服务器版能识别 >4GB 内存
64 位系统:
- 虚拟地址 48-bit(用户空间)或 57-bit(Kernel)
- 物理地址 48-bit~52-bit
- 可以寻址 256TB~4PB 内存总结
- e820:BIOS 给操作系统的内存映射表,通过 INT 15h E820h 调用获取
- 结构:Base Address(64-bit)+ Length(64-bit)+ Type(32-bit)
- Type 类型:1=可用内存,2=保留/MMIO,3=ACPI Reclaim,4=ACPI NVS
- MMIO:内存映射 I/O,外设寄存器占用的地址空间,不能当 DRAM 用
- 为什么 32 位只能看到 4GB:地址空间被 MMIO 分走了一部分,DRAM 可用空间缩水
下篇预告(B02):内存条的”身份证”——SPD 芯片里到底存了什么?SPD 数据格式详解,以及 BIOS 是怎么用 SPD 来配置内存的。
关注公众号「AI不着急」,回复”资料”获取内存学习路线图。
评论