自由及开放源码软件项目聚焦:LinuxBoot

Linux 作为固件。

变化越多,不变的也越多。这听起来可能很老套,但这对于引导操作系统的固件来说仍然是真实的,就像 2001 年《Linux Journal》首次发表 Eric Biederman 的“关于 LinuxBIOS”时一样。LinuxBoot 是一个已经持续了大约二十年的想法的最新体现:使用 Linux 作为引导程序。

在大多数系统中,固件的存在是为了使硬件处于操作系统可以接管的状态。在某些情况下,固件和操作系统紧密相连,甚至可能是同一个二进制文件;然而,基于 Linux 的系统通常有一个固件组件,在加载 Linux 内核本身之前初始化硬件。这可能包括 DRAM、存储和网络接口的初始化,以及在启动 Linux 之前执行与安全相关的功能。为了提供一些视角,这种 Linux 之前的设置在 1999 年可以用大约 100 条指令完成;现在超过了十亿条指令。

通常有人建议应该将 Linux 本身放在引导向量中。那是最初在 x86 上尝试 LinuxBIOS 的方法,它看起来像这样


#define LINUX_ADDR 0xfff00000; /* offset in memory-mapped NOR flash */
void linuxbios(void) {
       void(*linux)(void) = (void *)LINUX_ADDR;

       linux();  /* place this jump at reset vector (0xfffffff0) */
}

然而,这并没有取得太大进展。当时的 Linux 还没有达到可以完全自引导的程度——例如,它缺乏初始化 DRAM 的功能。因此,LinuxBIOS(后来更名为 coreboot)实现了启动内核所需的最低限度的硬件初始化功能。

如今,Linux 已经成熟得多,可以自行初始化更多——虽然不是全部——的东西。这在很大程度上与需要将系统和电源管理功能(例如睡眠状态和 CPU/设备热插拔支持)集成到内核中以获得最佳性能和节能有关。虚拟化也促进了 Linux 自引导能力的提升。

固件启动和运行时组件

现代固件通常由两个主要部分组成:硬件初始化(早期阶段)和操作系统加载(后期阶段)。这些部分可以根据实现方式进一步划分,但整个流程在启动固件中是相似的。后期阶段多年来获得了许多功能,并且通常具有包含驱动程序、实用程序、shell、图形菜单(有时带有 3D 动画)等的环境。运行时组件可能在固件退出后仍然驻留并处于活动状态。过去可以装在 8 KiB ROM 中的固件,现在包含一个用于引导另一个操作系统的操作系统,并且不总是在操作系统启动后停止运行。

图 1. 固件组件和启动流程的总体概述

LinuxBoot 将后期阶段替换为 Linux 内核和 initramfs,它们用于加载和执行下一阶段,无论它是什么以及来自哪里。LinuxBoot 中包含的 Linux 内核被称为“引导内核”,以区别于将被引导的“目标内核”,目标内核可能是 Linux 之外的其他东西。

图 2. LinuxBoot 组件和启动流程

将 Linux 内核与固件捆绑在一起,通过两种主要方式简化了固件。首先,它消除了固件包含驱动程序以支持不断增加的各种启动介质、网络接口和外围设备的需要。其次,我们可以使用 Linux 用户空间中熟悉的工具,例如 wget 和 cryptsetup,来处理诸如下载目标操作系统内核或访问加密分区之类的任务,这样固件的后期阶段就不需要(重新)实现复杂的工具和库。

对于具有 UEFI 固件的系统,所有需要的只是 PEI(预 EFI 初始化)和少量的 DXE(驱动执行环境)模块,用于 SMM 和 ACPI 表设置等。使用 LinuxBoot,我们不需要大多数 DXE 模块,因为外围设备的初始化由 Linux 驱动程序完成。我们还可以跳过 BDS(启动设备选择)阶段,该阶段通常包含一个设置菜单、一个 shell 和加载操作系统所需的各种库。同样,coreboot 的 ramstage(初始化各种外围设备)可以大大简化或跳过。

除了启动路径之外,固件还捆绑了运行时组件,用于处理错误和其他硬件事件。这些被称为 RAS(可靠性、可用性和可维护性)功能。RAS 功能通常被实现为高优先级、高特权的、在操作系统上下文之外运行的中断处理程序——例如,在 x86 上的系统管理模式 (SMM) 中。这带来了性能和安全问题,LinuxBoot 正在通过将一些 RAS 功能移至 Linux 来解决这些问题。有关更多信息,请参阅 Ron Minnich 在 ECC'17 上的演讲“让我们将 SMM 从固件移到内核中”。

