关于 LinuxBIOS
一年多以前,我被 Linux NetworX 聘请从事 LinuxBIOS 的工作,从那时起我就一直在陡峭的学习曲线上。在研究 LinuxBIOS 之后,我可以肯定地说,我毫不怀疑内核代码是高级代码,C 是一种高级语言。
当微处理器启动时,它开始执行位于 ROM 芯片中的指令。这些初始指令负责初始化硬件(特别是启用 RAM)并加载操作系统。此功能的实现和接口因机器而异,但其基本责任保持不变。

图 1. 启动过程阶段
在 Alpha 平台上,微处理器将整个串行 ROM(称为 SROM)读入指令缓存并开始执行代码。SROM 中的代码初始化处理器和内存,并从 Flash EEPROM 加载 SRM。然后,SRM 加载 palcode(基本上是 Alpha 上的真实内核),初始化更多硬件并加载操作系统。由于固件分为两部分,因此可以升级甚至替换 SRM。实际上,Alpha 架构的初始设计规定,每个操作系统都将有不同的固件(在 SRM 级别)。
x86 微处理器以 16 位模式开始执行代码,地址空间末尾前 16 个字节,CS 寄存器指向地址空间末尾下方 64K 处。在 8086 上,地址为 0xf000:0xfff0 == 0xffff0,正好低于 1MB。在 80286 上,地址为 0xfffff0,正好低于 16MB。在 80386 及更高版本上,此空间位于 0xfffffff0,正好低于 4GB。对于 286 及更高版本的 Intel 处理器,CS 中的值是您永远无法再次加载的值。为了弥补这一点,硬件将 ROM 芯片映射到 0xffff0000 和 0xf0000。
与 Alpha 不同,x86 处理器一次从 ROM 芯片中获取一条指令。由于 ROM 芯片本质上是 ISA 设备,这导致了一些有趣的后果,首先是在启用某种形式的缓存之前,代码运行速度非常慢。第二个影响是芯片组必须大部分启用,因为到 ROM 芯片的通常路径是从 CPU 到北桥,到 PCI 总线到南桥,到 ISA 总线到 ROM。当使用已知良好的板时,第二个事实使初始设备的调试变得更加容易。
标准 PC BIOS 具有初始化硬件、加载操作系统并在操作系统加载后提供各种服务(主要以最小设备驱动程序的形式)的责任。
SPARC 和 PowerPC 架构指定了固件,也称为 OpenBoot、Open Firmware 或已失效的 IEEE 1275。标准化的 Forth 固件与 Alpha 上的 SRM 位于大致相同的位置。关于 Open Firmware 有几个独特之处:它在多个处理器和机器架构上运行;它使用基于 Forth 的字节码,因此二进制文件与处理器无关;并且它从这个基于 Forth 的字节码执行大部分系统初始化。
Itanium/IA64 架构使用 EFI 固件,并且比 Open Firmware 更依赖于架构,因为其驱动程序是 IA32 或 IA64 代码。从范围上看,它似乎更雄心勃勃;EFI 包括 IP 堆栈和一些文件系统驱动程序。与 Open Firmware 一样,早期硬件初始化阶段未指定。
Linux 内核对固件的要求极低。Linux 内核直接驱动硬件,不使用 BIOS。由于 Linux 内核不使用 BIOS,因此大多数硬件初始化都是多余的。Linux 在这方面并不孤单;我不知道有哪个现代操作系统不遵循这一趋势。现代操作系统只需要基本的系统初始化服务。除了帮助加载操作系统外,EFI、Open Firmware 甚至 PCBIOS 等固件提供的额外设备驱动程序和系统功能都不是必需的。由于这些服务不是必需的,因此 LinuxBIOS 代码不提供它们。
LinuxBIOS 代码足以从 Flash ROM 加载编码为 ELF 可执行文件的独立程序。独立程序可以是像 Linux 这样的操作系统内核,但大多数独立程序是硬件诊断程序或引导加载程序(例如,Memtest86、Etherboot 和 RedBoot)。LinuxBIOS 预计将与独立的引导加载程序配对,以便加载操作系统。
LinuxBIOS 的最初想法是从 ROM 加载 Linux 内核,并在其之上构建引导加载程序。引导加载程序 nbc 实现了这个想法,通过网络加载 Linux 内核或独立程序,并使用 kexec 内核补丁从 Linux 启动。当有 512KB 或更多 ROM 可用时,此解决方案效果很好。不幸的是,今天出货的大多数标准主板只有 256KB 的 ROM。对于 x86 平台,几乎不可能获得小于 360KB 的可用 Linux 内核。
已经开发了各种策略来解决这些受可用 ROM 容量限制的系统。其中一些策略包括 Tiara,它似乎是 SiS630 芯片组的完整固件和引导加载程序;Etherboot,它已被移植为在 LinuxBIOS 下工作;RedBoot,它在 LinuxBIOS 下运行,但尚不可用;以及 LinuxBIOS 本身的一些 hack。
Alpha 固件要求独立程序熟悉其运行的主板,这可能会有问题。虽然具有这种程度的熟悉度很好,但支持新的主板可能非常困难,因为必须更新的软件数量很多。使用 LinuxBIOS,我们尽最大努力避免这个问题。
我们从传统的 x86 方法开始:将 Super-IO 芯片初始化为工作值和预期值(即,串行端口位于其预期的旧地址、IRQ 等),然后为 SMP 提供 IRQ 路由表和 mptables。
从长远来看,我们需要一个表来跟踪即插即用已识别的功能。此软件列出存在的硬件并配置硬件将使用的资源,或者至少列出单个设备使用的资源。我正在研究的解决方案涉及创建一个设备表,其中包含有关设备如何在主板上相互连接的信息。该表将列出当前未参与任何类型的即插即用枚举的设备,并提供足够的信息以便可以处理 IRQ 路由。此外,这个想法似乎与计划用于 2.5 内核的 struct device tree 非常吻合。ACPI 似乎提供了一种替代解决方案,但它似乎以 PC 为中心,并且解释的字节码似乎是不必要的,甚至是危险的。
自第一台 IBM PC 以来,启动 ROM 的硬件架构已经发生了很大发展,以至于今天几乎每台机器都具有可以在现场升级或从升级失败中恢复的 BIOS。实现此目的的常用技术是在主板上安装一个插槽式 Flash ROM。Flash 芯片允许软件更新它,而插槽允许在更新以某种方式失败时更换芯片。使用这种类型的硬件架构,现在可以开发自定义启动固件。对于生产机器,您可以在没有特殊硬件的情况下更新固件,并且在开发期间,如果出现问题,您可以恢复。
当前 PC 硬件架构的一个缺点是,通常启动 ROM(256KB)太小。这对于固件来说是足够的空间,但对于 Linux 内核来说不够大。
当端口正确完成时,Linux 内核可以像从标准 PCBIOS 一样从 LinuxBIOS 运行。迄今为止,我已成功将 LinuxBIOS 移植到三块主板。在最新的主板上,从 LinuxBIOS 和 PCBIOS 启动 Linux 的结果是无法区分的。因此,虽然将 LinuxBIOS 移植到新平台存在重大的技术障碍,但这些障碍是可以并且已经被克服的。
获得足够的文档是非技术因素需要考虑。说服硬件供应商支持 LinuxBIOS,或发布文档供其他人编写代码,迄今为止已取得有限的成功。缺少或有限的供应商支持对于自由软件来说并不是一个新问题,并且过去已经克服了——现在不是游戏中应该气馁的时候。值得记住的是,如果没有这些努力,就不会有新的硬件可以让我们运行自由软件。
目前,有两个不同的兴趣小组正在研究 LinuxBIOS:一个致力于嵌入式系统,另一个构建大型计算机集群。对于这些应用,传统的 x86 固件不是最优的。
LinuxBIOS 有很多值得推荐用于嵌入式应用程序的地方。由于 LinuxBIOS 是在 GPL 下发布的,因此它是免版税的。LinuxBIOS 的重量通常在 64KB 以下,并且不会因不必要的功能而浪费 ROM 空间。因为它不是传统设计,所以 LinuxBIOS 启动速度很快,即使没有代码优化也是如此。
2001 年 8 月,General Software 宣布在硬件重置后,嵌入式板上 0.8 秒启动到 LILO。这是完成这项工作的合理时间,但在 LinuxBIOS 下,如此令人印象深刻的结果是例行公事。我可以从冷启动在两秒钟内通过网络在双处理器服务器板上加载内核——无需优化 LinuxBIOS。
LinuxBIOS 的小 footprint 给 SiS 留下了深刻的印象,以至于他们专门安排了一位开发人员将 LinuxBIOS 移植到他们的芯片组,目标是嵌入式应用程序。这证明了一个得到良好支持的平台。
对于计算机集群,这正是 Linux NetworX 的专长,LinuxBIOS 也有很多值得推荐的地方。串行端口是本机控制台,因此您不需要视频硬件。串行连接可以轻松重定向到终端服务器以进行远程控制台访问。串行控制台的早期设置也带来了好处。例如,LinuxBIOS 可以通过串行控制台报告所有错误和硬件故障。即使使用串行控制台扩展,普通 BIOS 也将在游戏后期初始化串行端口,以检测某些故障,并且如果 CMOS 被清除,它通常会失败。
LinuxBIOS 还支持大多数硬件平台上的网络启动,允许通过更改 DHCP 服务器上的设置来更改启动选项。由于代码是开源的,如果网络启动策略不符合您的喜好,可以更改它。LinuxBIOS 的快速启动意味着,如果您正在调试某些内容并且必须重新启动节点,硬件不会浪费系统管理员的宝贵时间。
LinuxBIOS 的开放性及其对 Linux 的关注使其可以在 Linux 内核下的用户空间中进行配置和管理。从用户空间完成的任何事情也可以设置为远程完成。这在同构集群中是一个很大的优势,允许全局进行固件更改和管理,而不是一次一个节点。
对于大量机器,硬件故障的概率远大于单台机器。LinuxBIOS 降低的硬件要求——例如不需要软盘驱动器、CD-ROM 或硬盘驱动器来启动,以及不需要显卡和键盘来控制系统——可以带来更便宜和更可靠的系统。更少的硬件组件导致硬件故障的风险降低。
对于集群,LinuxBIOS 还带来了插入集群的潜力,并且只需运行固件,就可以拥有一台充当单个系统的机器,而不是看起来像节点集合的机架。
在 LinuxBIOS 树中,目前有 13 种不同主板的端口。LinuxBIOS 已移植到 x86 和 Alpha 硬件架构。它已在 AMD Athlon、AMD Duron、Pentium II、Pentium III、Alpha 211264 CPU、ALI m1631、Digital Tsunami、AMD 760、AMD 760MP、Intel 440BX、Intel 440GX、VIA VT8601、SiS540、SiS550、SiS630 和 SiS730 芯片组上运行。这只是已完成并放置在主 LinuxBIOS 树中的代码。其他端口仍在进行中,截至撰写本文时尚未提交。因此,虽然硬件支持有限,但列表正在增长。LinuxBIOS 目前不与任何特定的芯片组、供应商或处理器架构绑定。
硬件支持的质量各不相同。在芯片组方面,对 SiS 芯片组的支持非常好。Intel 和 AMD 都有记录其芯片组的标准政策,因此两者的支持都相当不错。Via 没有公开记录他们较新的芯片组,这使得这里的支持成为一个挑战。
在处理器方面,Compaq 公布了重要的细节,因此支持 Alpha 处理器是可行的。然而,Alpha 的开发并不是高度优先事项,因为 Alpha 是一款昂贵的处理器,未来前景不明朗。
Pentium II 和 Pentium III 在 Intel 手册中有相当详细的文档,除了其插槽处理器的 L2 缓存初始化(L2 缓存初始化现在已受支持)。AMD Athlon 和 Duron 没有得到很好的支持,因为 AMD 没有公开记录其处理器需要设置的所有内容。
来自主板制造商的支持不是必需的,因为在大多数情况下,只需查看一下即可识别主板上的组件。
主板制造商通常只对支持其主板的一个固件感兴趣。由于 LinuxBIOS 目前不提供启动 Linux 以外的其他操作系统(尤其是 Windows)的兼容性层,因此主板制造商对以当前形式部署 LinuxBIOS 没有太大兴趣。
LinuxBIOS 为固件的工作、其结构、编写和许可方式提供了创新的视角。随着机器变得越来越集成,LinuxBIOS 正在崛起以满足对更大代码重用和灵活性的需求。如果对该技术日益增长的兴趣有任何迹象表明,它看起来将拥有光明的未来。

Eric Biederman (ebiederman@linuxnetworx.com) 是 Linux NetworX 的软件工程师,专注于 LinuxBIOS 并帮助开发集群管理工具。当不深入参与 LinuxBIOS 时,Eric 会阅读科幻小说、玩 DOSEMU 并在盐湖城郊外的 Wasatch 山脉周围远足。