不确定这个问题是应该放在这里还是放在 stack overflow 中,但我正在编写一个 UEFI 应用程序来启动自定义内核。我可以在 QEMU 中测试 UEFI 应用程序并使用 GDB 来调试和检查内存。我还可以做一些基本的事情,比如定位协议、打印和清除屏幕。
我的问题是,从 UEFI 应用程序启动内核的典型过程是什么? UEFI 应用程序是否需要读取文件系统来查找内核?
我在网上找到的大多数 UEFI 应用程序示例都是 hello world 应用程序。我发现了一个启动内核的简单示例,但我不明白 UEFI 应用程序如何找到内核。我也不明白内存复制。
https://devcodef1.com/news/1304006/custom-kernel-uefi-boot-with-qemu
我还发现了几个更复杂的例子,但我仍然有点困惑。 https://gitlab.com/bztsrc/bootboot/-/blob/master/x86_64-efi/bootboot.c https://github.com/KunYi/Simple-UEFI-Bootloader/blob/master/Simple_UEFI_Bootloader/src/Loader.c#L2771
您找到的带有示例的文章看起来像是人工智能生成的——如果它是由真人撰写的,他们肯定会至少查看一次自己的帖子并修复损坏的 #includes HTML。(他们的其他一些帖子直接引用了不存在且从未存在过的命令和选项。)
没有固定的过程。UEFI 程序会执行其需要的任何操作,以任何方式将其需要加载到内存中,然后最终调用 ExitBootServices() 并跳转到内核入口点。可能唯一不变的是从 EFI 获取内存映射。
该程序可以使用 EFI 文件系统访问协议将单独的文件加载到内存中(例如,使用普通的 Open/Read/Close),也可以使用 EFI 块设备访问协议来实现自己的文件系统驱动程序(例如,GRUB2 就是这样做的),或者它本身可以是内核(Linux 使用其“EFI 存根”功能来实现这一点)。
看一下Linux:
Linux 的旧efilinux引导加载程序相当简单 - fs/fs.c 使用 EFI“文件系统协议”读取其配置文件并从文件系统加载 Linux 内核映像(以及将移交给 Linux 的 initrd 存档),然后 loaders/bzimage/bzimage.c 准备一个带有一些初始参数的结构以移交给内核,然后它调用 ExitBootServices 并跳转(通过 loaders/bzimage/x86_64.h)到内存指针。
GRUB2 使用一些 EFI 服务,但它也严重依赖直接设备访问;它对各种文件系统甚至硬件类型提供内部支持(例如,它具有内部 SATA 支持)。初始配置嵌入在 grub.efi 中,并将其指向 grub.cfg 的路径,然后其中包含内核的路径。
systemd-boot 不进行任何内核加载;它期望内核包含一个“EFI 存根”,以便它可以作为 EFI 可执行文件启动(即内核是其自己的引导加载程序)。内核的 EFI 存根已经在内存中拥有内核的其余部分,因此它不需要任何文件系统访问。