|
本帖最后由 wintoflash 于 2022-10-10 20:50 编辑
关于 grub4efi 对 Linux 内核支持的改进,我想征求一下 yaya 和大家的意见。
UEFI 下启动 Linux 内核,有很多种方式。
1. 传统的 32 位启动协议 (32-bit Boot Protocol)
这种方式下 Linux 接管时,已经退出了 UEFI 启动服务,Linux 获取不到 UEFI 系统表指针,因此 Linux 启动后无法调用 UEFI 运行时服务。
这种方式的实现也比较复杂,主流 Linux 发行版都没有采用这种方法,因此不予考虑。
2. 64 位启动协议 (64-bit Boot Protocol)
缺点同上,而且不支持 32 位 Linux。
3. EFI 交接协议 (EFI Handover Protocol)
grub4efi 目前使用的就是这种方式。将内核加载到内存后直接跳转到对应位数(32/64)下的入口,同时传递镜像句柄,UEFI 系统表和 Linux 启动参数。
EFI Handover Protocol 目前已经被主线 Linux 废弃:
NOTE: The EFI Handover Protocol is deprecated in favour of the ordinary PE/COFF
entry point, combined with the LINUX_EFI_INITRD_MEDIA_GUID based initrd loading protocol (refer to [0] for an example of the bootloader side of this), which removes the need for any knowledge on the part of the EFI bootloader regarding the internal representation of boot_params or any requirements/limitations regarding the placement of the command line and ramdisk in memory, or the placement of the kernel image itself.
而且这种方式需要内核自己进行重定位。在有些电脑上启动 ntloader 出现问题,就是因为 ntloader 没有进行 self-relocation 导致的。
4. 直接当作 EFI 可执行程序进行启动
这种方式下,我们不用操心内核的加载/重定位,直接把它交给固件来做。我们只要在 initrd 加载到内存后通过某种方式告诉内核就行了。
Linux 官方给出的方法是 initrd loading protocol。bootloader 实现一个 EFI_LOAD_FILE2_PROTOCOL,Vendor GUID 设为 EFI_INITRD_MEDIA_GUID,内核就会自己找到这个 protocol,来读内存中的 initrd。目前 u-boot 使用的就是这种方法。grub2 官方也在考虑支持这种方式。
iPXE 使用的方式是实现一个 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL,把它对应的句柄传给内核,这样内核就能加载上面的 initrd。
目前 grub4efi 支持方法 3,但是方法 3 已经被 Linux 官方废弃,将来有可能会删掉。
因此我考虑改为用方法 4 启动 Linux 内核,弄一个 EFI_LOAD_FILE2_PROTOCOL 来加载 initrd。
这样会造成一定程度的不兼容,就是 64 位 EFI 下不能启动 32 位 Linux (反之亦然)。不过不支持方法 3 的发行版要比不支持方法 4 的发行版要多。
不知道 yaya 有没有什么看法?
-----------------------
u-boot 相关实现:https://github.com/u-boot/u-boot ... cc3a5d717d4739b0fd0
Linux 官方已经在讨论默认取消 EFI Handover Protocol 支持:https://lore.kernel.org/lkml/Y0GOKnD89SOjGzCf@nazgul.tnic/t/
|
|