Skip to content

导引:点亮什么与为什么

到 024 为止,内核已经能把程序丢进 Ring 3、收发系统调用、跑一个能 echo/help/clear 的 shell 了。但这个 shell 再花哨,程序和数据还是被 bootloader 一股脑塞进内存、只读、用完即弃——内核从来没「自己」碰过磁盘。这一章开始补这个洞:我们要让内核先在 PCI 总线上找出那块 SATA 控制器,再驱动它的 AHCI 接口,最终读出磁盘第 0 号扇区的 MBR 签名(55 AA)。能自己读写扇区,是后面一切文件系统、initrd、用户程序加载的前提。

这一章我们要点亮什么

一件能力,一个验证。

能力是:内核第一次主动去碰外部存储设备。具体分两层——先写一个 PCI 驱动,它会遍历总线、读每个设备的「身份证」(厂商/设备/类别码),从茫茫设备里认出「这块是 AHCI SATA 控制器」;再写一个 AHCI 驱动,把控制器的寄存器窗口映射进内核、初始化它、给它的端口搭好命令队列,然后通过 DMA 发一条「读扇区」命令,把磁盘上的数据搬进内存。从这一章起,内核不再只活在 RAM 里,它够得到磁盘了。

验证是:读出磁盘第 0 号扇区,检查它的最后两字节是不是 55 AA——这是传统 MBR 的引导签名。我们要在 QEMU 里挂一张手造的测试盘,在偏移 510-511 处写好 55 AA,然后看内核打出 [AHCI] Read sector 0: 55 AA。看到这行,说明「找设备 → 映射寄存器 → 起端口 → 发命令 → 收数据」整条链路全通。

这两件事合起来,意味着内核从「设备是别人给我配好的」升级成了「我自己认设备、自己驱动设备」。这是存储子系统的第一块基石。

为什么现在需要它

为什么紧跟在 userland 之后。022 到 024 让内核有了用户态、系统调用、shell,看起来像个「能交互的系统」了。但所有用户程序——包括那个 shell 本身——都是 bootloader 在启动时一次性塞进来的,内核运行起来之后没法再从磁盘加载任何东西。要真做成一个能「跑程序、读文件」的系统,内核得能自己读盘。而要读盘,首先得知道盘在哪——在 PC 上,这就是 PCI 总线。

为什么先 PCI 再 AHCI。现代 PC 的设备不是直接挂在 CPU 上的,而是挂在 PCI(以及它的继任者 PCIe)总线上。每块 PCI 设备有一小段「配置空间」,内核靠它认设备、拿到设备寄存器的基地址(BAR)。我们想用的 SATA 磁盘控制器,其寄存器接口遵循 AHCI 标准(Advanced Host Controller Interface),而 AHCI 控制器的寄存器块就暴露在它的 BAR5 上。所以顺序是死的:先写 PCI 驱动认出 AHCI 控制器、拿到 BAR5 地址,再写 AHCI 驱动操作那块寄存器。没有 PCI 这一步,AHCI 无从谈起。

还有一笔技术上的账。AHCI 的寄存器是内存映射的(MMIO)——它不是端口 I/O,而是把寄存器「铺」在一段物理地址上,CPU 像访问内存一样读写。但内核只能访问虚拟地址,所以读 BAR5 之前,得先用 016 写好的 VMM 把这块物理地址 map 进内核的虚拟地址空间。这里还要踩一个关键 flag:FLAG_PCD(Page Cache Disable),MMIO 寄存器绝不能被 CPU 缓存——这个坑调试现场专门讲。所以这一章不是凭空冒出来的,它直接站在 016 的 VMM 肩膀上。

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