Skip to content

下面给你一篇可以直接发 CSDN / 博客园 / GitHub 的完整踩坑记录(偏工程 + 面试级),我帮你整理成一篇“有技术深度”的版本👇


🧠 E820 内存探测踩坑全记录(从“看似成功”到“真正可用”)

在实现操作系统内核的过程中,E820 内存探测是一个绕不开的关键步骤。它直接决定了后续:

  • 物理内存管理
  • 页表初始化
  • 内核加载位置

本文记录一次从“E820 调用成功但没有数据”到“正确解析内存布局”的完整踩坑过程。


🚨 一、问题现象:调用成功,但数据异常

在通过 BIOS INT 0x15, E820 枚举内存后,GDB 中观察到:

text
(gdb) x/w 0x5000
0x5000: 0x00000007

进一步解析后发现:

  • 实际收到了 7 条 E820 记录
  • 但最初解析结果为空或异常

👉 现象: ✔ 调用成功 ✔ EBX 正常递增 ❌ 但内存数据“看起来不对”


🔍 二、踩坑一:E820 调用参数错误(最关键)

❌ 错误写法

asm
movl $E820_CMD, %eax
movl $E820_SIGNATURE, %edx
movl $E820_ENTRY_SIZE, %ecx
int $0x15

🚨 问题点

  1. EAX 必须是 0x0000E820
  2. ECX 必须是 24(结构大小)
  3. 不能随意使用 16 位寄存器

✅ 正确写法

asm
movl $0x0000E820, %eax
movl $0x534D4150, %edx   # 'SMAP'
movl $24, %ecx
int $0x15

🔍 三、踩坑二:段寄存器使用错误(real mode 核心坑)

❌ 错误做法

asm
movw $0x5000, %es

👉 在 real mode 中:

text
物理地址 = segment << 4 + offset

👉 结果:

text
0x5000 << 4 = 0x50000 ❌(完全错)

✅ 正确做法

asm
movw $0x0500, %ax
movw %ax, %es

👉 结果:

text
0x0500 << 4 = 0x5000 ✔

🔍 四、踩坑三:内存写入地址错误

❌ 错误写法

asm
incl 0x5000

👉 实际问题:

  • DS 段寄存器设置错误
  • 导致写入完全错误的地址

✅ 正确做法

asm
movl E820_COUNT_ADDR, %eax
incl %eax
movl %eax, E820_COUNT_ADDR

👉 或直接:

asm
movl %ds:0x0, %eax

🔍 五、踩坑四:结构大小不一致

❌ 错误

asm
movl $20, %ecx

👉 但结构定义是:

c
struct e820_entry {
    u64 base;
    u64 length;
    u32 type;
}; // = 24 bytes

🚨 后果

  • BIOS 只填部分数据
  • 后半部分是垃圾
  • 解析错误

✅ 正确

asm
movl $24, %ecx

🔍 六、踩坑五:死循环导致 BIOS 未执行

❌ 错误

asm
jmp .
int $0x15

👉 结果:

  • CPU 无限循环
  • BIOS 调用根本没执行

✅ 修复

直接删除:

asm
int $0x15

🔍 七、踩坑六:数据解析错误(最大隐患)

最终正确解析后,E820 结果如下:

text
Entry 0: base=0x0 len=0x9fc00 type=1
Entry 1: base=0x9fc00 len=0x400 type=2
Entry 2: base=0xf0000 len=0x10000 type=2
Entry 3: base=0x100000 len=0x1fee0000 type=1
Entry 4: base=0x1ffe0000 len=0x20000 type=2
Entry 5: base=0xfffc0000 len=0x40000 type=2
Entry 6: base=0xfd00000000 len=0x300000000 type=2

🚨 关键认知

条目含义
type = 1可用内存
type ≠ 1不能使用

🧠 八、真正可用内存分析

✅ 可用区域:

text
0x00000000 ~ 0x0009FC00   (约 640KB)
0x00100000 ~ 0x1FFE0000   (约 511MB)

❗ 不可用区域:

  • BIOS 保留区
  • ROM
  • ACPI
  • NVS
  • 高位扩展(long mode 才能访问)

🧪 九、验证方法(关键)

方法1:直接写内存

plaintext
set *(unsigned long long*)0x100000 = 0xdeadbeef
x/gx 0x100000

👉 如果能读回:

text
0xdeadbeef

👉 说明:

✅ 内存真实可用


方法2:扫描 E820 表

plaintext
check_e820

(自定义 GDB 脚本)


🚀 十、最终总结(面试级)

本次 E820 踩坑主要集中在:


🚨 核心问题

  1. BIOS 调用参数错误(EAX / ECX)
  2. 段寄存器设置错误(real mode)
  3. 内存写入方式错误(DS 混乱)
  4. 结构大小错误(20 vs 24)
  5. 死循环导致 BIOS 未执行

✅ 最终经验

👉 操作系统开发中:

“看起来成功 ≠ 真正成功”

必须做到:

  • ✔ 数据解析正确
  • ✔ 内存可写验证
  • ✔ 结构完全符合规范

🎯 一句话总结

E820 只是告诉你“哪些内存可能存在”, 真正可用必须通过“读写验证”确认。

035_multi_terminal-40-g5d72b8b · 5d72b8b · 2026-06-26