ToB企服应用市场:ToB评测及商务社交产业平台

标题: Linux工作原理5内核如何启动 [打印本页]

作者: 一给    时间: 2024-7-21 11:40
标题: Linux工作原理5内核如何启动
5 内核如何启动

如今你已经知道了 Linux 体系的物理和逻辑布局、什么是内核以及如何使用进程。本章将向你介绍内核是如何启动的。换句话说,你将学习内核如何移动到内存中,以及在第一个用户进程启动之前内核所做的工作。
启动过程的简化视图如下:
在某些时候,init 会启动一个允许登录的进程,通常是在启动序列的末尾或接近末尾时。

本章主要介绍引导加载器和内核的前几个阶段。第 6 章通过具体介绍 systemd(Linux 体系中最常见的 init 版本),继续介绍用户空间启动。
5.1 启动信息

传统的 Unix 体系在启动时会产生许多诊断信息,告诉您启动过程。这些信息起首来自内核,然后来自 init 启动的进程和初始化程序。然而,这些信息并不美丽,也不连贯,在某些环境下甚至没有什么参考价值。此外,由于硬件的改进,内核的启动速度比以前快得多;信息闪过的速度太快,很丢脸清发生了什么。因此,目前大多数 Linux 发行版都会尽力用闪屏和其他情势的填充物来隐蔽启动诊断信息,以便在体系启动时分散你的留意力。
查看内核启动和运行诊断信息的最佳方法是使用 journalctl 命令获取内核日志。运行 journalctl -k 会表现当前启动时的信息,但也可以使用 -b 选项查看以前的启动信息。我们将在第 7 章具体介绍日志。
假如没有 systemd,可以查抄 /var/log/kern.log 等日志文件,或运行 dmesg 命令查看内核环缓冲区中的信息。
下面是 journalctl -k 命令的示例:
  1. # journalctl -k
  2. Jun 20 15:42:09 sanrui kernel: Booting Linux on physical CPU 0x0000080000 [0x481fd010]
  3. Jun 20 15:42:09 sanrui kernel: Linux version 5.15.0-106-generic (buildd@bos03-arm64-019) (gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #116-Ubuntu SMP Wed Apr 17 09:19:>
  4. Jun 20 15:42:09 sanrui kernel: efi: EFI v2.70 by EDK II
  5. Jun 20 15:42:09 sanrui kernel: efi: ACPI 2.0=0x2f690018 SMBIOS 3.0=0x2f530000 MEMATTR=0x3370c018 MOKvar=0x261b0000 RNG=0x2f69f698 MEMRESERVE=0x2f670498
  6. Jun 20 15:42:09 sanrui kernel: random: crng init done
  7. Jun 20 15:42:09 sanrui kernel: secureboot: Secure boot disabled
  8. Jun 20 15:42:09 sanrui kernel: ACPI: Early table checksum verification disabled
  9. Jun 20 15:42:09 sanrui kernel: ACPI: RSDP 0x000000002F690018 000024 (v02 HISI  )
  10. ...
  11. ``
  12. 内核启动后,用户空间启动过程经常会产生信息。这些信息可能更难查看和审查,因为在大多数系统中,你不会在一个日志文件中找到它们。启动脚本被设计为向控制台发送信息,并在启动过程结束后被清除。不过,这在 Linux 系统上不是问题,因为 systemd 会捕获启动和运行时的诊断信息,这些信息通常会发送到控制台。
  13. ##5.2 内核初始化和启动选项
  14. 启动时,Linux 内核按以下一般顺序初始化:
  15. - CPU检查
  16. - 内存检查
  17. - 设备总线发现
  18. - 设备发现
  19. - 辅助内核子系统设置(网络等)
  20. - 根文件系统挂载
  21. - 启动用户空间
  22. 前两个步骤并不复杂,但当内核进入设备时,就会出现依赖性问题。例如,磁盘设备驱动程序可能依赖于总线支持和 SCSI 子系统支持,这在第3章中已经提到过。之后,在初始化过程中,内核必须在启动 init 之前挂载根文件系统。
  23. 能够识别启动过程中的每个阶段,对你解决启动问题和了解整个系统将是非常有价值的。不过,许多 Linux 发行版的默认行为通常会使你很难甚至不可能在启动过程中识别最初的几个启动阶段,所以你可能只能在这些阶段完成并登录后才能看清楚。
  24. 一般来说,除了某些必要组件可能是可加载的内核模块而不是主内核的一部分外,你不必担心这些依赖关系。有些机器可能需要在挂载真正的根文件系统前加载这些内核模块。我们将在第 6.7 节中介绍这个问题及其初始 RAM 文件系统(initrd)的解决方法。
  25. 内核会发出某些信息,表明它准备启动第一个用户进程:
  26. ```sh
  27. Freeing unused kernel memory: 2408K
  28. Write protecting the kernel read-only data: 20480k
  29. Freeing unused kernel memory: 2008K
  30. Freeing unused kernel memory: 1892K
复制代码
在这里,内核不仅清算了一些未使用的内存,还保护了本身的数据。然后,假如你运行的是一个足够新的内核,你会看到内核以 init 的身份启动第一个用户空间进程:
  1. Run /init as init process
  2.    with arguments:
  3. --snip--
复制代码
随后,你应该能看到根文件体系被挂载,systemd 启动,并向内核日志发送一些信息:
  1. EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
  2. systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
  3. systemd[1]: Detected architecture x86-64.
  4. systemd[1]: Set hostname to <duplex>.
复制代码
此时,你肯定知道用户空间已经启动。
5.3 内核参数

Linux 内核启动时,会收到一组基于文本的内核参数,此中包含一些额外的体系细节。这些参数指定了许多不同范例的行为,例如内核应产生的诊断输出量和特定于设备驱动程序的选项。
你可以通过查看 /proc/cmdline 文件,查看传递给体系当前运行内核的参数:
  1. $ cat /proc/cmdline
  2. BOOT_IMAGE=/vmlinuz-5.10.0-218.0.0.117.oe2203sp4.aarch64 root=/dev/mapper/openeuler-root ro rd.lvm.lv=openeuler/root rd.lvm.lv=openeuler/swap video=VGA-1:640x480-32@60me cgroup_disable=files apparmor=0 crashkernel=1024M,high smmu.bypassdev=0x1000:0x17 smmu.bypassdev=0x1000:0x15 arm64.nopauth console=tty0 kpti=off
复制代码
参数要么是简朴的单字标记,如 ro 和 quiet,要么是键值对,如 vt.handoff=1。许多参数并不重要,例如用于表现闪屏的 splash 标记,但此中一个关键参数是 root 参数。这是根文件体系的位置;没有它,内核就无法精确执行用户空间启动。
根文件体系可以指定为设备文件,如下面的例子:
  1. root=/dev/sda1
复制代码
在大多数现代体系中,有两种更常见的选择。起首,你可能会看到如许一个逻辑卷:
  1. root=/dev/mapper/my-system-root
复制代码
你还可能看到一个 UUID(见第 4.2.4 节):
  1. root=UUID=17f12d53-c3d7-4ab3-943e-a0a72366c9fa
复制代码
这两个参数都比较好,因为它们不依赖于特定的内核设备映射。
ro参数指示内核在用户空间启动时以只读模式挂载根文件体系。这是正常现象;只读模式可确保 fsck 在执行任何重要操作之前安全地查抄根文件体系。查抄结束后,启动进程会以读写模式重新挂载根文件体系。
碰到不理解的参数时,Linux 内核会保存该参数。内核随后会在执行用户空间启动时将该参数传递给 init。例如,假如你在内核参数中添加了-s,内核就会将-s传递给init程序,以表明它应该以单用户模式启动。
假如您对基本启动参数感兴趣,请参阅 bootparam(7) 手册。假如你想找一些非常具体的参数,可以查看 Linux 内核自带的参考文件 kernel-params.txt。
有了这些基础知识,你就可以跳到第 6 章,相识用户空间启动、初始 RAM 磁盘和内核作为第一个进程运行的 init 程序的具体细节。本章其余部分将具体介绍内核如何加载到内存并启动,包罗如何获取参数。
5.4 引导加载器(Boot Loaders)

在启动过程开始时,在内核和 init 启动之前,引导加载程序会启动内核。引导加载器的工作听起来很简朴:从磁盘上的某个地方将内核加载到内存中,然后用一组内核参数启动内核。然而,这项工作比外貌看起来要复杂得多。要理解原因,请考虑一下引导加载器必须答复的问题:
答案是(通常)内核及其参数通常在根文件体系的某处。听起来内核参数应该很轻易找到,但请记住,内核本身尚未运行,通常是内核遍历文件体系来查找须要的文件。更糟糕的是,通常用于访问磁盘的内核设备驱动程序也不可用。这就像一个 “先有鸡还是先有蛋 ”的问题。问题可能比这还要复杂,但如今,让我们来看看 Boot Loader 如何克服驱动程序和文件体系的停滞。
Boot Loader 确实需要驱动程序来访问磁盘,但与内核使用的驱动程序不同。在个人电脑上,引导加载器使用传统的基本输入/输出体系(BIOS)或较新的同一可扩展固件接口(UEFI)来访问磁盘。(可扩展固件接口或 EFI 和 UEFI 将在第 5.8.2 节中具体讨论)。现代磁盘硬件包含固件,允许 BIOS 或 UEFI 通过逻辑块寻址 (LBA) 访问毗连的存储硬件。LBA 是访问任何磁盘数据的通用、简朴方法,但性能较差。但这并不是问题,因为启动加载程序通常是唯一必须使用这种模式访问磁盘的程序;启动后,内核可以访问本身的高性能驱动程序。
要确定体系使用的是 BIOS 还是 UEFI,请运行 efibootmgr。 假如得到启动目的列表,说明体系使用的是 UEFI。假如表现不支持 EFI 变量,则说明体系使用的是 BIOS。别的,也可以查抄是否存在 /sys/firmware/efi;假如存在,则说明体系使用了 UEFI。
一旦解决了访问磁盘原始数据的问题,引导加载程序就必须在文件体系中查找所需数据。大多数常见的 Boot Loader 都能读取分区表,并内置了对文件体系只读访问的支持。因此,它们可以找到并读取内核进入内存所需的文件。这种功能使得动态设置和增强 Boot Loader 变得轻易得多。Linux 引导加载器并不总是具备这种能力;假如没有这种能力,设置引导加载器就会更加困难。
一样平常来说,内核增加新功能(尤其是存储技术)后, Boot Loader 会增加这些功能的单独简化版原来弥补。
5.4.1 引导加载器的任务

Linux 引导加载器的核心功能包罗以下功能:
自 Linux 内核诞生以来,引导加载器已经变得相称先进,具备了命令行历史记录和菜单体系等功能,但内核映像和参数选择的机动性始终是一个基本需求。(一个令人惊讶的现象是,有些需求实际上已经减少了。例如,由于可以从 USB 存储设备执行紧急启动或恢复启动,因此很少需要担心手动输入内核参数或进入单用户模式)。当前的 Boot Loader 比以往提供了更强大的功能,假如你正在构建自定义内核或只是想调解参数,这一点会特别方便。
5.4.2 引导加载器概述

以下是您可能会碰到的主要 Boot Loader:
本书险些只涉及 GRUB。使用其他 Boot Loader 的理由是它们比 GRUB 设置更简朴、速度更快或提供其他特殊用途的功能。
在引导提示符下输入内核名称和参数,可以相识引导加载器的很多信息。要做到这一点,你需要知道如何进入引导提示符或菜单。不幸的是,由于 Linux 发行版对引导加载程序的行为和外观举行了大量定制,这一点偶然很难弄明确。通常无法通过观察启动过程来判断发行版使用了哪个引导加载器。
接下来的章节将告诉你如何进入启动提示符,以输入内核名称和参数。一旦你认识了这些,你将看到如何设置和安装 Boot Loader。
5.5 GRUB 简介

GRUB 是 Grand Unified Boot Loader 的缩写。我们将介绍 GRUB 2,但还有一个旧版本称为 GRUB Legacy,已不再使用。
GRUB 最重要的功能之一是文件体系导航,可以轻松选择内核映像和设置。查看 GRUB 菜单是相识 GRUB 功能的最佳方式之一。该界面易于浏览,但你很可能从未见过它。
要访问 GRUB 菜单,请在 BIOS 启动屏幕首次出现时按住 SHIFT,假如体系是 UEFI,则按住 ESC。否则,引导加载器设置可能不会在加载内核前暂停。

实验以下方法探索引导加载器:

该屏幕表现,在此设置中,root 被设置为 UUID,内核映像为 /boot/vmlinuz-4.15.0-45-generic,内核参数包罗 ro、quiet 和 splash。初始 RAM 文件体系为 /boot/initrd.img-4.15.0-45-generic。但假如你以前从未见过这种设置,可能会觉得有些困惑。为什么会有多个 root 引用,它们为什么不同?为什么 insmod 会出如今这里?假如你以前见过它,可能会记得它是 Linux 内核的一项功能,通常由 udevd 运行。
你有理由多看两眼,因为 GRUB 并不使用 Linux 内核(记住,它的任务是启动内核)。你所看到的设置完全由 GRUB 内部的功能和命令组成,它存在于本身独立的世界中。
造成混淆的部分原因是 GRUB 借用了许多来源的术语。GRUB 有本身的 “内核 ”和 insmod 命令,用于动态加载 GRUB 模块,完全独立于 Linux 内核。许多 GRUB 命令与 Unix shell 命令相似;甚至还有一个 ls 命令来列出文件。
留意:启动内核位于逻辑卷上的体系需要一个用于 LVM 的 GRUB 模块。你可能会在体系中看到这个模块。
到目前为止,最轻易引起混淆的是 GRUB 对 root 一词的使用。通常,root 指的是体系的根文件体系。在 GRUB 设置中,这是一个内核参数,位于 linux 命令的映像名称之后。
设置中其他所有提及 root 的地方都是指 GRUB root,它只存在于 GRUB 内部。GRUB 的 “根 ”是 GRUB 查找内核和 RAM 文件体系映像文件的文件体系。
在图 5-2 中,GRUB 根目次起首被设置为 GRUB 专用设备(hd0,msdos1),该设置的默认值为 1。在下一条命令中,GRUB 将搜索分区 2 上的特定 UUID。假如找到该 UUID,就会将 GRUB root 设为该分区。
最后,linux 命令的第一个参数(/boot/vmlinuz-. . )是 Linux 内核映像文件的位置 3。GRUB 会从 GRUB 根目次加载该文件。initrd 命令与此雷同,它指定了第 6 章所述初始 RAM 文件体系的文件 4.
您可以在 GRUB 中编辑此设置;这通常是临时修复错误启动的最简朴方法。要永世解决启动问题,需要更改设置(参见第 5.5.2 节),但如今让我们更深入一步,通过命令行界面查看 GRUB 的一些内部信息。
5.5.1 使用GRUB命令行查看设备和分区

如图 5-2 所示,GRUB 有本身的设备寻址方案。例如,找到的第一个硬盘被命名为 hd0,然后是 hd1,以此类推。设备名称分配可能会改变,但荣幸的是,GRUB 可以搜索所有分区的 UUID,找到内核所在的分区,如图 5-2 中的搜索命令所示。
列出设备
要相识 GRUB 如何指代体系中的设备,请在启动菜单或设置编辑器中按下 c 进入 GRUB 命令行。您将看到 GRUB 提示:
  1. grub>
复制代码
您可以在此输入设置中看到的任何命令,但要开始使用,请实验使用诊断命令:ls。在没有参数的环境下,输出是 GRUB 所知道的设备列表:
  1. grub> ls
  2. (hd0) (hd0,msdos1)
复制代码
在这种环境下,有一个主磁盘设备 (hd0) 和一个分区 (hd0,msdos1)。假如磁盘上有一个交换分区,也会表现出来,如 (hd0,msdos5)。分区上的 msdos 前缀说明磁盘包含 MBR 分区表;GPT 则以 gpt 开头,这在 UEFI 体系上可以找到。(还有更深条理的组合,即分区中包含 BSD 磁盘标签映射(第三个标识符),但除非在一台呆板上运行多个操作体系,否则通常不必担心这个问题)。
要获取更具体的信息,请使用 ls -l。该命令特别有用,因为它会表现分区文件体系的 UUID。例如
  1. grub> ls -l
  2. Device hd0: No known filesystem detected – Sector size 512B - Total size 32009856KiB
  3.         Partition hd0,msdos1: Filesystem type ext* – Last modification time
  4.           2019-02-14 19:11:28 Thursday, UUID 8b92610e-1db7-4ba3-ac2f-30ee24b39ed0 - Partition start at 1024Kib - Total size 32008192KiB
复制代码
该磁盘的第一个 MBR 分区上有一个 Linux ext2/3/4 文件体系。使用交换分区的体系会表现另一个分区,但从输出结果中无法判断其范例。
如今让我们看看 GRUB 的文件体系导航功能。使用 echo 命令确定 GRUB 根目次(请记住,这是 GRUB 盼望找到内核的位置):
  1. grub> echo $root
  2. hd0,msdos1
复制代码
要使用 GRUB 的 ls 命令列出根目次下的文件和目次,可以在分区的末尾添加一个斜线:
  1. grub> ls (hd0,msdos1)/
复制代码
由于不方便键入实际的 root 分区,可以用 root 变量来代替,以节流时间:
  1. grub> ls ($root)/
复制代码
输出结果是该分区文件体系中文件和目次名的简短列表,如 etc/、bin/ 和 dev/。如今,GRUB ls 命令的功能完全不同了。以前,你列出的是设备、分区表,或许还有一些文件体系头信息。如今,你实际上是在查看文件体系的内容。
你可以用雷同的方式深入查看分区上的文件和目次。例如,要查抄 /boot 目次,请从以下步骤开始:
  1. grub> ls ($root)/boot
复制代码
使用上下箭头键翻阅 GRUB 命令历史记录,使用左右箭头编辑当前命令行。尺度的读行键(CTRL-N、CTRL-P 等)也可以使用。
你还可以使用 set 命令查看当前设置的所有 GRUB 变量:
  1. grub> set
  2. ?=0
  3. color_highlight=black/white
  4. color_normal=white/black
  5. --snip--
  6. prefix=(hd0,msdos1)/boot/grub
  7. root=hd0,msdos1
复制代码
这些变量中最重要的一个是 $prefix,即 GRUB 盼望在此中找到设置和辅助支持的文件体系和目次。接下来我们将讨论 GRUB 设置。
使用完 GRUB 命令行界面后,可以按 ESC 键返回 GRUB 菜单。或者,假如你已经设置了启动所需的所有设置(包罗 linux 变量和可能的 initrd 变量),可以输入启动命令来启动这些设置。无论如何,启动你的体系吧。我们将探究 GRUB 设置,这最好在体系完整可用时举行。
5.5.2 GRUB 设置

GRUB 设置目次通常为 /boot/grub 或 /boot/grub2。它包含中心设置文件 grub.cfg、特定架构目次(如 i386-pc)(包含后缀为 .mod 的可加载模块)以及其他一些项目(如字体和本地化信息)。我们不会直接修改 grub.cfg,而是使用 grub-mkconfig 命令(或 Fedora 上的 grub2-mkconfig)。
起首,快速查看 grub.cfg,相识 GRUB 如何初始化菜单和内核选项。你会看到该文件由 GRUB 命令组成,通常以一系列初始化步骤开始,然后是一系列菜单条目,用于不同的内核和启动设置。初始化过程并不复杂,但开头的许多条件可能会让你误以为并非如此。前半部分包罗大量函数定义、默认值和视频设置命令,如下所示:
  1. if loadfont $font ; then
  2.   set gfxmode=auto
  3.   load_video
  4.   insmod gfxterm
  5.   --snip--
复制代码
留意:许多变量如 $font 都来自 grub.cfg 开头附近的 load_env 调用。
在设置文件的后面,你会发现可用的启动设置,每个设置都以 menuentry 命令开头。根据前一节所学,你应该可以或许阅读并理解这个示例:
  1. menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-8b92610e-1db7-4ba3-ac2f-30ee24b39ed0' {
  2.         recordfail
  3.         load_video
  4.         gfxmode $linux_gfx_mode
  5.         insmod gzio
  6.         if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
  7.         insmod part_msdos
  8.         insmod ext2
  9.         set root='hd0,msdos1'
  10.         search --no-floppy --fs-uuid --set=root 8b92610e-1db7-4ba3-ac2f-30ee24b39ed0
  11.         linux   /boot/vmlinuz-4.15.0-45-generic root=UUID=8b92610e-1db7-4ba3-ac2f-30ee24b39ed0 ro quiet splash $vt_handoff
  12.         initrd  /boot/initrd.img-4.15.0-45-generic
  13. }
复制代码
查抄 grub.cfg 文件中是否有包含多个 menuentry 命令的子菜单命令。许多发行版在旧版本的内核中使用子菜单命令,如许就不会挤占 GRUB 菜单。
假如你想更改 GRUB 设置,不要直接编辑 grub.cfg 文件,因为它会主动生成,体系偶尔会覆盖它。你可以在其他地方设置新设置,然后运行 grub-mkconfig 生成新设置。
要相识设置生成的工作原理,请查看 grub.cfg 的开头部分。应该有如许的解释行:
  1. ### BEGIN /etc/grub.d/00_header ###
复制代码
进一步查抄后,你会发现 /etc/grub.d 中的险些每个文件都是一个 shell 脚本,用于生成 grub.cfg 文件的一部分。grub-mkconfig 命令本身就是一个运行 /etc/grub.d 中所有内容的 shell 脚本。请记住,GRUB 本身不会在启动时运行这些脚本;我们在用户空间运行这些脚本,生成 GRUB 运行的 grub.cfg 文件。
请以 root 用户身份切身实验。不用担心会覆盖当前设置。该命令本身只是将设置打印到尺度输出。
  1. # grub-mkconfig
复制代码
假如想在 GRUB 设置中添加菜单项和其他命令怎么办?简而言之,你应该在 GRUB 设置目次(通常为 /boot/grub/custom.cfg)中新建一个 custom.cfg 文件,将你的自定义设置放入此中。
长答案要复杂一些。/etc/grub.d 设置目次提供了两个选项: 40_custom 和 41_custom。第一个选项 40_custom 是一个脚本,你可以本身编辑,但它最不稳定;软件包升级可能会破坏你所做的任何更改。41_custom 脚本更简朴;它只是一系列在 GRUB 启动时加载 custom.cfg 的命令。假如选择第二个选项,在生成设置文件时将不会表现您所做的更改,因为 GRUB 会在启动时完成所有工作。
留意:文件名前面的数字会影响处理顺序;较低的数字在设置文件中排在前面。
自定义设置文件的两个选项并不是特别广泛,没有什么能阻止你添加本身的脚原来生成设置数据。你可能会在/etc/grub.d目次中看到一些针对你的特定发行版而添加的内容。例如,Ubuntu 在设置中添加了内存测试启动选项 (memtest86+)。
要写入并安装新生成的 GRUB 设置文件,可以使用 grub-mkconfig 的 -o 选项将设置写入 GRUB 目次,如下所示:
  1. # grub-mkconfig -o /boot/grub/grub.cfg
复制代码
像往常一样,备份旧设置并确保安装到精确的目次。
如今我们将进入 GRUB 和 Boot Loader 的一些技术细节。假如你听腻了引导加载器和内核,请跳至第 6 章。
参考资料

5.5.3 安装 GRUB

安装 GRUB 比设置 GRUB 更复杂。荣幸的是,您通常不必担心安装问题,因为您的发行版会为您处理。不外,假如您要复制或还原可启动磁盘,或准备本身的启动顺序,可能需要自行安装。
在继续之前,请阅读第 5.4 节,相识 PC 如何启动,并确定是使用 MBR 还是 UEFI 启动。接下来,构建 GRUB 软件集,并确定 GRUB 目次的位置;默以为 /boot/grub。假如您的发行版会为您编译 GRUB,您可能不需要编译 GRUB,但假如需要,请参阅第 16 章相识如何从源代码编译软件。请确保构建了精确的目的:MBR 或 UEFI 启动的目的不同(32 位和 64 位 EFI 启动的目的甚至也不同)。
安装引导加载器需要您或安装程序确定以下内容:
当前运行体系看到的 GRUB 目的目次。如前所述,这通常是 /boot/grub,但假如您要将 GRUB 安装到另一个磁盘上供另一个体系使用,则可能有所不同。
GRUB 目的磁盘的当前设备。
对于 UEFI 启动,EFI 体系分区(通常为 /boot/efi)的当前挂载点。
请记住,GRUB 是一个模块化体系,但为了加载模块,它必须读取包含 GRUB 目次的文件体系。你的任务是构建一个能读取该文件体系的 GRUB 版本,以便加载其余设置(grub.cfg)和任何所需的模块。在 Linux 上,这通常意味着构建一个预加载了 ext2.mod 模块(可能还有 lvm.mod)的 GRUB 版本。有了这个版本后,你需要做的就是把它放在磁盘的可启动部分,然后把其他所需的文件放到 /boot/grub。
荣幸的是,GRUB 自带了一个名为 grub-install 的实用程序(不要与 install-grub 混淆,你可能会在一些旧体系上找到它),它可以为你完成安装 GRUB 文件和设置的大部分工作。例如,假如你的当前磁盘位于 /dev/sda,而你想在该磁盘的 MBR 上安装 GRUB,并使用当前的 /boot/grub 目次,请使用此命令:
  1. # grub-install /dev/sda
复制代码
错误安装 GRUB 可能会破坏体系的启动顺序,因此不要轻易执行此命令。假如担心,请研究如何使用 dd 备份 MBR,备份当前安装的任何其他 GRUB 目次,并确保有一个紧急启动计划。
要在当前体系之外的存储设备上安装 GRUB,必须手动指定该设备上的 GRUB 目次,就像当前体系如今看到的那样。例如,目的设备是 /dev/sdc,而该设备包含 /boot 的根文件体系(例如 /dev/sdc1)已挂载到当前体系的 /mnt。这意味着安装 GRUB 时,当前体系将看到 /mnt/boot/grub 中的 GRUB 文件。运行 grub-install 时,请告诉它这些文件的位置,如下所示:
  1. # grub-install --boot-directory=/mnt/boot /dev/sdc
复制代码
在大多数 MBR 体系中,/boot 是根文件体系的一部分,但有些安装程序会将/boot 放入本身的独立文件体系中。请确保您知道目的 /boot 位于何处。
UEFI 安装应该更简朴,因为只需将引导加载器复制到适当的位置即可。但你还需要用 efibootmgr 命令将引导加载器 “宣布 ”到固件中,也就是将加载器设置保存到 NVRAM 中。假如有的话,grub-install 命令会运行它,所以通常你可以像如许在 UEFI 体系上安装 GRUB:
  1. # grub-install --efi-directory=efi_dir –-bootloader-id=name
复制代码
这里,efi_dir 是当前体系中 UEFI 目次的位置(通常是 /boot/efi/EFI,因为 UEFI 分区通常挂载在 /boot/efi),name 是引导装载程序的标识符。
不幸的是,安装 UEFI 启动加载器时可能会出现很多问题。例如,假如您安装到的磁盘最终会被安装到另一个体系中,您就必须想办法将引导加载器公布到新体系的固件中。可移动媒体的安装程序也有不同。
但最大的问题之一是 UEFI 安全启动。
5.6 UEFI 安全启动问题

影响 Linux 安装的一个新问题是如何处理近期 PC 上的安全启动功能。激活 UEFI 机制后,任何引导加载程序都必须经过可信机构的数字签名才能运行。微软要求硬件供应商在出货 Windows 8 及更高版本的体系时使用安全启动。其结果是,假如你试图在这些体系上安装未签名的启动加载程序,固件将拒绝加载程序,操作体系将无法加载。
主要的 Linux 发行版在安全启动方面没有问题,因为它们包含签名的启动加载器,通常基于 UEFI 版本的 GRUB。通常环境下,UEFI 和 GRUB 之间会有一个小的签名临时文件;UEFI 运行临时文件,临时文件反过来执行 GRUB。假如你的呆板不在可信环境中或需要满足某些安全要求,防止启动未经授权的软件是一项重要功能,因此有些发行版更进一步,要求整个启动序列(包罗内核)都要签名。
安全启动体系也有一些缺点,尤其是对于实验构建本身的启动加载器的人来说。你可以在 UEFI 设置中禁用安全启动要求。不外,这对双启动体系来说并不奏效,因为假如不启用安全启动,Windows 将无法运行。
5.7 链载其他操作体系

UEFI 支持加载其他操作体系相对轻易,因为您可以在 EFI 分区中安装多个引导加载器。然而,旧的 MBR 风格不支持此功能,即使您有 UEFI,您可能仍有一个带有 MBR 风格引导加载器的单独分区。GRUB 可以在磁盘的特定分区上加载并运行不同的引导加载器,而不是设置并运行 Linux 内核;这就是所谓的链式加载。
要举行连锁加载,请在 GRUB 设置中创建一个新的菜单项(使用 “生成新设置文件 ”一节中描述的方法之一)。下面是在磁盘第三个分区安装 Windows 的示例:
  1. menuentry "Windows" {
  2.         insmod chain
  3.         insmod ntfs
  4.         set root=(hd0,3)
  5.         chainloader +1
  6. }
复制代码
+1选项告诉chainloader加载分区第一个扇区的任何内容。你也可以让它直接加载文件,方法是使用如许的一行来加载 io.sys MS-DOS 加载器:
  1. menuentry "DOS" {
  2.         insmod chain
  3.         insmod fat
  4.         set root=(hd0,3)
  5.         chainloader /io.sys
  6. }
复制代码
5.8 引导加载器细节

如今我们来快速相识一下 Boot Loader 的内部布局。要相识 GRUB 如许的引导加载器是如何工作的,起首我们要相识一下电脑是如何启动的。由于必须解决传统 PC 启动机制的许多不足,启动加载方案有多种变化,但主要有两种: MBR 和 UEFI。
5.8.1 MBR 启动

除了第 4.1 节所述的分区信息外,MBR 还包罗一个 441 字节的小区域,PC BIOS 在开机自检(POST)后加载并执行该区域。不幸的是,这个空间不足以容纳险些所有的引导加载程序,因此需要额外的空间,这就是所谓的多级引导加载程序。在这种环境下,MBR 中的初始代码除了加载引导加载程序的其余代码外,什么也不做。引导加载程序的其余部分通常被塞入 MBR 和磁盘上第一个分区之间的空间。这并不十分安全,因为任何东西都可以覆盖那里的代码,但大多数引导加载器都如许做,包罗大多数 GRUB 安装。
这种将引导加载程序代码放在 MBR 之后的方案对于使用 BIOS 引导的 GPT 分区磁盘无效,因为 GPT 信息位于 MBR 之后的区域。(GPT 的解决方法是创建一个称为 BIOS 启动分区的小分区,并使用特殊的 UUID(21686148-6449-6E6F-744E-656564454649),为完整的启动加载程序代码提供一个位置。不外,这种设置并不常见,因为 GPT 通常用于 UEFI,而非传统 BIOS。通常只有在拥有超大磁盘(超过 2TB)的旧体系中才会使用,因为这些磁盘对于 MBR 来说太大了。
5.8.2 UEFI 启动

PC 制造商和软件公司意识到传统的 PC BIOS 有很大的局限性,因此决定开发一种名为 “可扩展固件接口 (EFI) ”的更换软件。EFI 花了一段时间才在大多数 PC 上盛行起来,但如今它已成为最常见的固件接口,尤其是在微软要求 Windows 安全启动的今天。目前的尺度是同一 EFI (UEFI),它包罗内置 shell、读取分区表和浏览文件体系等功能。GPT 分区方案是 UEFI 尺度的一部分。
与 MBR 相比,UEFI 体系的启动方式大相径庭。在大多数环境下,它更轻易理解。在 UEFI 体系中,可执行的启动代码并不驻留在文件体系之外,而是始终存在一个特殊的 VFAT 文件体系,称为 EFI 体系分区(ESP),此中包含一个名为 EFI 的目次。在 Linux 体系中,ESP 通常挂载在 /boot/efi,因此你可能会发现大部分 EFI 目次布局都是从 /boot/efi/EFI 开始的。每个 Boot Loader 都有本身的标识符和相应的子目次,如 efi/microsoft、efi/apple、efi/ubuntu 或 efi/grub。引导加载程序文件的扩展名为 .efi,与其他支持文件一起存放在这些子目次中。假如你继续探索,可能会发现 grubx64.efi (GRUB 的 EFI 版本)和 shimx64.efi 等文件。
留意:ESP 与第 5.8.1 节所述的 BIOS 启动分区不同,具有不同的 UUID。你应该不会碰到同时使用这两种启动分区的体系。
但有一个问题:你不能将旧的引导加载程序代码放入 ESP,因为旧的代码是为 BIOS 界面编写的。相反,你必须提供一个为 UEFI 编写的引导加载器。例如,使用 GRUB 时,必须安装 UEFI 版本的 GRUB 而不是 BIOS 版本。而且,正如前面在 “使用 UEFI 安装 GRUB ”中解释的,必须向固件发布新的引导加载器。
最后,如第 5.6 节所述,我们还必须解决 “安全启动 ”问题。
5.8.3 GRUB如何工作

最后,我们来看看 GRUB 是如何工作的:
由于传统 PC 启动机制的不足,GRUB 内核加载序列的第 3 步和第 4 步可能会比较复杂。最大的问题是 "GRUB 内核在哪里?有三种基本可能性
除了 UEFI/ESP 之外的所有环境下,电脑 BIOS 都会从 MBR 中加载 512 字节,这就是 GRUB 的起始位置。这一小段(源自 GRUB 目次中的 boot.img)还不是核心,但它包含核心的起始位置,并以后处加载核心。
不外,假如你有一个 ESP,GRUB 内核就会以文件情势存在。固件可以浏览 ESP 并直接执行 GRUB 或其他操作体系加载器中的所有内容。(你可能会在 ESP 中的 GRUB 之前加一个垫片来处理安全启动,但想法是一样的)。
不外,在大多数体系中,这还不是全部。在加载和执行内核之前,引导加载器可能还需要将初始 RAM 文件体系映像加载到内存中。这就是 initrd 设置参数指定的内容,我们将在第 6.7 节中介绍。不外,在相识初始 RAM 文件体系之前,你应该先相识一下用户空间的启动--下一章就从这里开始。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4