第 15 章 FreeBSD 的引导过程

如果发现翻译错误,请直接 发起PR修改

15.1. 简介

启动计算机并加载操作系统的过程被称为“引导过程”或“引导”。 FreeBSD 的引导过程提供了很大的灵活性,可以自定义系统启动时发生的事情,包括选择在同一台计算机上安装的不同操作系统、同一操作系统的不同版本或不同的内核。

本章详细介绍了可以设置的配置选项。它演示了如何自定义 FreeBSD 的启动过程,包括在 FreeBSD 内核启动、设备探测和 init(8) 启动之前发生的所有事情。这发生在启动消息的文本颜色从亮白色变为灰色时。

阅读完本章后,您将会认识到:

  • FreeBSD 引导系统的组件及其相互作用方式。

  • 可以传递给 FreeBSD 引导程序中组件的选项,以控制引导过程。

  • 设置设备提示的基础知识。

  • 如何进入单用户模式和多用户模式,以及如何正确关闭 FreeBSD 系统。

本章仅描述在 x86 和 amd64 系统上运行的 FreeBSD 的引导过程。

15.2. FreeBSD 引导过程

打开计算机并启动操作系统会带来一个有趣的困境。根据定义,计算机在启动操作系统之前不知道如何执行任何操作,包括从磁盘运行程序。如果计算机没有操作系统就无法从磁盘运行程序,而操作系统的程序又存储在磁盘上,那么操作系统是如何启动的呢?

这个问题与《巴伦·门舒森的冒险》一书中的一个问题相似。一个角色在一个井盖上卡住了一半身子,他通过抓住自己的靴带并抬起来自救。在计算机的早期,术语 引导(bootstrap) 被用来指代加载操作系统的机制。后来,这个术语被缩短为“引导(booting)”。

在 x86 硬件上,基本输入/输出系统(BIOS)负责加载操作系统。BIOS 在硬盘上查找主引导记录(MBR),该记录必须位于硬盘的特定位置。BIOS 具有足够的知识来加载和运行 MBR,并假设 MBR 可以完成加载操作系统的其余任务,可能需要 BIOS 的帮助。

FreeBSD 支持从旧的 MBR 标准和新的 GUID 分区表(GPT)进行引导。GPT 分区通常在具有统一可扩展固件接口(UEFI)的计算机上找到。然而,即使在只有传统 BIOS 的机器上,FreeBSD 也可以从 GPT 分区引导,使用 gptboot(8) 。目前正在进行直接支持 UEFI 引导的工作。

MBR 中的代码通常被称为“引导管理器”,特别是当它与用户交互时。引导管理器通常在磁盘的第一个磁道或文件系统中有更多的代码。引导管理器的示例包括标准的 FreeBSD 引导管理器 boot0,也称为 Boot Easy,以及 GNU GRUB,它被许多 Linux® 发行版使用。

GRUB 的用户应参考 GNU 提供的文档

如果只安装了一个操作系统,MBR 会搜索磁盘上第一个可引导(活动的)分区,并运行该分区上的代码来加载操作系统的其余部分。当存在多个操作系统时,可以安装不同的引导管理器来显示操作系统列表,以便用户可以选择要引导的操作系统。

FreeBSD 引导系统的剩余部分分为三个阶段。第一阶段只需知道让计算机进入特定状态并运行第二阶段即可。第二阶段可以做更多的事情,然后运行第三阶段。第三阶段完成加载操作系统的任务。将工作分为三个阶段是因为 MBR 对可以在第一和第二阶段运行的程序的大小有限制。将任务链接在一起使 FreeBSD 能够提供更灵活的加载程序。

然后启动内核,并开始探测设备并初始化它们以供使用。一旦内核引导过程完成,内核将控制权交给用户进程 init(8),该进程确保磁盘处于可用状态,启动用户级资源配置以挂载文件系统,设置网络卡以进行网络通信,并启动已配置为在启动时运行的进程。

本节将更详细地描述这些阶段,并演示如何与 FreeBSD 引导过程进行交互。

