问题:
内核在磁盘文件系统中,要加载内核,就必须先加载文件系统。
但根文件系统又是被内核负责加载的,它是内核的启动参数,没有它,内核是无法启动的。
到底先有鸡,还是先有蛋?机器是如何加载文件系统中的内核的?
1、在PC机中,一般流程应该是:
bios先加载0扇区中的grub的第一段代码,即stage1。
stage1 然后加载 1~63扇区中的grub的第二段代码,即stage1.5。
stage1.5中有文件系统的驱动程序,stage1.5 从文件系统中读出 grub最后一段(比如/boot/grub/grub.cfg),即stage2
stage2 再 读取并启动内核
内核启动时,用自己的驱动读取磁盘,挂载根文件系统。
2、嵌入式环境中,一般流程应该是:
BootROM读取并加载flash中的uboot
uboot读取硬盘或另外一个flash中的文件系统,找到内核,启动内核。
内核启动时,用自己的驱动读取磁盘,挂载根文件系统。
3、如果根文件系统比较特殊,比如是lvm,加密盘等,则内核是无法读取这个文件系统的,就需要initramfs
Bootloader → 内核 + initramfs(cpio) → initramfs 里加载模块/做解密/LVM激活 → 挂载真正的磁盘根fs → switch_root → 正常运行
再详细一些:
bootloader 先加载内核,并创建initramfs文件系统,再把initramfs这个压缩包解压到文件系统中。
内核执行这个文件系统中的init程序,这个init程序 探测设备,加载驱动,挂载真正的文件系统,执行真正文件系统中的 init程序,进而使用switch_root 切换真正的用户空间。
4、多系统引导的原理
双linux系统, grub的 stage1 和 stage1.5 是两个系统公用的。
grub引导时,先加载主linux的stage2,读取grub.cfg文件,让用户选择要启动哪个linux。 如果用户选择启动另外一个linux,就会去读取另外一个linxu的grub.cfg文件,然后引导启动。
linux+windows系统, grub的 stage1 和 stage1.5 还是在0~31扇区中的。
grub引导时,先加载linux的stage2,读取grub.cfg文件,让用户选择要启动inux还是windows。 如果用户选择启动windows,grub就会把windows分区的第一个扇区(VBR)读入内存,并把控制器交给VBR,即进行链式启动。
GPT分区模式下,安装系统时,可以安装成bios和efi 兼容模式
比如 $ sudo fdisk -l /dev/sda
Disk /dev/sda: 3.5 TiB, 3840653221888 bytes, 7501275824 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 262144 bytes / 1048576 bytes Disklabel type: gpt Disk identifier: 99E1C9F8-D740-451A-81E2-B0BBF116031F Device Start End Sectors Size Type /dev/sda1 2048 22527 20480 10M BIOS boot /dev/sda2 22528 227327 204800 100M EFI System
为啥要专门分一个bios 和 efi分区呢
你看到的fdisk -l输出中,/dev/sda使用的是GPT 分区表(Disklabel type: gpt)。在 GPT 格式下,BIOS boot和EFI System分区是系统能够正常启动的“绝对前提”。
简单来说,它们的存在是为了解决主板固件(Firmware)与操作系统引导程序(Bootloader,如 GRUB)之间的沟通问题。
下面为你通俗地解释它们各自的职责:
1./dev/sda1(10M, BIOS boot)
- 它是给谁用的?专为传统 BIOS(Legacy BIOS)启动模式准备的。
- 为什么需要它?
在老式的 MBR 分区表中,引导程序(GRUB)的前半部分可以藏在硬盘最前面的 512 字节(MBR)和分区之间的空隙里。但 GPT 分区表没有这种空隙。
为了让传统 BIOS 也能在 GPT 硬盘上启动,GRUB 需要一块独立的“地盘”来存放它的stage1.5(core.img)。这个 10M 的 BIOS boot 分区就是专门用来装这段引导代码的。 - 总结:如果你用传统 BIOS 模式启动 GPT 硬盘,这个分区必不可少。
2./dev/sda2(100M, EFI System)
- 它是给谁用的?专为现代 UEFI 启动模式准备的。
- 为什么需要它?
现代主板(UEFI)不再读取传统的 MBR 引导代码,而是直接读取 FAT32 格式的分区里的.efi可执行文件。
这个 EFI 分区(通常格式化为 FAT32)里面存放了操作系统的引导文件(比如grubx64.efi)以及主板自身的固件更新文件。主板开机时,会直接去这个分区里找对应的引导程序来加载操作系统。 - 总结:如果你用现代 UEFI 模式启动,这个分区是必须的。
💡 为什么你的系统里这两个分区同时存在?
这通常是因为系统在安装时采用了“双模兼容”策略。
安装程序同时创建了这两个分区,这意味着无论你的主板设置成传统的 Legacy BIOS 启动,还是现代的 UEFI 启动,这块硬盘都能顺利引导系统。这提供了极大的灵活性,特别是在需要更换主板或排查启动故障时。
一、为什么 MBR 磁盘开头会有 1~63 扇区的空隙?
1.1 历史原因:CHS 寻址与柱面对齐
在古老的 CHS(柱面/磁头/扇区)时代,磁盘的几何结构是:
每个磁道(Track)有 63 个扇区
分区最好从一个柱面的起始(即某个磁头的第 1 扇区)开始,以避免跨柱面带来的性能损失
MBR 占据第一个柱面、第一个磁头、第一个扇区(CHS=0,0,1)
因此:
第一个分区从柱面 0、磁头 1、扇区 1 开始 → 相对 MBR 的偏移 = 63 个扇区
MBR(1 个扇区) + 保留的 62 个扇区(第 2~63 扇区) = 共 63 个扇区被跳过
这就是“第1~63扇区空隙”的历史来源。
第一个分区,是从64号扇区开始的。
1.2 现代磁盘还保留吗?
是的,兼容性考虑,大部分分区工具(如fdisk)仍然默认按 1MiB 对齐(2048 扇区),空隙更大:
text
旧式 CHS 对齐: 空隙 = 63 扇区(31.5KB) 现代 1MiB 对齐: 空隙 = 2048 扇区(1MB)
实际上你执行fdisk -l /dev/sda时,第一个分区的 Start 字段如果是2048,就意味着 MBR 后面有 2047 个扇区未被第一个分区使用。
什么时候用u-boot,什么时候用bios?bios也要自己下载编译吗 在 QEMU 中,选择使用 U-Boot 还是 BIOS(通常指 UEFI 固件),以及是否需要自己编译,主要取决于你的**开发目标**和**应用场景**。以下是详细的解答: ### 一、 什么时候用 U-Boot,什么时候用 BIOS (UEFI)? 这两者代表了不同的系统启动流程和硬件生态: **1. 什么时候使用 U-Boot?** * **适用场景**:主要用于**嵌入式 Linux 开发**、裸机开发或底层系统调试。 * **核心作用**:在真实的嵌入式硬件上,U-Boot 负责最底层的硬件初始化(如设置 CPU 时钟、配置 DDR 内存控制器等),然后才加载内核。在 QEMU 中使用 U-Boot,可以让你深入学习和调试系统启动的每一个环节(如手动加载内核、配置启动参数等),非常贴近真实的嵌入式开发流程。 **2. 什么时候使用 BIOS (UEFI)?** * **适用场景**:主要用于运行**现代通用操作系统**(如 Ubuntu、Debian、Windows 11 等)或模拟服务器/云环境。 * **核心作用**:现代操作系统通常要求运行在 UEFI 启动模式下。在 QEMU 中,UEFI 固件(如 `QEMU_EFI.fd`)模拟了物理硬件上的 UEFI 芯片,负责初始化虚拟硬件,并在虚拟磁盘上寻找 EFI 系统分区(ESP),加载引导程序(如 GRUB)来启动系统。 --- ### 二、 BIOS (UEFI) 也要自己下载编译吗? **不需要。** 与 U-Boot 通常需要针对特定硬件或板卡自行编译不同,UEFI 固件(如 `QEMU_EFI.fd`)通常有现成的预编译版本可以直接使用: **1. 随 QEMU 软件包自动安装(推荐)** 在大多数 Linux 发行版中,当你安装 QEMU 及其 EFI 支持包时,固件文件会自动放置在系统目录中。 * **Debian/Ubuntu**:安装 `qemu-efi-aarch64` 包后,文件通常位于 `/usr/share/qemu-efi-aarch64/QEMU_EFI.fd` 或 `/usr/share/AAVMF/`。 * **CentOS/RHEL**:安装 `edk2-aarch64` 包后,文件通常位于 `/usr/share/edk2/aarch64/QEMU_EFI.fd`。 我的环境中,qenu是自己编译的,会自动编译好bios 在 ~/code/gitlab/qemu/build 目录下已经编译好了 BIOS 固件: BIOS/UEFI 固件位置 路径: build/pc-bios/ 已编译的 BIOS/UEFI 固件文件包括: | 包括: - x86_64: - edk2-x86_2-x86_64-code.fd (3.5MB) - edk2-x86_64-secure-code.fd (安全启动版本) - i386: - edk2-i386-code.fd - edk2-i386-secure-code.fd - ARM/AARCH64: - edk2-aarch64-code.fd (64MB) - edk2-arm-code.fd (64MB) - RISC-V: - edk2-riscv-code.fd (32MB) - LoongArch: - edk2-loongarch64-code.fd (16MB) 这些 .fd 文件是 UEFI/BIOS 固件镜像,可用于 QEMU 虚拟机启动。 **2. 直接下载预编译版本** 如果你使用的是 Windows 环境,或者不想通过包管理器安装,可以直接从开源社区下载预编译好的 `QEMU_EFI.fd` 文件。例如,可以从 Linaro 的官方快照仓库或 EDK2 项目的发布页面直接获取。 **总结建议**: * 如果你只是想**跑一个完整的 ARM Linux 系统**(如 Ubuntu Server),直接去系统目录找 `QEMU_EFI.fd` 并在 QEMU 启动命令中使用 `-bios QEMU_EFI.fd` 即可,无需自己编译。 * 如果你是为了**学习嵌入式启动流程或做底层驱动开发**,才需要去克隆 U-Boot 源码并使用交叉编译工具链自己编译 `u-boot.bin`。