"zeropage" 是 Linux 内核启动过程中一个核心的数据结构,它实际上就是struct boot_params的别称。
什么是 Zeropage?
"Zeropage"(零页)是 x86 架构 Linux 内核启动协议中,一个承载所有启动信息的内存页(大小为4KB)。它之所以叫这个名字,是因为在启动协议中,它被要求初始化为全零。
这个结构体是连接引导程序(Bootloader)和内核的桥梁,包含了从固件收集到的硬件信息。引导程序在启动内核前,会将从 BIOS/UEFI 获取的硬件信息填充到 Zeropage 的特定字段中,内核启动时再从这里读取。
Zeropage 里有什么?
Zeropage 的结构定义在arch/x86/include/uapi/asm/bootparam.h文件中。它包含了非常丰富的信息,以下是其中一些关键的字段:
| 偏移/大小 | 名称 | 含义 |
|---|---|---|
| 000/040 | screen_info | 文本模式或帧缓冲区的显示信息。 |
| 070/008 | acpi_rsdp_addr | ACPI RSDP (根系统描述指针) 表的物理地址,对电源管理至关重要。 |
| 0C0/004 | ext_ramdisk_image | ramdisk_image的高32位,用于指定 initrd (初始 RAM 磁盘) 的位置。 |
| 0C8/004 | ext_cmd_line_ptr | cmd_line_ptr的高32位,用于传递内核命令行参数。 |
| 1C0/020 | efi_info | 用于 EFI (可扩展固件接口) 启动的信息。 |
| 1EC/001 | secure_boot | 指示固件是否开启了安全启动(secure boot)。 |
| 2D0/A00 | e820_table | 由 BIOS/UEFI 提供的E820 内存映射表,这是内核了解物理内存布局最核心的数据。 |
表中“偏移/大小”一列的数值,如
000/040,表示该字段从 Zeropage 起始地址偏移0x000字节,大小为0x40(64) 字节。
如何传递 Zeropage?
Zeropage 的传递方式取决于启动协议:
32位启动协议:内核要求 CPU 处于32位保护模式,并禁用分页。此时,
%esi寄存器必须保存 Zeropage 的物理基地址。64位启动协议:内核要求 CPU 处于64位长模式并启用分页。此时,
%rsi寄存器必须保存 Zeropage 的物理基地址。
这正是在head_64.S中反复看到%rsi被用作boot_params指针的原因——它必须被精确地传递给内核。
重要提示:非稳定 ABI
Linux 内核官方强烈警告:Zeropage (struct boot_params)不是一个稳定的 ABI (应用程序二进制接口)。
这意味着它的内部布局(如字段的偏移和大小)可能随内核版本变化而改变。因此,任何外部引导程序都不应依赖其内部结构,而应通过内核提供的、已版本化的实模式启动协议来与内核交互。Kexec 或 LinuxBIOS 等直接使用 32/64 位协议的程序,则必须严格遵守协议规范。