15.2.1. 引导管理器

MBR 中的引导管理器代码有时被称为引导过程的 零阶段。默认情况下,FreeBSD 使用 boot0 引导管理器。

FreeBSD 安装程序安装的 MBR 基于 /boot/boot0。由于 slice 表和 MBR 末尾的 0x55AA 标识符, boot0 的大小和功能被限制为 446 字节。如果安装了 boot0 和多个操作系统,则在启动时会显示类似于以下示例的消息:

例 1. boot0 截图
F1 Win
F2 FreeBSD

Default: F2

如果在 FreeBSD 之后安装其他操作系统,它们将覆盖现有的 MBR。如果发生这种情况,或者要用 FreeBSD 的 MBR 替换现有的 MBR ,请使用以下命令:

# fdisk -B -b /boot/boot0 device

其中 device 是引导磁盘,例如 ad0 表示第一个 IDE 磁盘,ad2 表示第二个 IDE 控制器上的第一个 IDE 磁盘,或者 da0 表示第一个 SCSI 磁盘。要创建自定义的 MBR 配置,请参考 boot0cfg(8)

15.2.2. 第一阶段和第二阶段

从概念上讲,第一阶段和第二阶段是同一个程序在磁盘的同一个区域的一部分。由于空间限制,它们被分成两部分,但总是一起安装的。它们是由 FreeBSD 安装程序或 bsdlabel 从组合的 /boot/boot 复制而来。

这两个阶段位于文件系统之外,在引导 slice 的第一个磁道上,从第一个扇区开始。这是 boot0 或任何其他引导管理器期望找到一个程序来继续引导过程的位置。

第一阶段,boot1,非常简单,因为它的大小只能是 512 字节。它对 FreeBSD 的 bsdlabel 有一定了解,该标签存储有关分区的信息,以便找到并执行 boot2

第二阶段,boot2,稍微复杂一些,足够理解 FreeBSD 文件系统以找到文件。它可以提供一个简单的界面来选择要运行的内核或加载程序。它运行加载程序,加载程序更加复杂,并提供一个引导配置文件。如果在第二阶段中断了引导过程,将显示以下交互式屏幕:

例 2. boot2 截图
>> FreeBSD/i386 BOOT
Default: 0:ad(0,a)/boot/loader
boot:

要替换已安装的 boot1boot2 ,请使用 bsdlabel 命令,其中 diskslice 是要从中引导的磁盘和分区,例如 ad0s1 表示第一个 IDE 磁盘上的第一个分区。

# bsdlabel -B diskslice

如果只使用磁盘名称,例如 ad0bsdlabel 将以“危险专用模式(dangerously dedicated mode)”创建磁盘,而不使用分区。这可能不是期望的操作,所以在按下 Return 之前,请仔细检查 diskslice

15.2.3. 第三阶段

加载器是三阶段引导过程的最后阶段。它位于文件系统上,通常是作为 /boot/loader 文件。

加载器旨在作为一种交互式的配置方法,使用内置的命令集,并由更强大的解释器支持,该解释器具有更复杂的命令集。

在初始化过程中,加载器将探测控制台和磁盘,并确定正在引导的磁盘。它将相应地设置变量,并启动一个解释器,用户可以通过脚本或交互方式传递命令。

然后,加载程序将读取 /boot/loader.rc 文件,默认情况下会读取 /boot/defaults/loader.conf 文件,该文件为变量设置了合理的默认值,并读取 /boot/loader.conf 文件以获取对这些变量的本地更改。loader.rc 文件会根据这些变量的设置加载所选的模块和内核。

最后,默认情况下,加载程序会等待 10 秒钟以等待按键操作,如果没有被中断,则启动内核。如果被中断,用户将会看到一个理解命令集的提示符,用户可以在其中调整变量、卸载所有模块、加载模块,最后进行启动或重新启动操作。 加载器内置命令 列出了最常用的加载程序命令。有关所有可用命令的完整讨论,请参阅 loader(8)

