在幕后使用什么进程来加载 Ubuntu Linux 内核?

Joh*_*ber 6 boot

加载和启动 Ubuntu Linux 内核在幕后发生了哪些特定步骤?

Joh*_*ber 15

为没有 EFI 的传统 i386 和 amd64 架构计算机从磁盘启动 Ubuntu Linux 内核

具有 EFI 功能的现代台式机和笔记本电脑。与使用了 20 多年的传统 BIOS 系统不同,这些系统的固件中实际上有一个操作系统——能够一次性加载大量软件项目。此外,面对以某种方式获得了存储启动软件能力的软件的攻击,这些可以在具有更高安全性的计算机上启动。

更传统的硬件具有更少的固件并且一点一点地开始。此处描述的这些系统在其固件中运行自检,然后开始启动过程。

这是从软盘启动第一台 PC 的固件代码(在软盘子系统重置后):

   MOV AX,201H  
   SUB DX,DX  
   MOV ES,DX  
   MOV BS,OFFSET BOOT_LOCN  
   MOV CX,1  
   INT 13H  
   JNC H4  
Run Code Online (Sandbox Code Playgroud)

接下来是从重置开始的错误处理(4 次重试)。

H4 的位置稍早一点,是:

   JMP BOOT_LOCN  
Run Code Online (Sandbox Code Playgroud)

BOOT_LOCN 被定义为位置 7C00H

[1] IBM PC 技术参考手册 (1984)

没有太多东西可以让您的系统启动。存储介质的第一个扇区,即主引导记录,在位置 0:7c00 处被读入计算机内存,然后执行跳转到其开始位置。

据说,boot 是指用你的靴子把自己捡起来。有一系列事件必须正确发生才能启动您的系统。一旦从磁盘加载了足够多的代码并启动,系统就可以提供诸如错误消息、提示和错误处理之类的信息。单个部门没有足够的空间来处理任何这种复杂性。

顺便说一句,最终代码发生了一些变化。DX 的高位字节设置为 80H 以引用第一张磁盘而不是第一张软盘。当然,后来对 PC BIOS 的添加包括弯曲几何和基于数据包的 I/O 以用于更大的扇区地址,并允许它从 CD 引导,通过 USB 等。传统 PC 硬件的想法仍然相同,读取第一个扇区并传输控制。

除此之外,在 EFI 之前没有发生太多事情。

由第一个扇区决定接下来应该发生什么并至少加载它的第一个扇区,然后由该扇区加载多个扇区——然后您的系统应该关闭并运行。这就是现代 Ubuntu 系统在近乎现代的硬件上启动的方式。

MBR


来源:http : //bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head :
/grub-core/boot/i386/pc/boot.S


第一个扇区是 MBR,下一个扇区是 Grub2 的第一部分。我应该补充一点,四个主分区也在 MBR 中定义,其中一个可以描述包含扩展分区链的磁盘区域。第一个扇区的地址是扇区 0。

可能出错的地方:
如果在 Grub 之后安装或重新安装了 Windows,它可以用自己的 Grub MBR 代码替换。随着指向 Grub 代码的指针消失,新的 Windows 代码将搜索带有引导标志的分区,从其开头加载一个扇区并将控制权转移给它。

在通常的安装中,grub 代码核心的其余部分直接跟随,并且 Grub MBR 指向下一个扇区,扇区 1。如果您将 Grub 安装到一个分区,指针可能会改变。该 grub 指针位于 MBR 的 0x5c-0x60 中,必须进行相应更改。

00000050  f7 c1 01 00 74 03 fe 46  10 66 00 80 01 00 00 00  |....t..F.f......|
                                               ^
Run Code Online (Sandbox Code Playgroud)

4 字节指针将保存的最大扇区数是 2^32、2,294,967,296 个扇区,或小于 2.2 x 10 12字节。以下 grub 代码必须位于磁盘的该部分内。

Grub2 core.img 启动


来源:http : //bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head :
/grub-core/boot/i386/pc/diskboot.S


通常从扇区 1 开始(例如,如果您将 Grub2 安装到 /dev/sda)是 core.img 的部分。必须为 grub 加载整个图像才能给您提示。在它的第一个扇区的最后是一个块列表,一个扇区和计数的列表,必须从中加载图像的其余部分。与 MBR 不同,扇区中有足够的空间来加载多组多扇区。现在我们正在到达某个地方。扇区每 0x200 字节定位一次。每个范围用 16 个字节描述。

         |
00000360  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000370  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000380  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000390  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003f0  00 00 00 00 02 00 00 00  00 00 00 00 63 00 20 08  |............c. .|
Run Code Online (Sandbox Code Playgroud)

可能出什么问题:
GPT 格式的驱动器的分区描述符位于第二个扇区开始处。在这种情况下,grub 映像必须位于分区中的其他位置。最好格式化一个小分区,以便 grub 保存其核心映像。将它放在靠近磁盘开头的某个地方,在那里您不会想要移动或打扰它。如果不重新安装 grub 就不能移动它。

