点亮什么与为什么
这是 Cinux 真正"上电"的第一章。前面 000 只是把工具链和 ROADMAP 摆好,机器一个字节都没跑。这一章,我们要让 BIOS 把我们写的第一段代码从磁盘读进内存、执行,并在离开实模式之前,把后面所有阶段都要用的两样东西准备好:能读盘、一块配好的图形屏。
这一章我们要点亮什么
一台 x86 机器按电源的那一刻,CPU 处在一个非常复古的状态——实模式。它假装自己是 1978 年的 8086:16 位寄存器、段式寻址、只能寻址 1MB、没有任何保护。BIOS 做完自检(POST)后,会去硬盘的第一个扇区(512 字节)找一段叫 MBR(Master Boot Record) 的代码,把它原封不动读进内存的 0x7C00,然后跳过去执行。这个 0x7C00 不是我们挑的,是 BIOS 和所有 PC 定死的约定。
所以我们的第一段代码,只有 512 字节的预算,要做这些事:
BIOS ──读扇区0──▶ 0x7C00 ──执行 MBR──┐
│
① 把段寄存器理顺(DS=ES=SS=CS)
② 给自己搭个栈
③ 让 BIOS 把"第 2 段代码"从磁盘读进来
④ 跳过去,把接力棒交出去这"第 2 段代码"叫 Stage2。它住在磁盘的扇区 1 之后,被读到 0x8000。为什么要分两段?因为 MBR 那个 512 字节太挤了——光是把"读磁盘、切图形模式"这些活干完就装不下,而且 BIOS 要求第 0 扇区末尾两个字节必须是魔数 0xAA55,挤得更死。所以标准做法是:MBR 当跳板,极简;真正干活的是 Stage2。
Stage2 干完这章的活就停了:
- 打印几句话(还能看,因为还在文本模式);
- 打开 A20 地址线(为什么需要它,下面讲);
- 调 BIOS 的 VESA 接口,把屏幕切成 1024×768 的图形模式,并把这块"画布"(framebuffer)的物理地址、宽度、每行字节数记到一个固定地址
0x6400,留给将来的内核; - 然后
hlt原地停下。
完成后你会看到:QEMU 窗口里先是几行文本(Cinux Booting...、Stage2 OK、Mode info OK, switching...),然后屏幕"啪"地切进图形模式(黑屏,因为还没人往 framebuffer 里画东西),机器安静地停在那里。这就是 001 的全部——通电、读盘、配屏、待命。
为什么现在需要它
你可能会问:既然我们最终要写一个 64 位、有保护、有分页的现代内核,为什么一开始要窝在这么古董的实模式里?
因为 BIOS 只在实模式下存在。BIOS 提供的那些"帮我读磁盘""帮我切显示模式""帮我查内存布局"的服务,统统是 16 位实模式的中断例程(int $0x10、int $0x13、int $0x15 …)。一旦我们走进保护模式(下一章)、再走进长模式,CPU 就不再认这些中断了,BIOS 这套"白嫖来的能力"当场作废。
所以这里有个时序上的硬约束:所有要用到 BIOS 的活,必须在离开实模式之前做完。读盘、配图形模式、开 A20,都是这一类。这一章就是"趁着 BIOS 还在,把能蹭的服务都蹭完"。
外部依据:OSDev 的 Boot Sequence 页描述了 BIOS POST 之后加载第一个可引导扇区到
0x7C00并跳转的标准流程;Memory Map (x86) 页给出了0x7C00这个约定地址的由来。精确的实模式段式地址翻译(seg<<4+offset)见 Intel SDM Vol.3A §3.3。