B01 — BIOS’s First Map for the OS: The e820 Memory Map
Key Insight: When the computer starts, the first problem the OS must solve is: how much memory is there and where is it?
The OS’s First Question After Power-On
After power-on, BIOS (UEFI) first completes hardware initialization. Then the OS starts booting. The first question the OS must solve is: how much physical memory is there, where is it, and which regions are usable.
启动顺序:
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 和操作系统之间的"第一份合同"。What is e820
e820 is the BIOS memory map of the x86 architecture. It is provided to the OS via INT 15h, function 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,不可覆盖)
其他 = 保留/不可用Real Example of an e820 Table
用 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 保留区Why e820 Is Needed: MMIO Regions Exist
The most important role of e820 is to tell the OS: which addresses are for peripherals and cannot be used as 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 Construction Process
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 是一个连续的"内存段"列表。Accessing e820 in Code
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 表示没有更多条目Why 32-bit Systems Only Show 4GB of Memory
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 内存Summary
- e820: BIOS memory map for the OS; obtained via INT 15h E820h call
- Structure: Base Address (64-bit) + Length (64-bit) + Type (32-bit)
- Type Values: 1=usable memory, 2=reserved/MMIO, 3=ACPI Reclaim, 4=ACPI NVS
- MMIO: Memory-mapped I/O; address space occupied by peripheral registers; cannot be used as DRAM
- Why 32-bit Only Sees 4GB: Address space is partially consumed by MMIO; available DRAM space shrinks
Next (B02): The memory module’s ID card. What does the SPD chip actually store? Detailed SPD data format and how BIOS uses SPD to configure memory.
Comments