系列文章: http://www.ibm.com/developerworks/cn/views/linux/libraryview.jsp?search_by=%E5%AD%A6%E4%B9%A0+linux+101
从 BIOS 到运行 Linux 系统
引导顺序
在我们深入了解启动加载程序(比如 LILO 和 GRUB)之前,先来重温一下 PC 是如何启动或引导 的。名为 BIOS(表示 Basic Input Output Service)的代码存 储在 ROM、EEPROM 或闪存等非易变 (non-volatile) 内存中。当启动或重启 PC 时,会执行该代码,并执行开机自检 (Power-On Self Test, POST) 来检查机器。它还会确定可用移动存储设备或固定存储设备中的引导驱动器,然后从该驱动器上的 Master Boot Record (MBR) 加载第一扇区。引导驱动器可以是传统硬盘驱动器、固态驱动器、USB 记忆棒 (stick) 或驱动器、或者带有可移动媒介(比如磁盘、CD 或 DVD)的驱动器。本文主要关注硬盘驱动器,但其他类型的存储设备的引导进程均与硬盘驱动器相似。
正如文章 “学习 Linux,101:硬盘布局” 所描述的,因为 MBR 还包含分区表,所以 MBR 中的可执行代码小于 512 字节,这个代码量不算大。注意,每个磁盘(即使是软盘、CD、DVD 或者 USB 记忆棒之类的固态设备) 的 MBR 中均包含一个可执行代码,即使这个代码只能用于显示一条消息,比如 "Non-bootable disk in drive A:(驱动器 A 中没有可引导磁盘:)"。这个由 BIOS 从第一扇区加载的代码称为第一阶段启动加载程序 或阶段 1 启动加载程序。
MS DOS、PC DOS 和 Windows® 操作系统所使用的标准硬盘驱动器 MBR 会检查分区表,以查找主分区上标记为 active 的引导驱动器,加载该分区的第一扇区,然后将控制权交给已加载的代码。这个新代码也称为分区引导记录。分区引导记录实际上是阶段 1 的另一个启动加载程序,但它只能从分区加载一组块。该新组块中的代码称为阶段 2 启动加载程序。MS-DOS 和 PC-DOS 使用的阶段 2 加载程序直接继续加载操作系统其余部分。以上就是操作系统启动并运行的引导进程。
这个引导进程对于单操作系统很适用。但是,如果您想要使用多个操作系统,比如 OS/2、Windows XP 和 3 个不同的 Linux 发行版,那么会出现什么样的情况呢?您可以 使用一个程序(比如 DOS FDISK 程序)来更改活动分区并重新启动,但这种方法比较笨拙。此外,一个磁盘只能拥有 4 个主分区,而标准 MBR 只能拥有一个主分区;系统不能从逻辑分区引导。但我们假设的示例提到了 5 种操作系统,每个系统都需要一个分区。
该问题的解决方案是使用一些特殊代码,允许用户选择引导哪个操作系统。此类程序包括:
-
Loadlin
- 一个 DOS 可执行程序,可以在一个正在运行的 DOS 系统中调用以引导一个 Linux 分区。如果多引导系统的设置过程很复杂、风险很大时,这个代码就很有用。 OS/2 Boot Manager
- 这个程序安装在一个专用小分区上,分区被标记为 active,标准 MBR 引导进程启动 OS/2 Boot Manager,之后会显示一个菜单用于选择要引导的操作系统。 智能启动加载程序
-
该程序可以驻留在操作系统的分区上,并可以通过一个活动分区的分区引导记录调用,也可以通过主引导记录调用。此类程序包括:
- BootMagic(Norton PartitionMagic 的一个组件)
- LILO (LInux LOader)
- GRUB (GRand Unified Boot loader)(现在称为 GRUB Legacy)
- GRUB2(一个新型启动加载程序,经常出现在一些常见的发行版中)
很明显,如果能够将系统控制权交给某个包含 512 字节以上代码的程序来完成其任务,那么支持从逻辑分区引导或从位于引导驱动器之外的分区引导应该不太难。上述解决方案都支持这些可能性,这是因为它们都能 从任意分区加载引导记录,或者是因为它们都对启动引导过程需要加载哪个或哪些文件有所理解。
链式加载
当一个引导管理器获得控制权时,它能做的一件事就是加载另一个引导管理器。这种现象称为链式加载 (chain loading), 通常发生在位于主引导记录 (MBR) 中的引导管理器加载一个分区引导记录中的启动加载程序的时候。当一个 Linux 启动加载程序被请求引导一个 Windows 或 DOS 分区时,或者当一个系统的 Linux 启动加载程序被请求加载另一个系统的启动加载程序时,几乎总是需要进行链式加载。例如,您可能需要使用一个分区中的 LILO 链式加载另一个分区中的 GRUB,以便访问该分区中的 GRUB 菜单。
Linux 启动加载程序
接下来我们要关注的是 LILO 和 GRUB,因为它们是大多数 Linux 发行版包含的启动加载程序。LILO 的历史长一些,而 GRUB 比较新。原始 GRUB 现在已成为 GRUB Legacy,GRUB2 正处于开发中,它是由 Free Software Foundation 赞助(请参见 参考资料 了解相关的详细信息)。我们将简要讨论 GRUB2,阐述 GRUB 和 GRUB2 之间的主要区别,以及二者如何能够共存。对于本文余下部分,我们假设 GRUB 是指 GRUB Legacy,除非上下文明确表示为 GRUB2。LILO 也有一个新版本,称为 ELILO(其设计意图是用于引导使用 Intel 而非使用 BIOS 的 Extensible Firmware Interface (EFI)。请参见 参考资料 了解关于 GRUB2 和 ELILO 的其他相关信息。
您的发行版的安装过程可能支持选择设置哪个启动加载程序。GRUB 和 LILO 都支持大多数小于 2TB 的现代磁盘,但有些发行版(最著名的是 Fedora)不再包含 LILO。别忘了,磁盘技术已经飞速发展,因此您应该总是确保所选的启动加载程序、Linux 发行版(或其他操作系统)以及您的系统 BIOS 适用于您的新磁盘。否则,就有可能导致数据丢失。同样,向现有系统添加新发行版时,可能需要确保您的 MBR 中拥有最新的 LILO 或 GRUB。如果您打算从 LVM 或 RAID 磁盘引导,也需要拥有比较新的 GRUB 或 LILO 版本。
LILO 和 GRUB 中使用的阶段 2 加载程序允许从几个操作系统或版本中选择其中之一。但是,LILO 和 GRUB 差别很大:只要升级内核或对系统进行其他更改,就需要使用一条命令重新创建 LILO 引导设置;而 GRUB 支持通过一个可编辑配置文本文件来完成这个任务。GRUB2 也需要从一个通常存储在 /etc 中的配置文件进行一个重构。
下面小结 PCs 的引导过程:
- 当 PC 启动时,BIOS (Basic Input Output Service) 会执行一个自检。
- 当机器通过自检时,BIOS 会加载 Master Boot Record(或 MBR,通常位于引导驱动器的第一个 512 字节扇区)。引动驱动器通常是系统上的第一个硬盘驱动器,但也可以是一个磁盘、CD 或 USB 密匙。
- 对于硬盘驱动器,MBR 加载一个阶段 1 启动加载程序,该程序通常是 Linux 系统上的 LILO 或 GRUB 阶段 1 启动加载程序。这是另一个 512 字节单扇区记录。
- 阶段 1 启动加载程序通常加载一个记录序列,该序列通常称为阶段 2 启动加载程序(有时称为阶段 1.5 加载程序)。
- 阶段 2 加载程序加载操作系统。对于 Linux,这是内核,也可能是初始 RAM 磁盘 (initrd)。
您的系统应该能够安装两个流行启动加载程序的其中一个:LILO (LInux LOader) 或 GRUB (GRand Unified Boot loader)。您应该能够使用所选的启动加载程序按前面描述的方式执行引导。如果您想回顾启动加载程序安装或基本引导过程,请参阅配套文章 “学习 Linux,101:引导程序”。
可以采用以下方法影响您的系统引导过程:
- 更改引导设备。您可能通常从硬盘驱动器引导,但有时可能需要从软盘、USB 内存密匙、CD 或 DVD,或者网络引导。要设置这类引导设备,您需要适当配置 BIOS;在引导过程中可能还需要一个特殊键击,以便显示一些选项。我的一个系统上的选项如 图 1 所示。设置引导设备和选择在启动时引导设备的方法特定于您的系统及其 BIOS。这也超出了这个 LPI 目标的要求,您可以参考您的系统文档。
图 1. 选择引导设备 - 可以与启动加载程序交互,选择引导哪个配置。本文稍后将介绍如何针对 LILO 和 GRUB 完成这个任务。
- 您可以使用 GRUB 或 LILO 来将参数传递到内核,控制内核被启动加载程序加载后启动系统的方式。
GRUB
GRUB 配置文件默认为 /boot/grub/grub.conf 或 /boot/grub/menu.lst。如果二者同时存在,那么一个通常是另一个的符号链接。清单 5 展示了上面用于 LILO 的系统的一个示例。注意,为了便于阅读,我们已将三个内核定义语句分割为多个行。
清单 5. GRUB 配置示例
|
GRUB 提供一个菜单界面。它还使用一个通过 MD5 算法加密的密码,而不是 LILO 的纯文本密码。而且,也许最重要的是,对 GRUB 配置文件进行的更改不需要在 MBR 中安装 GRUB。注意,许多发行版均能在更新到一个新的内核级别时自动更新 GRUB(或 LILO)配置文件,但是,如果您安装一个新内核或创建一个新的初始 RAM 磁盘,那么可能需要编辑配置文件。
要为分区配置一个启动条目,GRUB 不需要装载该分区。您将看到 root (hd0,9)
和 splashimage=(hd1,12)/boot/grub/splash.xpm.gz
这样的条目。GRUB 将您的硬盘引用为 hdn,其中 n 是一个整数,从 0 开始。类似地,磁盘上的分区从 0 开始编号。注意:GRUB2 已经更改了磁盘命名方式,因此在 GRUB 和 GRUB2 之间切换时要小心。
因此,在这个系统上,(hd0,0) 代表 Windows 主分区 /dev/sda1,而 (hd0,9) 代表 Slackware 逻辑分区 /dev/sda10。软盘驱动器通常是 (fd0)。如果使用这些参数从一个 bash shell 调用 GRUB,例如,在软盘、USB 密匙或您的 MBR 上安装 GRUB 时,别忘了使用引号将参数引起来。
新版 GRUB 允许使用一个标签 或一个 UUID 来指定 root
元素。要详细了解标签和 UUIDs,请参阅配套文章 学习 Linux,101:控制文件系统的安装和卸载 中的 “标签、UUID 和链接” 小节。
使用 GRUB 引导系统时,经常会看到一个默认选项,如 图 5 所示。如果您不做任何操作,会在配置超时后启动这个选项。这里的超时值单位为秒,因此清单 5 中的 timeout=5
表示一个 5 秒的超时。
图 5. 引导 GRUB 到一个默认选项
如果您按任意键中断默认启动,将会看到一个类似于 图 6 的选项菜单。
图 6. GRUB 菜单选项
GRUB 菜单显示时,可以使用光标移动键在列表中上下移动,选择一个引导映像。
自定义背景
如果您想对 GRUB 使用不同的启动图像,那么您只能使用 14 色 X Window pixmap (.xpm) 文件,而且文件必须被 gzip 压缩。您钟爱的 JPEG 图像将会减少到 14 色时看起来可能有些不同,因此您需要试验试验,看看效果。可以使用诸如 GIMP 的图形程序将图像减少到 14 色,这时应该使用 Image->Mode->Indexed... 菜单动作并将 Maximum number of colors 字段设置为 14。也可以使用命令行工具,比如 ImageMagick。清单 6 显示将一个 800x531 原始图像减小到需要的 640x480 像素的一种方法:首先将其缩小到 640 像素高,然后裁剪部分图像,减小画布以匹配图像。然后,我们将颜色数量减少到 14,将图像格式从 .jpg 转换为 .xpm。最后我们 gzip 压缩图像。
清单 6. 构建一个自定义 GRUB 启动图像
|
GRUB shell
与 LILO 不同,GRUB 的表现形式是一个小 shell。它包含几个命令,允许执行类似操作:在命令执行之前编辑命令、查找并加载配置文件、或者使用 cat
命令显示文件。在菜单中的条目上按 e 键将编辑条目,按 c 键切换到 GRUB 命令行,按 b 键引导系统,按 p 键输入密码,按 Esc 键返回菜单或上一步。还有一个 grub
命令,用于创建一个模拟 shell,可以在其中测试 GRUB 配置或您的 GRUB 命令技能。普通用户模式提供一些基本组件,但许多命令都需要根权限。清单 7 展示如何作为根用户启动 grub shell。这个 grub 命令通常位于 /sbin 或 /usr/sbin 中。
清单 7. 启动 GRUB shell
|
在 GRUB shell 中,help
命令提供一列表的命令。help commandname
提供 commandname 命令帮助。清单 8 显示了可用命令和 rootnoverify
命令帮助。
清单 8. 使用 GRUB shell
|
作为一个实践示例,您可以继续前面的示例,使用 GRUB 的 find
命令查找配置文件。下面,您可以从 (hd1,12)(即 /dev/sdb13) 加载配置文件,如 清单 9 所示。
清单 9. 使用 GRUB 查找并加载 GRUB 配置文件
|
加载配置文件时,可能会看到一个类似于 清单 10 的菜单。记住,这已在 GRUB shell 下完成了,该 shell 模拟真实的 GRUB 环境,不显示启动图像。但是,这非常类似于真正使用 GRUB 启动系统时启动图像上叠加的图像。
注意:如果您的菜单看起来不是这样,而且您的方向键回显为 ^[[A 这样的符号,那么您的 grub 命令版本可能不包含正确的菜单显示所需的 curses 支持。据说,这个问题影响了一些最新 Fedora 发布。在这种情况下,使用 grub shell 进行测试会受到限制。
清单 10. GRUB 菜单
|
假设您突出显示了第三个条目 Fedora (2.6.35.13-91.fc14.x86_64)
,然后按 e 编辑该条目。您将看到类似于 清单 11 的内容。
清单 11. 编辑一个 GRUB 配置条目
|
同样,可以使用方向键选择要编辑的行,然后按 e 键编辑它。在本例中,我们假设您在 /dev/sdb14 上安装了 Fedora,然后删除一个较低的分区,比如 /dev/sdb8。这将把 Fedoro 分区下放到 GRUB 标记中的 /dev/sdb13(或 hd1,12)。使用光标键移过 '(hd1,13)' 中的 '3',然后返回去删除 '3',插入 '2' 代替。完成后,按 Enter 键接受更改,或者按 Esc 键取消更改。最后,如果您的确在引导系统,而不是运行 GRUB shell,按 b 键引导系统。
启动到一个 GRUB shell 时,它有足够的能力显示您的文件系统上的文件,它好像作为根用户运行,因此您确实需要使用 GRUB 密码保护您的系统。但是,请记住,如果用户能够从可移动介质启动,就能提供他或她自己的 GRUB 配置。请参阅 GRUB 手册的安全性部分(参见 参考资料),了解关于 GRUB 安全性和其他方面的更多信息。您也可以通过使用 info grub
命令在您的系统上查看它。
内核参数
内核参数(有时称为启动参数)为内核提供其可能无法独自确定的硬件参数信息,其目的是覆盖内核以其他方式可能检测到的值,或者避免检测到不适当的值。例 如,您可能想启动到单用户模式来修复系统,以单核模式启动一个 SMP 系统,或者指定一个替代根文件系统。有些内核级别可能需要一个参数来启用 RAM 大于一定量的系统上的大内存支持。
有时需要向引导进程添加参数。例如,您可能想以 \single-user 模式启动系统,这时,您需要添加 S
参数。或者,您可能需要指定一个此前工作的内核,以便能够查明您新构建的自定义内核无法工作的原因。按 Tab 键查看要引导的映像列表和原始简略 LILO 文本提示 boot:。此时,您可以键入映像名称,或者按 Enter 选择第一个条目。如果需要添加参数,可以在映像名称后面键入参数。清单 12 和 图 7 显示执行下面的操作将看到的画面:按 Tab 键,键入 Slackware13
选择 Slackware 13 映像,添加参数 S 以单用户模式启动,然后按 Enter 键启动引导进程。
清单 12. 使用 LILO 指定启动参数
|
图 7. 将 Slackware 引导到单用户模式
使用 GRUB,您可以键入另一组内核命令和 initrd
语句;或者,最好使用前面介绍的编辑功能编辑一个现有条目。例如,添加参数 S 启动到单用户模式。
init 进程
内核加载完成后,通常会启动 /sbin/init
。这个程序在系统关闭之前将一直运行。它总是被分配进程 ID 1,如 清单 13 所示。
清单 13. init 进程
|
init
程序通过运行一系列脚本引导系统的其余部分。这些脚本通常位于 /etc/rc.d/init.d 或 /etc/init.d 中,它们执行一些服务,比如设置系统的主机名、检查文件系统错误、装载其他文件系统、启用网络、启动打印服务,等等。这些脚本执行完后,init
启动一个名为 getty
的程序,在控制台上显示登录提示。图形登录屏幕通过一个图形显示管理器处理,比如 GDM for Gnome。
如果您的系统能够加载内核,但无法成功运行 init
,您可以通过指定一个替代初始化程序来尝试修复。例如,指定 init=/bin/sh
将把您的系统引导到一个拥有根权限的 shell 提示,您可以在那里修复系统。
要详细了解可用的启动参数,可以参阅 bootparam
的手册页,也可以浏览 /usr/src/linux/Documentation/ramdisk.txt,这个文件在有些系统上也称为 /usr/src/linux-$(uname -r)/Documentation/kernel-parameters.txt。
显然,如果您每次引导时都必须应用同一组额外参数,那么应该将它们添加到配置文件中。如果使用 LILO,别忘了重新运行 lilo
。
引导事件
在 Linux 引导进程中,大量消息将被发送到控制台,描述正在引导的内核、系统硬件、以及其他内核相关事项。这些消息通常一闪而过,您可能来不及阅读它们,除非引导进 程因等待处理而出现延迟,比如无法访问某个时间服务器,或者必须检查一个文件系统。随着 Linux Bootsplash 项目(参见 参考资料)的出现,这些消息可能会重叠在一个图形背景上,或者被一个简单的状态栏隐藏或替换。如果您的发行版支持隐藏模式,那么您通常可以通过按一个键(比如 F2)切换为显示引导消息。
dmesg
如果能够返回并查看内核消息,那么应该感觉不错。由于标准输出与进程相关,而内核没有进程标识符,因此系统会将内核(或模块)输出消息保存到内核环缓冲区 中。可以使用 dmesg
命令显示内核环缓冲区,会在标准输出上显示这些消息。当然,您可以将这个输出重定向到一个文件以便将来分析,或者将其转发给一个内核开发人员进行调试。清单 14 展示了一些您可能会看到的输出。
清单 14. 部分 dmesg 输出
|
在系统启动后,内核环缓冲区也可以用于一些事件,其中包括某些程序失败和热插拔事件。清单 15 展示了几个与插入一个 USB 内存密匙相关的事件。
清单 15. 内核环缓冲区中的后续事件
|
/var/log/messages
您的系统启动到运行 /sbin/init
的时点后,如您所见,内核仍然在内核环缓冲区中记录事件,但进程使用 syslog 守护进程来记录消息,日志文件通常位于 /var/log/messages 中。与内核环缓冲区不同,每个 syslog 行都有一个时间戳,日志文件在系统能够重启之间持久化。如果引导进程中的 init 脚本阶段出现错误,那么您应该首先检查这个文件。
大多数守护进程的名称都以字母 'd' 结尾。清单 16 展示如何在重启后查看最后几条守护进程状态消息。
清单 16. 来自 /var/log/messages 的守护进程消息
|
您还能在 /var/log 中找到更多其他系统程序的日志。例如,您能看到您的 X Window 系统的启动日志。
我们对通过引导进程引导 Linux 系统的介绍就到此结束了。