思考人生、专注技术
分类: C/C++
2007-12-18 15:05:42
在很多系统上,引导时间中有很大一部分都花费在为 MS-DOS 提供传统支持上面了。有很多项目,包括 LinuxBIOS 和 Open Firmware,都试图使用最新的代码来替换原有的 BIOS 系统,它们只实现加载并运行 Linux® 内核所必需的功能。本文对这个领域的内容简要进行了介绍。
响铃!
尽管在 PC 硬件加电时喇叭响一下看起来似乎是件非常自然的事情,但实际上却有一些代码来驱动喇叭发声。这段代码就是引导固件。在大部分 PC 上,这都称为 BIOS(这个单词是 basic input/output system(基本输入/输出系统)的缩写)。BIOS 提供了底层的硬件支持,早期的 x86 操作系统就是使用它们来访问磁盘、显示器和其他东西的。
BIOS 要做的第一件事情是执行各种加电测试:确定(还可能要测试)可用内存、确定时钟速度等。如果测试成功,机器的喇叭就会响一声。这个过程就称为加电测试(power-on self test)或 POST。计算机对于自己是相当幽默的,这个术语通常会被当作动词来使用:“这台机器根本通不过 POST 测试,因此我们应该更换内存”。
通常的诊断包括响铃代码(不同供应商提供的代码都不相同),或者可以写入到某个特定裸地址的代码。有些后插的卡可以简单地访问这些代码;标准的解决 方案是诊断代码都写到 80 端口中。有些制造商会销售一种卡,它可以以 16 进制的形式显示最新写入到 80 端口的内容。如果我们要进行严格调试,可能就会希望有一个这种卡,或者希望使用一个更好的发明,例如 PC Weasel,它可以记录最新的(256)POST 代码以供大家阅读。(有关 PC Weasel 的更多信息请参看下面的 参考资料 一节的内容。)当然,这些代码的确切含义对于各个 BIOS 来说不尽相同,只有部分供应商提供了文档。幸运的是,开源供应商提供了很好的文档。
诸如 MS-DOS 之类的操作系统可以加载其他设备驱动程序,例如 CD-ROM 驱动器,但是需要所有硬件驱动程序在启动时就已经加载上来了。为这些驱动程序提供的标准接口是由 BIOS 来处理的,正是由于这个原因,BIOS 需要对设备进行探测、识别,还可能要进行初始化。
同样,BIOS 要负责对内存进行初始化。并非所有的操作系统都需要对内存进行初始化,但是早期的 DOS 系统通常都需要进行这种操作,即使在今天大部分 BIOS 为了兼容性的目的也需要进行初始化。这个过程自己可能需要很长时间才能完成,很多现代系统允许彻底或部分地将其禁用。同时,BIOS 还会试图确定系统中有多少内存可用。其他的引导时操作还可能包括对处理器缓存的初始化和启用,配置双 CPU,构建有关处理器的信息表,构建连接到系统中的 PCI 设备,甚至运行这些设备提供的引导 ROM,这可以加载其他驱动程序。
这里有很多工作需要做。实际上这些工作是如此繁杂,我的某些系统要花一分钟甚至更长时间才能完成 POST 和后续的驱动程序初始化过程。BIOS 可以执行各种硬件扫描,从而寻找可引导的设备,在某些系统上,BIOS 甚至可以执行通过以太网进行的网络引导。我的一个系统就会花大约 5 秒钟的时间来初始化网络引导参数,即使在禁用了网络引导功能的情况下也是如此。这可真令人懊恼!
最后一点(但不是最不重要的一点),BIOS 还需要做相当多的初始化工作。不管您要引导什么系统,这些工作中的一部分(但并非全部)都会非常有用。为设备分配中断请求(IRQ)的确是一个非常有用的 服务,因为它允许 OS 只获取一个服务列表并开始运行,而不用对它们进行编程。很多设备都有配置寄存器,BIOS 可以基于系统可写内存中的设置向其中写入合理或正确的值。(通常来说,这种内存都称为 CMOS,尽管它们并非严格要求使用这种技术来实现。)
在 BIOS 完成上面这些功能之后又会发生什么呢?它会在某个地方(通常是在磁盘上)查找一段代码,并运行它,这通常会加载一个操作系统。如果操作系统是 DOS,或其他类似的东西,那么这种设置工作就意味着我们可以很快就有自己的命令提示符了。
|
但是对于 Linux、BSD 或 Windows® 来说,操作系统有自己的驱动程序。因此,操作系统可以丢弃连接到系统上的 PCI 设备列表,并开始加载这些设备。BIOS 所做的工作大部分会被忽略掉,操作系统一旦加载 SCSI 驱动程序之后,就会自行扫描 SCSI 总线。BIOS 并没有做什么其他工作,仅仅是提供信息而已,并且它所提供的很多信息也都不会被使用。BIOS 实际上需要做的事情是加载第一段代码(称为引导加载程序(bootstrap loader)或 bootloader),并让机器开始运行。
因此,在负载相当重的机器上,我们需要等待每个设备都被探测两次。通常,SCSI 控制器的引导 ROM 要花费相当长的时间来扫描设备。更为糟糕的是,在引导 ROM 运行时,其他东西都无法运行。与之不同的是,现代操作系统可以很好地加载 SCSI 驱动程序,发起一个总线重置命令,在检查设备完成之前就可以继续加载其他驱动程序,并执行网络设备的加载。简而言之,操作系统的扫描要比 BIOS 的扫描速度更快。
确切的速度差异取决于操作系统。不过我们知道 Linux 的引导时扫描可以非常快。这意味着 BIOS 不仅要花从加电到最后一个内核模块加载时间的一半在这上面;有时还可能会花费更多时间。当重要性较低的内核模块(例如声卡驱动程序)在引导过程最后加载时 (此时一些重要的东西,例如 Web 服务器,可能已经加载了),这种现象更加明显。
我们希望要的是一种不用等待 BIOS 来做大量有关内核的工作就可以加载内核的方法 —— 这样可以更快、更好、更可靠地完成引导过程。
|
如果我们将所有的设备驱动程序从 BIOS 中删除,显然有很多问题都需要考虑:BIOS 是否没有加载所有的设备驱动程序?它怎样读取内核?一种简单的解决方案是使用因忽略维持一个小型内核所需的设备驱动程序而释放出来的所有空间。这种内核所 需要加载的东西就是磁盘的设备驱动程序,其他可加载的模块都可以保存在磁盘上。然后在内核启动之后,可以动态加载这些模块。
现代 BIOS 闪存芯片使得这个过程令人惊奇地成为了可能。很多系统都有 1 MB 或 2 MB 的闪存给 BIOS 使用。有时候,实际的 BIOS 也就这么大。另外一些时候,这种芯片也都已经非常便宜了。精简并压缩过的内核可以很容易地放入这种空间中,Linux 引导加载程序在构建小型的解压程序来展开压缩内核方面有着非常丰富的经验。
这种解决方案对于积极参与内核开发的人来说可能没有什么好处,但是对于一个希望尽快引导的系统来说,可能会获益良多。LinuxBIOS 项目(请参看 参考资料)就正在开发这样一个解决方案,这对于服务器和嵌入式用户来说可能最合适不过了。
|
不是为 MS-DOS 设计的引导固件的一个主要分支是 Open Firmware。它通常由 Sun 和 Apple 使用,这种引导固件的开放标准设计时很少关注 DOS 风格的系统,它更感兴趣的是诸如最初的 Mac OS、Mac OS X 或 Solaris 之类的系统,它期望能够实现自己的驱动程序的工作。Open Firmware 的一大优点是它是 “一次编写,随处运行” 的:使用 Open Firmware 的引导 ROM 的设备只能在具有安插这些设备的总线的 Open Firmware 系统上正常工作。这带来的一个问题是很少为 x86 PC 设计的设备具有 Open Firmware 引导 ROM。不过,如果我们可以找到一个具有这种引导 ROM 的设备,这就可能是一种很好的选择了;当然,这需要我们指定自己的硬件平台,并对特定组件进行标准化。
Open Firmware 对黑客来说可能是界面最为友好的 BIOS 风格控件。尽管它并不像 LinuxBIOS 之类的项目一样重点关注的是引导速度,但是其速度通常都比传统的 PC BIOS 快很多,这对于希望对自己机器进行配置的用户来说显得尤其友好。
如果 x86 供应商缺省开始使用 Open Firmware,这个世界将变得更加友好。
|
即使只是试图重新实现传统 BIOS 的基本功能的 BIOS,也通常使得速度更快,实现也更为开放。例如,如果我们知道某个给定系统上没有需要花费 5 到 10 秒进行探测的设备,就可以调节用来进行设备探测所进行的 BIOS 延时。
免费的 BIOS 可以实现的一种重要功能是在构建引导加载程序时具有更好的灵活性。例如,OpenBIOS 项目就已经与 LinuxBIOS 联合起来使用了,它们使用了 LinuxBIOS 的底层代码,并使用一个 OpenBIOS Forth 内核作为有效内核,从而将一个系统引导到 Open Firmware 中。x86 系统中很多最为困难的工作是构建小型的代码块来加载真正的引导加载程序;更灵活的 BIOS 可以完成这种工作,并解决这个问题。
注意,尽管 LinuxBIOS 的目标主要是为 Linux 设计的,不过它正在用来引导其他系统;例如,在 2002 年末,LinuxBIOS 用户就成功使用它引导了 Windows 2000。尽管扩展兼容性的努力和技术支持正在进行,但是消除系统引导对私有软件的依赖性依然是非常重要的一个方向。
还有一些非常专用但却并不免费的 BIOS 程序。例如,Soekris Engineering 系统就运行了一个名为 comBIOS 的 BIOS,它比常见的 BIOS 更加简单,尺寸也更小,引导速度也更快。
|
当人们与计算机问题展开搏斗时,他们收到的一个最为常见的建议就是应该更新 BIOS。为什么呢?理论上来说,BIOS 在系统加载之后就不会被真正使用了。然而,实际上 BIOS 所完成的初始化工作都是非常关键的。例如,在我使用的一个嵌入式的 x86 系统上,CardBus 控制器无法使用了,这是因为它需要一个 IRQ 进行编程;升级 BIOS 可以修复这个问题。理论上来说,操作系统可能已经开发了特殊的代码来识别这个 CardBus 控制器的精确模型,并使用一个 IRQ 进行编程;但是主板供应商处于一个更加有利的位置,它们可能向这个 IRQ 中写入了主板特有的代码,这样才能对控制器正确进行编程。
以我们传统的经验来讲,开源系统可以更好地修复 bug。然而,在 BIOS 的情况下,情况却并不如此明显。毕竟,原始的硬件供应商可能了解通用 BIOS 开发人员所没有的一些信息。通用免费的 BIOS 软件需要在很多主板上运行;供应商的情况却并不相同,它们可以假设不用担心代码在不同硬件上运行的问题。
尽管如此,开源方法也有很多优点。例如,我使用的一个老式 Alpha 系统可以支持 Symbios Logic 的 875 SCSI 控制器芯片。然而,它硬编码了一个 PCI 供应商/产品 ID 对的列表,其中保存的是已知的支持设备,它只能使用这个列表中的卡;其他卡即使能够工作,如果不在这个列表中,也不能在这个系统上使用。由于它的 BIOS 不是开源的,这个问题就显得有些混乱了,我无法对这个表打补丁进行修正;我只好花了 220 美元从一个特殊的供应商那里购买了一个 SCSI 卡,而不能使用一个等效的销售价格为 75 美元的卡。
当有一个主板供应商决定使用一个开源的 BIOS 而不继续使用主流的商业实现时,将可能会出现一个转折点。我不知道这是否会真的发生,什么时候发生,但是看到一个 BIOS 能够获得更好的支持并提供丰富的文档将是件非常好的事情。
|
对于大部分用户来说,这有些不切实际。烧坏 BIOS 芯片的危险依然相当高:在重新烧制 BIOS 之前,计算机根本就无法工作了,由于计算机并不能引导以刷新芯片,因此我们必须采用一些特殊的硬件来实现这种功能。有些系统具有两个闪存芯片,这让我们可 以使用其中一个来引导系统,然后对另外一个进行编程,但是并非所有的系统都有这种功能。因此,对于大部分用户来说,试验其他 BIOS 设计可能有些冒险。不过,如果您自己找到一台空闲的旧式机器,又愿意冒险来试验一下,又有一个免费的 BIOS 项目可以支持这种系统,那么体验一下将会非常有趣。兴趣将使您爱上它。
对于从事服务器或嵌入式系统工作的人来说,他们更可能从这种技术中获益。如果重新启动系统的时间对于您来说非常重要,那么您就会有很大的动力来花一 些时间和精力让这种类似技术在您使用的系统上可以运行。另外,如果您没有做一件疯狂且毫无技术支持的事情,那么去做嵌入式开发项目对您来说可能就没有任何 乐趣。
最后,这种技术可以为供应商提供更多选择。嵌入式系统的供应商对于引导固件有更多选择,这可以帮助我们远离少量的专有 BIOS 设计,进入更加开放和相互竞争的市场。
Peter Seebach 已经使用计算机很多年了,也正在逐渐适应计算机的特性。不过他仍然不清楚为什么鼠标要如此频繁地进行清洗。 |