引导内核使用的 initramfs 可以是用户可以放入引导 ROM 中的任何与 Linux 兼容的环境。有关想法,请参阅《Linux Journal》在 2018 年 2 月发布的“自定义嵌入式 Linux 发行版”

一些 LinuxBoot 开发人员也在开发 u-root (u-root.tk),这是一个用 Go 编写的通用 rootfs。Go 的可移植性和快速编译使得可以将 u-root initramfs 作为源代码包捆绑在一起,只需少量工具链二进制文件即可动态构建环境。这使得可以在系统上进行实时调试(例如,通过 BMC 的串行控制台),而无需重新编译或重新刷新固件。当在现场遇到错误或难以重现错误时,这尤其有用。

开放性和使用 LinuxBoot 的优势

虽然 LinuxBoot 可以使那些熟悉 Linux 并希望更多控制其启动流程的人受益,但拥有大量 Linux 基础服务器或产品的公司将获得最大的收益。他们通常拥有工程师团队或整个组织,他们在开发、部署和支持 Linux 内核和用户空间方面拥有专业知识——毕竟他们的业务依赖于此。

用 Linux 替换晦涩难懂且通常是封闭的固件代码,使组织能够利用他们已经拥有的人才来优化其服务器和产品的启动流程、维护和支持功能,跨越来自不同供应商的几代硬件。LinuxBoot 还使他们能够在跟踪和解决与启动相关的问题时采取主动而非被动。

LinuxBoot 用户在使用具有高度硬件资源访问权限并设置平台安全策略的启动代码时,可以获得透明性、可审计性和可重现性。这一点比以往任何时候都更加重要,因为资金充足且高度复杂的黑客正在不遗余力地渗透基础设施。组织必须跳出防火墙的思维,并考虑从供应链攻击到硬件接口和协议实现中的漏洞等威胁,这些漏洞可能导致特权升级或中间人攻击。

虽然不完美,但 Linux 提供了健壮、经过良好测试和良好维护的代码,这对许多组织来说至关重要。它是开放的,并由从个人到数十亿美元公司的庞大社区积极开发。因此,它非常擅长支持新设备、最新协议和获取最新的安全修复程序。

LinuxBoot 旨在为固件做 Linux 为操作系统所做的事情。

谁在支持 LinuxBoot 以及如何参与

尽管使用 Linux 作为其自身引导加载程序的想法由来已久,并且已在各种设备中使用,但在协作或项目结构方面做得很少。此外,硬件预装了一个完整的固件堆栈,该堆栈通常是封闭的和专有的,用户可能不具备修改它所需的专业知识。

LinuxBoot 正在改变这种情况。最后缺失的部分正在积极制定中,以为新平台提供完整的、可用于生产的引导解决方案。还在开发工具来重组标准 UEFI 镜像,以便可以对现有平台进行改造。虽然当前的努力是针对以 Linux 作为目标操作系统,但 LinuxBoot 有潜力引导其他操作系统目标,并为这些用户提供前面提到的相同优势。LinuxBoot 当前使用 kexec,因此可以引导任何 ELF 或 multiboot 镜像,并且将来可以添加对其他类型的支持。

贡献者包括来自 Google、Horizon Computing Solutions、Two Sigma Investments、Facebook、9elements GmbH 等公司的工程师。他们目前正在形成一个有凝聚力的项目结构,以促进 LinuxBoot 的开发和采用。2018 年 1 月,LinuxBoot 成为 Linux 基金会内的官方项目,并设立了一个由致力于其长期成功的成员组成的技术指导委员会。目前还在努力将 LinuxBoot 作为开放计算项目开放系统固件项目的组件包含在内。OCP 硬件社区启动了这个项目,以确保云硬件具有安全、开放和优化的启动流程,以满足云提供商不断变化的需求。

LinuxBoot 利用 Linux 的能力和势头来开放固件,使来自不同背景的开发人员能够改进它,无论他们是硬件启动、内核开发、工具、系统集成、安全还是网络方面的专家。要加入我们,请访问 linuxboot.org

关于作者

David Hendricks 和 Andrea Barberio 是 Facebook 的工程师,他们的团队负责服务器的验证、配置和维护运营。Ron Minnich 于 1999 年发明了 LinuxBIOS,现在称为 coreboot。他于 2017 年在 Google 启动了 LinuxBoot 项目,现在正与 Gan Shun Lim 和 Christopher Koch 合作在 Google 的基础设施中部署 LinuxBoot。

加载 Disqus 评论