跳转至

UEFI 启动过程

计算机的启动

在「计算机组成原理」课程中,各位应该都编写过一个简单的 CPU,而这个 CPU 带有一段预先编写好的程序。在那时 CPU 只需要支持最简单的固定的外部设备,因此可以直接编写程序来满足这些外部设备的需要,并且把程序固化到 CPU 的 ROM 中。

但是,现实中的计算机(指 IBM PC)具有多种不同的设备,而 CPU 需要适应多种外部设备和执行环境,因此人们发明了 DDR、PCI、PS/2、USB 等多种不同的通信协议,从而构建了 CPU 和外部设备通信的标准;同时,计算机通过引入 BIOS 这个中间层来实现设备的初始化。

在现在的计算机中,主板芯片组(如 AMD B450)会带有一块小型的 ROM,其中存放了初始化计算机的各种设备的代码。主板制造商通过连接 CPU 的地址线,使得芯片组上的程序的入口地址和 CPU 通电后的默认指令地址相同。这样,计算机在启动后就会执行这段代码,来检测内存、初始化主板芯片组、检测设备,而这段代码就被称为 BIOS。

在完成了基本的初始化过程后,BIOS 将加载磁盘扇区 0 的内容,放置在 0x7C00 地址,然后跳转到该地址执行引导程序。引导程序将完成探测内存布局、加载操作系统内核等工作,并最终进入到操作系统内核中。

这里叙述的引导过程有所简化,没有讨论在没有内存的情况下如何完成内存的初始化等内容。知乎用户老狼有一系列文章叙述了计算器 BIOS 和 UEFI 相关的知识,包括 Cache As RAM、可信启动等,各位读者可以简单参考作为补充。

BIOS 与 UEFI

为了有效地让操作系统(引导程序)能够知晓系统的情况(如内存布局,也就是内存地址的分布情况),BIOS 向操作系统提供了一系列 系统调用,这些调用通过中断触发。当触发中断后,BIOS 之前在 CPU 中注册的中断处理程序就会被执行,从而执行对应的功能。

BIOS 本身没有任何的规范定义,而是各个厂家在漫长的历史实践中,建立了一系列约定,使得各个不同厂家生产的计算机能够获得相似的表现。但是,因为缺乏规范,这样的历史实践并不能保证在所有的计算机上表现一致。

此外,在 BIOS 启动的引导程序运行时,系统的内存布局存在一个特殊的约定,从而使得引导程序不必获得完整的内存布局就可以执行一些简单的工作。这段内存的大小为 1MB,对于较大的引导程序来说有些紧张。同时,一个扇区的大小只有 512B,这也限制了引导程序的代码大小。因此,现在的引导扇区程序(如 Grub)往往采用两阶段引导的模式,第一阶段称为 Boot,放置在引导扇区中;而第二阶段称为 Loader,放置在磁盘的一个特殊区域;从而突破 BIOS 的代码和内存限制。

最后,BIOS 基于中断的函数调用产生了两个问题。其一是,中断调用的效率较低,导致计算机启动缓慢。其二是,引导程序和操作系统为了实现高级功能,往往会注册自己的中断处理程序,这可能和 BIOS 发生冲突。

为了更好地解决这一问题,Intel 联合 PC 厂商建立了 UEFI 标准,这是下一代的计算机固件的接口定义。有了 UEFI,操作系统开发人员能够更好地去实现操作系统的功能,编写更加复杂的引导程序,甚至可以在引导程序或固件管理界面访问网络、显卡等高级功能。

OVMF

OVMF 是一个开源的 UEFI 固件,它是 TianoCore 项目的一部分,由 Intel 发起。

OVMF 项目的目标是为虚拟机提供一个 UEFI 固件,从而使得虚拟机能够运行 UEFI 操作系统。

OVMF 通过实现 UEFI 规范,使得在虚拟化环境中能够模拟真实硬件的启动过程。它允许虚拟机系统使用像真实计算机一样的固件和引导方式,提供更加真实和高性能的虚拟化体验。

OVMF 的开源性质使得开发者能够修改和定制固件,以适应不同的虚拟化场景和需求。它在虚拟化和云计算领域广泛应用,为虚拟机提供了更好的启动和运行环境。

实验中在仓库中为大家提供了一个 OVMF 固件,位于 assets/OVMF.fd