正常
下面给你一篇可以直接发 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🚨 问题点
- EAX 必须是 0x0000E820
- ECX 必须是 24(结构大小)
- 不能随意使用 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 踩坑主要集中在:
🚨 核心问题
- BIOS 调用参数错误(EAX / ECX)
- 段寄存器设置错误(real mode)
- 内存写入方式错误(DS 混乱)
- 结构大小错误(20 vs 24)
- 死循环导致 BIOS 未执行
✅ 最终经验
👉 操作系统开发中:
“看起来成功 ≠ 真正成功”
必须做到:
- ✔ 数据解析正确
- ✔ 内存可写验证
- ✔ 结构完全符合规范
🎯 一句话总结
E820 只是告诉你“哪些内存可能存在”, 真正可用必须通过“读写验证”确认。