Skip to content

点亮什么与为什么

前三章我们把机器从 MBR 一路抬到了 64 位长模式,但严格说,我们写的还都叫"bootloader"——一大堆汇编,没有一行真正的"内核代码"。这一章是 boot 卷的收尾:我们要把第一个用 C++ 写的内核从磁盘读进内存,通过一个交接结构把启动信息交给它,然后跳进去。从此,汇编 bootloader 的历史使命完成,接力棒交给 C++。

这一章我们要点亮什么

这一章的成果,是一台机器能跑到这个程度:

text
... 长模式就绪(同 003) ...
 └─▶ 实模式收尾(还在 BIOS 能用的时候):
      ├─ query_memory_map()      # E820 查物理内存图 → 0x5000
      └─ load_kernel_from_disk() # 把 C++ 内核 ELF 读进物理 0x20000
 └─▶ 进长模式后(long_mode_entry):
      ├─ 填一张 BootInfo@0x7000(帧缓冲/内存图/入口地址)
      ├─ outb 'J'                # 要跳了
      └─ rdi = 0x7000; jmp 0xFFFFFFFF80020000   # 跳进 C++ 内核
           └─▶ kernel _start:
                ├─ 设栈、清 BSS、跑全局构造
                └─ call mini_kernel_main(BootInfo*)
                     └─▶ 一组 C++ 冒烟测试(类/虚函数/全局对象)
                          + 校验 BootInfo 完整
                          → halt

完成后,build/debug.log 里会从 003 的 PL 长成一串:P L J 1 2 3 G 4 ===CPP … B … ===END。那个 ===CPP…===END 中间的测试标记和 B(BootInfo 校验通过),就是"一个 C++ 内核真的跑起来了"的铁证。

为什么现在需要它

长模式只是把舞台搭好。到目前为止,我们所有的"逻辑"都是写在汇编 bootloader 里的——配 GDT、搭页表、切模式。这套东西能做的事很有限,而且汇编写到后面越来越难维护。我们真正想要的,是一个用 C++ 写的、有类、有虚函数、有全局对象、能被现代工具链编译的内核。

但 C++ 内核不能凭空跑起来,它需要 bootloader 替它做三件"一旦进 64 位就做不了"的事:

  1. 把它从磁盘读进内存(读盘要用 BIOS,只能在实模式做)。
  2. 把它需要的启动信息收集好(物理内存图要靠 BIOS 的 E820,帧缓冲参数是 001 配 VESA 时拿到的)。
  3. 给它一个能落脚的地址和一份交接说明(内核链接在高半地址,我们得在页表里把那个地址映射好,再用一个结构把信息传过去)。

这三件事,正好对应这一章的三个主角:ELF 加载BootInfo 交接高半内核。做完它们,bootloader 就可以功成身退了。

035_multi_terminal-45-gf25de18 · f25de18 · 2026-08-04