当前位置:首页>Linux>从零构建 Linux|02 Bootloader

从零构建 Linux|02 Bootloader

  • 2026-10-11 07:00:39
从零构建 Linux|02 Bootloader

系列第 2 篇|启动链第一环:把控制权交给 Linux 内核本篇重点建立概念,不讲移植手册

上一篇把整条启动链走了一遍。本篇只聚焦第一环:Bootloader(引导加载程序)——负责把控制权从机器固件交到 Linux 内核手里的那段程序。

本系列后面的 PC demo,实际用到的是 UEFI + GRUB;U-Boot 和 Little Kernel 作为嵌入式对照理解即可。

先把几个词说清楚

术语
含义
固件(firmware)
写在主板 / SoC 里、出厂就有的底层软件。PC 上今天多为 UEFI,老机器是 BIOS
Bootloader(引导加载程序)
在固件之后、内核之前运行的程序,负责加载内核
内核映像(kernel image)
内核编译后的那个大文件,例如 PC 上常见的 vmlinuz / bzImage
启动参数(kernel cmdline / bootargs)
一串文本,Bootloader 传给内核,用来说明「根分区在哪、日志打到哪」等
跳转(jump)
Bootloader 完成准备工作后,把 CPU 指令指针改到内核入口,相当于把舞台交给内核

如果你写过 C:Bootloader 很像「自己实现一个简易加载器」——把另一个程序的二进制读进内存,设置好参数,然后 call 过去;区别是它运行得更早,几乎没有操作系统可依赖。

Bootloader 共性职责

不管产品文档里写的是 GRUB 还是 U-Boot,核心职责通常都包括以下五步。理解这五步,比背产品名更重要。

  1. 做最小硬件初始化让内存、时钟、存储控制器等处在「至少能读到内核文件」的状态。PC 上很多事固件已经做了一部分;嵌入式上 U-Boot 往往要做更多。

  2. 从介质加载内核映像介质可能是硬盘、SSD、U 盘、eMMC、SD 卡,甚至网络。Bootloader 要访问这些介质上的分区或文件系统,把内核文件读出来。

  3. 准备硬件描述信息内核需要知道「这台机器有什么设备」。在 PC(x86)上,很多信息通过 ACPI 提供;在大量嵌入式板上,则使用设备树 DTB(Device Tree Blob)。

  4. 设置启动参数(cmdline)例如告诉内核:根文件系统在哪个分区(root=),日志打印到哪个控制台(console=)。

  5. 跳转到内核入口至此 Bootloader 的历史使命结束,CPU 开始执行内核代码。

四种常见实现

名称
常见场景
一句话
UEFI
现代 PC、笔记本
主板固件接口标准;开机后先跑它,再启动 .efi 程序(常是 GRUB)
GRUB
桌面 / 服务器 Linux、双系统
「启动菜单程序」:读文件系统、显示菜单、加载内核 / initrd、可改启动参数
U-Boot
嵌入式开发板(含很多 RISC-V 板)
用环境变量(如 bootcmd、bootargs)描述如何加载与传参
Little Kernel(LK)
手机、部分 SoC 方案
体量更小,常作为厂商快速启动链路里的一环

为什么 PC 爱用 UEFI + GRUB,板子爱用 U-Boot?

场景
原因
PC
固件已高度标准化(UEFI),磁盘分区、文件系统、多系统共存都很复杂;GRUB 擅长「读各种文件系统 + 画菜单 + 改参数」
嵌入式板
每家芯片启动链路不同,存储布局五花八门,需要能紧紧贴着 SoC 启动流程的 Bootloader;U-Boot 生态正好覆盖这一点

本系列 demo 要在 Windows PC 上做双系统,所以你会反复碰到 UEFI 启动项和 GRUB 菜单;它们是上下游关系,不是二选一。

Bootloader 交给内核的「包裹」

交接时,Bootloader 通常会准备好这些东西:

内容
作用
内核映像
内核本体文件。没有它就没有操作系统核心
initramfs / initrd(可选)
很小的「临时根文件系统」,存在内存里。用于早期加载驱动、找到真正的根分区,再切换过去
cmdline
一行或一段文本参数。内核启动时按文本配置行为
DTB(嵌入式常见)
设备树二进制。告诉内核板子上挂了哪些设备、地址在哪

启动参数里最值得先认的三个

参数
含义
root=
真正的根文件系统在哪个设备 / 分区,或用 UUID 指定
console=
内核日志和终端交互走哪个设备(串口或屏幕虚拟终端)
init=
指定用户空间一号进程的路径;不写则通常找 /sbin/init 等默认位置

PC 上常见样子(示意):

root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxro quiet

意思大概是:根分区用这个 UUID 标识;只读方式先挂上(ro);少打印一些信息(quiet)。

嵌入式串口调试时常见样子(示意):

console=ttyS0,115200root=/dev/mmcblk0p2 rw

意思大概是:日志打到串口 ttyS0,波特率 115200;根文件系统在 eMMC / SD 的第 2 分区;可读写挂载(rw)。

你以后排错时,先读懂 cmdline,往往比一上来就翻内核源码有效得多。

两段「长什么样」的最小例子

下面例子只为建立形状印象,不必在此刻背命令。

GRUB 菜单项在配置里的样子

menuentry 'My Linux' {  linux /boot/vmlinuz root=UUID=... ro  initrd /boot/initrd.img}

用文字翻译:

关键字
含义
menuentry
启动菜单里的一个选项
linux ...
指定内核文件,并附带 cmdline
initrd ...
指定初始内存盘,帮助早期启动

U-Boot 环境变量的样子

setenv bootargs \  console=ttyS0,115200 \  root=/dev/mmcblk0p2 rwsetenv bootcmd \  'fatload mmc 0:1 0x80080000 Image; \   booti 0x80080000 - 0x83000000'boot

用文字翻译:

关键字
含义
bootargs
要传给内核的参数字符串
bootcmd
一串「先加载文件到某地址,再启动内核」的动作
boot
执行启动

本篇小结

请用自己的话确认能回答这三句:

  1. Bootloader 的核心工作是:加载内核、传递参数、跳转执行。
  2. 在 PC 上,常见组合是 UEFI(固件)+ GRUB(Linux 引导器);在很多嵌入式板上,是 U-Boot。
  3. 看到 root=、console=,你应该能说出它们在指挥内核做什么。

下一篇我们继续往后看:内核接过控制权之后,如何一步步走到挂载 rootfs、启动 init。

系列文章列表:

从零构建 Linux 系统
从零构建 Linux|01 启动流程总览

最新文章

随机文章