加载和启动 Ubuntu Linux 内核在后台发生哪些具体步骤?
答案1
在没有 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
接下来是从重置开始的错误处理(4次重试)。
H4 的位置稍早一些,并且是:
JMP BOOT_LOCN
BOOT_LOCN 定义为位置 7C00H
[1] IBM PC技术参考手册(1984年)
这里没有太多东西可以启动你的系统。存储介质的第一个扇区,即主引导记录,被读入计算机内存中的 0:7c00 位置,然后执行跳转到其开始位置。
据说启动是指通过引导程序来启动自己。要启动系统,必须正确发生一系列事件。一旦从磁盘加载了足够的代码并启动,系统就可以提供错误消息、提示和错误处理等内容。单个扇区没有足够的空间来容纳任何复杂的内容。
顺便说一句,代码最终发生了一些变化。DX 的高位字节被设置为 80H,以引用第一个磁盘而不是第一个软盘。当然,后来 PC 的 BIOS 还加入了弯曲几何和基于数据包的 I/O,用于更大的扇区地址,并允许它从 CD、USB 等启动。传统 PC 硬件上的想法仍然是一样的,读取第一个扇区并转移控制。
除此之外,直到 EFI 之前没有发生太多事情。
第一个扇区负责查找接下来应该发生什么,并至少加载第一个扇区,然后由该扇区加载多个扇区——然后您的系统就可以启动并运行了。这就是现代 Ubuntu 系统在近现代硬件上的启动方式。
膜生物反应器
第一个扇区是 MBR,下一个扇区是 Grub2 的第一部分。我应该补充一点,四个主分区也在 MBR 中定义,其中一个可以描述包含扩展分区链的磁盘区域。第一个扇区的地址是扇区 0。
可能出现的问题:
如果在 Grub 之后安装或重新安装 Windows,它会用自己的代码替换 Grub MBR 代码。这样,指向 Grub 代码的指针就消失了,新的 Windows 代码将搜索带有 Boot 标志的分区,从其开头加载扇区并将控制权转交给它。
在通常的安装中,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......|
^
4 字节指针可容纳的最大扇区数为 2^32,即 2,294,967,296 个扇区,或小于 2.2 x 10 12字节。以下 grub 代码必须位于磁盘的该部分内。
Grub2 core.img 启动
通常从扇区 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. .|
可能出现的问题:
GPT 格式的驱动器的分区描述符位于第二个扇区开始处。在这种情况下,grub 映像必须位于分区中的其他位置。最好格式化一个小分区,以便 grub 保存其核心映像。将其放置在靠近磁盘开头的位置,这样您就不会想移动或打扰它。如果不将 grub 重新安装到该分区,就不能移动它。
如果在此位置安装了某些东西(例如整个磁盘加密系统),它将被清除。它可能必须在那里启动您的系统或访问您的数据。哎哟。
如果您稍后安装加密或其他使用该区域存储部分内容的软件,则核心 grub 将不再启动。
阻止列表为扇区号保留了 2 个长字,因此每个位都必须存储在驱动器开头的 2^21 TB 内。这在一段时间内应该足够了。它加载的大部分内容都经过了压缩。较旧的系统在 MBR 和第一个分区之间只有 1 个轨道 - 1 个 MBR 扇区的空间。这可能大约是 63 个扇区,而 63 个扇区是 Ubuntu 14.04 在撰写本文时加载的扇区。压缩是为了让映像中的整个 grub 内核以及几个方便的 grub 模块可以容纳。这将构成首次启动时的整个 grub 系统。
lzma_解压缩.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 映像所需的其他模块。
菜单项的最终命令特别令人感兴趣。
linux 命令指定 grub 要加载的 linux 内核以及应传递的 linux 启动命令。Linux 内核命令中特别有趣的是 root= 参数。它将以内核的术语而不是 grub 的术语告诉内核应该以 root 身份挂载哪个分区。
initrd 命令指定匹配的压缩 cpio initramfs 文件(称为 initrd.img-版本) 包含一个内存文件树,其中包含 Linux 内核启动所需的额外信息以及可能需要的内核模块。
然后,启动命令将 CPU 控制权转移到已加载的内核以进行启动。
可能出现的问题:
如果前缀错误,grub 将无法正常启动,也无法加载菜单或适当的模块。如果重新排序分区或删除了以前的分区,分区编号会发生变化,则会导致这种情况。如果指定分区中的信息已更改,也会导致这种情况。它应该始终与 grub-install 存储的内容相匹配,grub-install 被赋予了特定的安装目录。如果 grub 正在运行的分区上的实际 grub 代码发生了更改,则可能需要使用 重新安装 grub 到驱动器上grub-install
。即便如此,如果您能找到正确的分区,您应该能够手动设置前缀并让 grub 工作。
运行 Grub2 时需要了解的事项:
- 输入命令
pager=1
以避免物品从屏幕顶部滚落。 - 输入命令
debug=all
来发出调试消息,为您提供有关输入命令时发生的情况的额外信息。
内核启动
内核初始化过程一般以通用方式开始,并在书籍等中进行了描述。稍后,它会引用 initrd 文件系统映像中的 Debian 和 Ubuntu 特定信息。部分内容:找到指定用于根目录的分区,检查是否需要,并挂载以进行写入,将内存日志复制到该分区,然后运行 upstart。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 页