如果在此位置安装了诸如整个磁盘加密系统之类的东西,它就会被清除。它可能必须在那里引导您的系统或访问您的数据。哎哟。

如果您稍后安装加密或其他使用此区域的软件,则其某些内容核心 grub 将不再启动。

阻止列表为扇区号保留了 2 个长字,因此每个位都必须存储在驱动器开头的 2^21 TB 内。这应该足够好一段时间了。它加载的大部分内容都是压缩的。较旧的系统在 MBR 和只有 1 个磁道 - 1 个 MBR 扇区的第一个分区之间有空间。这可能是大约 63 个扇区,而 63 个扇区是 Ubuntu 14.04 在撰写本文时加载的内容。压缩是为了使图像中的整个 grub 内核以及几个方便的 grub 模块都可以容纳。这将包括首次启动时的整个 grub 系统。

lzma_decompress.image


来源:
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/startup_raw.S
HTTP://bazaar.launchpad .net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/lzma_decode.S


这是最后一步加载内容的开始,通常位于扇区 2,即第三个扇区。

整个核心映像现在都已加载。这部分获取其后的其余信息并将其解压缩到内存中。

Grub2 启动


来源:
http : //bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/files/head :/ grub-core/
http://www.gnu.org/software/grub/manual/ html_node/index.html


此时,大量的 Grub2 代码被加载和解压缩。这段代码包含几个模块,与 grub2 内核一样长。看起来像一个模块是一个包含 grub前缀的短段。这是一个字符串,如:

(hd0,msdos5)

当 grub 启动时,如果您输入c密钥,您可以输入 grub 命令,如果您这样做并输入set命令,您可以看到在您的磁盘上安装 Grub2 代码时设置的前缀。(按ESC返回)。

Grub 现在可以访问和浏览多种文件系统,前缀是它开始查找位置的关键。

从前缀 grub 描述的目录加载 grub.cfg 文件。该文件由update-grub命令(重新)创建,该命令查找您可能想要从中启动的所有位置,并在文件定义的菜单结构中指定这些位置。该文件还指定是否应加载 grubenv 文件。该文件加载 grub2 环境,对于某些 grub 配置,可能包括上次成功加载的引导菜单。grub.cfg 文件还指示从同一目录加载更多 grub 模块。

如果需要进行选择,grub 现在可以显示菜单。

当您从菜单中选择一个项目时,该项目用于运行该菜单项中的 grub 命令。这些可能会在该菜单项引用的位置加载处理内核和 initrd 映像所需的更多模块。

菜单项的最后命令特别有趣。

  1. linux命令指定要加载的linux内核grub,以及应该传递的linux boot命令。Linux 内核命令中特别有趣的是 root= 参数。它会告诉内核,用内核的术语而不是 grub 的术语,应该以 root 身份挂载哪个分区。

  2. initrd 命令指定匹配的压缩 cpio initramfs 文件(称为 initrd.img- version)的位置,该文​​件包含一个内存文件树,其中包含 linux 内核启动所需的额外信息,以及它可能需要的内核模块。

  3. 然后,引导命令将 CPU 控制权转移到加载的内核以使其启动。

可能出错的地方:
如果前缀错误,grub 将无法正常启动,并且无法加载菜单或适当的模块。如果对分区重新排序或删除以前的分区,更改分区编号,则可能会导致这种情况。如果指定分区中的信息已更改,也可能导致此问题。它应该始终与 grub-install 存储的内容相匹配,grub-install 给出了一个特定的安装目录。如果在 grub 正在工作的分区上更改了实际的 grub 代码,则可能应该在驱动器上重新安装grub-install. 即便如此,如果您能找到正确的分区,您应该能够手动设置前缀并使 grub 工作。

运行 Grub2 时需要知道的事情:

  1. 输入命令pager=1以避免项目从屏幕顶部滚出。
  2. 输入命令debug=all以发出调试消息,以便为您提供有关输入命令时发生的情况的额外信息。

内核引导

内核初始化一般开始并在书籍等中进行了描述。稍后它指的是 initrd 文件系统映像中的 Debian 和 Ubuntu 特定信息。部分:找到为根目录指定的分区,必要时检查,并挂载写入,将内存日志复制到其中,并运行新贵。Upstart 接管系统初始化,包括在其 /etc/init/rc-sysinit.conf 作业中的 /etc/rc.#/ 目录中运行传统脚本。

可能出错的地方:
也许最常见的 grub 引入问题是从 grub 传递给内核的 root= kernel 命令是错误的。由于busybox无法找到所需系统的根目录,这可能会导致内核初始化提前停止并提示。


[1] IBM 个人计算机硬件参考库:技术参考;部件号 6361453 (1984),第 5-50 页(对于 IBM 5150 个人计算机,当时唯一的“PC™”)
http://www.minuszerodegrees.net/manuals/IBM_5150_Technical_Reference_6322507_APR84.pdf第 143 页