表 1. 加载器内置命令
变量 描述

autoboot seconds

如果在给定的时间范围内(以秒为单位)没有被中断,将继续启动内核。它会显示一个倒计时,而默认的时间范围是 10 秒。

boot [-options] [kernelname]

立即启动内核,使用指定的选项或内核名称。在执行 unload 命令之后,才能在命令行上提供内核名称。否则,将使用先前加载的内核。如果 kernelname 没有限定,将在 boot/kernelboot/modules 下进行搜索。

boot-conf

根据指定的变量,自动配置模块,通常是 kernel。只有在先使用 unload 卸载模块后,再更改一些变量时,这才有意义。

help [topic]

显示从 /boot/loader.help 读取的帮助信息。如果给定的主题是 index,则显示可用主题的列表。

include filename …​

读取指定的文件,并逐行解释。一旦出现错误,include 操作立即停止。

`

加载给定类型的内核、内核模块或文件,使用指定的文件名。filename 后的任何参数都将传递给该文件。如果 filename 没有限定,将在 /boot/kernel/boot/modules 下进行搜索。

ls [-l] [path]

显示给定路径中的文件列表,如果未指定路径,则显示根目录。如果指定了 -l ,还将显示文件大小。

lsdev [-v]

列出所有可能加载模块的设备。如果指定了 -v,则会打印更多详细信息。

lsmod [-v]

显示已加载的模块。如果指定了 -v,则显示更多详细信息。

more filename

显示指定的文件,在每个显示的 LINES 之间暂停。

reboot

立即重新启动系统。

set variable, set variable=value

设置指定的环境变量。

unload

移除所有已加载的模块。

以下是一些加载器使用的实际示例。要以单用户模式启动常规内核:

 boot -s

卸载常规的内核和模块,然后加载先前的或另一个指定的内核:

 unload
 load /path/to/kernelfile

使用限定的 /boot/GENERIC/kernel 来引用安装时默认的内核,或者使用 /boot/kernel.old/kernel 来引用在系统升级或配置自定义内核之前先前安装的内核。

使用以下内容在另一个内核中加载常用模块。请注意,在这种情况下,不需要使用限定名称:

unload
set kernel="mykernel"
boot-conf

加载自动化内核配置脚本的方法:

 load -t userconfig_script /boot/kernel.conf

15.2.4. 最后阶段

一旦内核被加载,无论是由引导程序还是由绕过引导程序的 boot2 加载,它都会检查任何引导标志并根据需要调整其行为。 引导过程中的内核交互 列出了常用的引导标志。有关其他引导标志的更多信息,请参阅 boot(8)

表 2. 引导过程中的内核交互
选项 描述

-a

在内核初始化期间,请求设备作为根文件系统进行挂载。

-C

从 CDROM 引导根文件系统。

-s

进入单用户模式。

-v

在内核启动过程中增加更多的详细信息。

一旦内核启动完成,它将控制权交给用户进程 init(8),该进程位于 /sbin/init 或者在 loader 中的 init_path 变量指定的程序路径。这是引导过程的最后阶段。

引导序列确保系统上可用的文件系统是一致的。如果 UFS 文件系统不一致,并且 fsck 无法修复不一致性,init 会将系统切换到单用户模式,以便系统管理员可以直接解决问题。否则,系统将启动到多用户模式。

15.2.4.1. 单用户模式

用户可以通过使用 -s 参数启动或在引导程序中设置 boot_single 变量来指定此模式。也可以通过在多用户模式下运行 shutdown now 命令来进入此模式。单用户模式从以下消息开始:

Enter full pathname of shell or RETURN for /bin/sh:

如果用户按下 Enter 键,系统将进入默认的 Bourne shell 。要指定不同的 shell,请输入 shell 的完整路径。

单用户模式通常用于修复由于不一致的文件系统或引导配置文件错误而无法启动的系统。它还可以用于在未知情况下重置 root 密码。由于单用户模式提示符提供对系统及其配置文件的完全本地访问权限,因此可以执行这些操作。在此模式下没有网络连接。

单用户模式在修复系统时非常有用,但如果系统不在物理安全的位置,它会带来安全风险。默认情况下,任何能够物理访问系统的用户在进入单用户模式后将完全控制该系统。

如果在 /etc/ttys 文件中将系统的 console 设置为 insecure,系统将在启动单用户模式之前首先提示输入 root 密码。这样做可以增加一定的安全性,但也会移除在未知情况下重置 root 密码的能力。

例 3. 在 /etc/ttys 中配置一个不安全的控制台
# name  getty                           type    status          comments
#
# If console is marked "insecure", then init will ask for the root password
# when going to single-user mode.
console none                            unknown off insecure

一个 不安全(insecure) 的控制台意味着控制台的物理安全被认为是不安全的,因此只有知道 root 密码的人才能使用单用户模式。

15.2.4.2. 多用户模式

如果 init 发现文件系统正常,或者用户在单用户模式下完成了他们的命令并输入 exit 退出单用户模式,系统将进入多用户模式,开始系统的资源配置。

资源配置系统从 /etc/defaults/rc.conf 读取配置的默认值,并从 /etc/rc.conf 读取系统特定的详细信息。然后,它会挂载 /etc/fstab 中列出的系统文件系统。它启动网络服务、杂项系统守护进程,然后启动本地安装软件包的启动脚本。

要了解更多关于资源配置系统的信息,请参考 rc(8),并检查位于 /etc/rc.d 的脚本。

15.3. 设备提示

在系统初始启动时,引导管理程序 boot loader(8) 会读取 device.hints(5) 文件。该文件存储了内核引导信息,也被称为 “设备提示(device hints)”。这些 “设备提示” 被设备驱动程序用于设备配置。

设备提示也可以在第三阶段的引导加载程序提示符中指定,如 第三阶段 中所示。可以使用 set 添加变量,使用 unset 删除变量,并使用 show 查看变量。在 /boot/device.hints 中设置的变量也可以被覆盖。在引导加载程序中输入的设备提示不是永久的,下次重启时不会应用。

一旦系统启动,可以使用 kenv(1) 命令来转储所有的变量。

/boot/device.hints 的语法是每行一个变量,使用井号 “#” 作为注释标记。行的构造如下:

 hint.driver.unit.keyword="value"

第三阶段引导加载程序的语法是:

 set hint.driver.unit.keyword=value

其中 driver 是设备驱动程序的名称,unit 是设备驱动程序的单元号,keyword 是提示关键字。关键字可以包含以下选项:

  • at:指定设备所连接的总线。

  • port:指定要使用的 I/O 的起始地址。

  • irq:指定要使用的中断请求号。

  • drq:指定 DMA 通道号。

  • maddr:指定设备占用的物理内存地址。

  • flags:为设备设置各种标志位。

  • disabled: 如果设置为 1 ,则设备被禁用。

由于设备驱动程序可能接受或需要更多未在此处列出的提示,建议查看驱动程序的手册页。有关更多信息,请参阅 device.hints(5)kenv(1)loader.conf(5)loader(8)

15.4. 关机序列

在使用 shutdown(8) 进行控制关闭时, init(8) 将尝试运行脚本 /etc/rc.shutdown ,然后继续向所有进程发送 TERM 信号,随后对于未能及时终止的进程发送 KILL 信号。

在支持电源管理的架构和系统上,要关闭 FreeBSD 机器,可以使用 shutdown -p now 立即关闭电源。要重新启动 FreeBSD 系统,可以使用 shutdown -r now 。要运行 shutdown(8),必须是 root 用户或 operator 组的成员。还可以使用 halt(8)reboot(8)。有关更多信息,请参考它们的手册页面和 shutdown(8)

通过引用 “用户和基本账户管理” 来修改组成员身份。

电源管理需要将 acpi(4) 加载为模块或静态编译到自定义内核中。


上次修改时间: September 18, 2024 by fiercex