按下电源后,电脑经历了什么?
从按下电源到看到登录界面:慢慢认识 BIOS、UEFI、U-Boot、AHCI 和 Linux 内核各自做了什么。
按下电源,屏幕亮起来,看上去像是电脑一下子醒了。其实电脑开机更像一栋刚开门的商店:先有人打开门,再开灯、搬工具,最后才请店长来安排工作。门口的管理员不会经营整家店,他只负责找到下一位接班人;下一位再把需要的东西准备好,交给再下一位。
电脑也这样一棒接一棒地启动。刚通电时,Linux 还没有运行;后来才轮到 BIOS 或 UEFI、启动程序、Linux 内核和第一个系统进程。每一棒做的事不同,知道谁把什么交给谁,就能看懂整个开机过程。
第一步:给电脑通电,让处理器找到起点
电源启动后,主板会先确认电压稳定,然后让处理器开始工作。处理器刚醒来时,内存、硬盘和屏幕都还没有完全准备好,它不能马上去硬盘里找 Linux。它会先从一个预先安排好的位置读取最早的启动代码。
可以把这想成新店开门:店长还没到,店里的灯也还没全开。门口有一张固定的指示纸,告诉最早醒来的工作人员下一步去哪里。电脑里的这张“指示纸”其实是一小段程序,通常存放在主板或芯片的非易失存储器里,断电后内容也不会消失。
在许多台式机上,最早运行的固件就是 BIOS 或 UEFI。BIOS 是较早的一套个人电脑固件方式;UEFI 是后来发展出的固件接口标准。我们平时按 Delete 或 F2 看到的设置画面,通常由这类固件提供。它不是 Linux 的一部分,而是电脑开机时先工作的基础软件。
第二步:固件先做检查和准备
固件会先做一些基本检查和准备。它需要让内存可以使用,让处理器知道机器有哪些基础设备,并尝试让显示器、键盘和存储设备进入可工作的状态。开机时有时会听到蜂鸣声、看到厂商标志,或看到内存检查信息,这些都可能是固件工作的表现。
这类开机自检常被叫作 POST,是“开机自我检查”的意思。它不是把电脑里每个零件都彻底检查一遍,而是先确认继续启动所需的关键部分能不能工作。比如内存完全无法使用,后面的程序就没有地方临时放东西,电脑自然也很难继续开机。
内存就像店里的工作桌:程序运行时,需要把正在处理的资料暂时摊在桌上。电脑刚通电时,这张桌子还没有收拾好,所以最开始的程序会特别小;等内存准备妥当,功能更完整的程序才能进来。
第三步:台式机要从硬盘找到启动程序
检查和准备完成后,固件要决定从哪里启动。启动顺序可以设置成先看 USB、再看硬盘,或先看网络。固件会按这个顺序寻找可以启动的设备。它必须先能读取设备上的一部分内容,才能找到下一段程序。
老路线:BIOS 从硬盘开头开始找
在传统 BIOS 启动中,固件通常从启动硬盘最前面的一个扇区读取启动代码。这个扇区常被称为 MBR,也就是主引导记录。一个扇区只有 512 字节,里面除了启动代码,还要留下位置记录硬盘分区。它小得像一张只能写几行字的便条,装不下一整套 Linux。
所以这张便条的工作只是指路:它把控制权交给更完整的启动程序。常见的启动程序之一是 GRUB。GRUB 能读懂更多硬盘分区和文件系统,找到 Linux 内核及其配套文件,再把它们放到内存里。传统 GRUB 有时也要分几小步启动,每一步都比前一步更有本领。
BIOS、MBR 和 GRUB 不是同一个东西:BIOS 是主板固件,MBR 是硬盘开头的一段区域,GRUB 是启动程序。把它们分开记,就不容易把整条路线混成一个名字。
新路线:UEFI 按名单打开启动文件
较新的台式机通常使用 UEFI。它会读取保存在主板里的启动顺序,知道先尝试哪一个启动选项。这个名单可以记录启动文件在哪块设备、哪个分区、哪个文件夹里。就像前台的值班簿,写着今天先去哪个柜子里找哪份文件。
UEFI 电脑常有一个专门存放启动文件的分区,叫 EFI 系统分区。分区可以理解成硬盘上的一个独立区域。里面放着以 .efi 结尾的启动文件,例如 GRUB、Windows Boot Manager;有些 Linux 内核也能带着 EFI 启动入口,直接由 UEFI 启动。
这和老式 BIOS 的重要区别是:BIOS 的传统路线从硬盘开头的小块启动代码起步;UEFI 通常会从一个文件系统里找到启动文件。UEFI 也不是“另一个 GRUB”,它是一套共同的接口规则和固件服务,启动文件按照这套规则和固件合作。
有些电脑还会打开 Secure Boot(安全启动)。它会检查准备启动的文件是否由受信任的签名者签署,像门卫核对工作证,减少来路不明的启动程序偷偷接管电脑的机会。它不是磁盘加密,也不能保证电脑绝不会中毒;它主要保护开机早期这一段。
BIOS 和 UEFI 是固件启动路线;MBR、EFI 系统分区是硬盘上的位置;GRUB 和 Windows Boot Manager 是可以被启动的程序。
AHCI 在哪儿?它帮电脑和 SATA 硬盘说话
要从硬盘里取出启动文件,电脑还得知道怎样和硬盘沟通。台式机里的 SATA 硬盘或 SATA 固态硬盘,通常通过主板上的 SATA 控制器连接。AHCI 是软件和这种 SATA 控制器之间的一套约定,可以理解成双方都看得懂的通信语言。
打个比方:硬盘是仓库,SATA 连接线是通往仓库的路,控制器是路口的调度员,AHCI 是调度员和司机约定好的交接办法。固件要能用某种方法读到启动盘,才能找到启动程序;Linux 内核启动后,也会加载自己的存储驱动,继续从硬盘读取系统文件。
因此,AHCI 不是一段负责启动电脑的软件,它也不是 BIOS 或 UEFI。它说明软件怎样操作 SATA 控制器。电脑设置中的 AHCI 选项,通常是在选择 SATA 控制器的工作方式。
如果电脑用的是 NVMe 固态硬盘,走的则是另一条存储通信路线,通常经过 PCI Express,不使用 AHCI 这套 SATA 控制器接口。固态硬盘只是硬盘的一种类型;SATA 和 NVMe 说的是它们怎样连接、怎样与电脑通信。
开发板上的路线:Boot ROM、SPL 和 U-Boot
在很多开发板和嵌入式设备上,开机路线和台式机不完全一样。芯片可能先运行写在里面的 Boot ROM,再从闪存、SD 卡或其他地方找到 U-Boot。有些设备还会先运行更小的 SPL,准备好内存之后,再启动完整的 U-Boot。
U-Boot 是一个实际运行的启动程序。它可以寻找 Linux 内核、设备树和临时文件系统,把它们放进内存,然后把控制权交给 Linux。它像一位带着清单的搬运员:先把店长和他的地图、工具箱送到店里,再请店长开始工作。
有些 U-Boot 还能够提供 UEFI 接口。换句话说,U-Boot 是具体的软件;UEFI 是接口规则。一套软件可以按某种标准提供服务,所以 U-Boot 和 UEFI 有时会出现在同一台设备里,不一定非得二选一。
内核怎样知道机器里有哪些设备?
固件或启动程序还要把一些硬件信息交给内核。台式机常通过一种叫 ACPI 的表格告诉系统处理器、内存、电源管理和设备连接等信息;许多嵌入式 ARM 开发板常把类似的板级信息放在设备树里。它们都在帮助操作系统认识机器,但使用方式和覆盖范围并不完全相同。
可以把 ACPI 表格和设备树想成两种不同格式的房屋说明书。说明书能告诉内核某个设备在哪里、需要什么资源;真正要操作它,还要有对应的驱动程序。说明书不是工具本身,也不能代替工具。
第四步:启动程序把 Linux 内核请进来
找到 Linux 之后,启动程序会把内核文件读进内存。它有时还要准备设备树、初始内存文件系统和启动参数。启动参数像随启动文件一起交给内核的小纸条,可以告诉内核系统文件在哪里、开机信息显示在哪个屏幕或串口上。
准备好之后,启动程序会跳到内核指定的入口位置,把电脑控制权交出去。从这一刻开始,Linux 内核接过主要工作。之前的固件和启动程序已经完成了它们的接力棒任务,接下来主要由内核管理处理器、内存、设备和程序。
第五步:Linux 内核醒来,整理电脑的工作台
内核开始运行后,会继续准备自己的工作环境。它会建立内存管理方式,安排处理器之间怎样配合,准备好中断处理,再逐渐认识磁盘、显示设备、网卡和其他硬件。不同电脑的具体先后次序会有差别,但目标相同:让内核自己能够稳定地管理整台机器。
如果一台电脑有很多种硬盘控制器、网卡和显示设备,内核需要相应的驱动来使用它们。驱动可以想成专门负责某类设备的工作人员。内核先发现设备,再让合适的驱动接手;没有合适驱动时,设备可能暂时不能使用。
找到根文件系统:正式系统的入口
内核自身不是整套 Linux 系统。系统还需要配置文件、命令、服务程序和用户文件。它们通常存放在硬盘的文件系统里。内核必须找到这个文件系统,并把它挂到一个统一的入口位置,这个入口叫根目录,写作一个斜杠:/。
有些电脑一开始还没有合适的硬盘驱动、磁盘解锁工具或文件系统工具,不能马上找到真正的系统。启动程序可以再交给内核一个临时的小系统,叫 initramfs。它像一只临时工具箱:里面放着找硬盘、加载驱动、解锁磁盘和挂载文件系统可能需要的工具。
如果用了 initramfs,里面通常有一个叫 /init 的小程序。内核会先让它作为 PID 1 启动;它找到真正的系统后,切换到正式的根文件系统,再启动那里面真正负责日常工作的 init 程序。这个接力过程中,PID 1 的号码会留给同一个进程继续使用。简单的设备可能不需要临时工具箱;比较复杂的桌面 Linux 系统常用它来兼容更多硬件和启动方式。
PID 1 出场:第一个用户程序开始安排工作
等内核准备好启动用户程序的条件后,它会启动第一个普通程序。这个程序的编号叫 PID 1。PID 是“进程编号”的缩写,可以把它理解成系统给每个正在运行的程序发的号码。第一个程序拿到号码 1,所以大家叫它 PID 1。如果前面用了 initramfs,这个号码可能已经先给了临时系统里的 /init;切换到正式系统后,正式的 init 程序接过工作,但仍然是 PID 1。
传统 Linux 通常让 init 程序担任 PID 1;今天很多发行版会让 systemd 担任 PID 1。名字可以不同,工作大致相似:启动登录服务、网络服务和其他后台程序,让系统从“内核正在运行”变成“人可以登录和使用”。
桌面电脑随后会显示登录画面,服务器可能停在命令行登录提示符,路由器则会启动自己的网络和管理服务。到这里,开机接力的大部分工作就完成了。
PID 1 的“1”是第一个用户程序的编号。传统 Linux 里的“运行级别 1”通常是单用户维护模式,是另一个概念。
把几条路线并排看
开机路线图传统台式机:电源 → BIOS → 硬盘 MBR → GRUB → Linux 内核 → 根文件系统 → PID 1 → 登录
新式台式机:电源 → UEFI → EFI 启动文件 → Linux 内核 → 根文件系统 → PID 1 → 登录
嵌入式开发板:电源 → Boot ROM →(可选 SPL)→ U-Boot → Linux 内核 + 设备树 → 根文件系统 → PID 1 → 可用系统路线图里没有把 AHCI 单独画成一棒,因为它不是一个负责找下一个程序的启动软件。它像仓库和司机之间的通信办法,会在固件、启动程序或 Linux 需要读写 SATA 硬盘时发挥作用。
不同电脑的前半段可能差别很大:有的用 BIOS,有的用 UEFI,有的嵌入式设备用 U-Boot;有的从 SATA 硬盘启动,有的从 NVMe、USB 或网络启动。但它们都要完成同一件事:找到操作系统,把它需要的文件和硬件信息准备好,再把控制权交给内核。
下一篇我们沿着台式机路线往前走,专门看 BIOS 怎样从硬盘的第一小块内容开始,把接力棒一步一步交给 GRUB 和 Linux。