UEFI 的一个优点是模块化,意思是你可以编写一个模块,编译后能够插入到已有的BIOS中并且执行。在此之前,每个 IVB 实现方式差异巨大,除了按照 PCI ROM 这种特别形式插入几乎没有办法实现通用。这次演示的就是在 EDK2环境下编写一个DXE 模块,然后插入到LattePanda中。
首先进行代码的设计,仿照\OvmfPkg\8254TimerDxe这个模块就可以写好。
代码非常简单,入口是InitializezMessage () 函数,进入之后注册OnMyReadyToBoot函数,当ReadyToBootEvent事件时触发之。代码如下:
EFI_STATUS
EFIAPI
InitializezMessage (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status=EFI_SUCCESS;
EFI_EVENT ReadyToBootEvent;
DEBUG ((DEBUG_INFO, "UPassword DXE Loaded\n"));
//
// Register the event to reclaim variable for OS usage.
//
EfiCreateEventReadyToBootEx (
TPL_NOTIFY,
OnMyReadyToBoot,
NULL,
&ReadyToBootEvent
);
return Status;
}
这样,当BIOS 准备启动的时候就是跳入OnMyReadyToBoot() 函数,执行,在函数中只是循环显示一段字符串。
/**
On Ready To Boot Services Event notification handler.
Notify SMM variable driver about the event.
@param[in] Event Event whose notification function is being invoked
@param[in] Context Pointer to the notification function's context
**/
VOID
EFIAPI
OnMyReadyToBoot (
IN EFI_EVENT Event,
IN VOID *Context
)
{
DEBUG ((EFI_D_INFO, "Invoke OnMyReadyToBoot\n"));
for (UINTN i=0;i<5;i++) {
gST->ConOut->OutputString(gST->ConOut,L"\r\n delay from www.lab-z.com\r\n");
gBS->Stall(1000000UL);
}
gBS->CloseEvent (Event);
}
然后将其加入编译,在\OvmfPkg\OvmfPkgX64.dsc 修改如下:
!ifdef $(CSM_ENABLE)
OvmfPkg/8259InterruptControllerDxe/8259.inf
OvmfPkg/8254TimerDxe/8254Timer.inf
!else
OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
!endif
#LABZ_Debug_Start
OvmfPkg/ zMessage / zMessage.inf
#LABZ_Debug_End
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
在 \OvmfPkg\OvmfPkgX64.fdf 修改如下:
!ifdef $(CSM_ENABLE)
INF OvmfPkg/8259InterruptControllerDxe/8259.inf
INF OvmfPkg/8254TimerDxe/8254Timer.inf
!else
INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
!endif
#LABZ_Debug_Start
INF OvmfPkg/ zMessage / zMessage.inf
#LABZ_Debug_End
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
使用如下命令在 QEMU 上测试:
qemu-system-x86_64 -bios ovmf.fd -net none
可以看到在启动过程中屏幕上输出了定义的字符串。
生成的FFS文件在\Build\OvmfX64\DEBUG_VS2019\FV\Ffs\00002237-2024-0513-A7F3-1449F9E0E4BDzMessage目录中(为了方便查找,我们在 INF中指定模块的 GUID 是 0000开头的)。文件名是 00002237-2024-0513-A7F3-1449F9E0E4BD.ffs。这就是我们编译后的模块。
接下来,使用 MMTOOL打开 LattePanda官方提供的 IFWI 文件:
我们选择在Volume 03:02-01 Index 137 的地方插入(理论上 UEFI模块在BIOS中的位置不影响加载顺序,这里只是为了方便查找随便选择的位置),下面就是完成后的结果:
最后,使用“Save Image as…”重新保存命名为 zMessage.fd,然后烧录到 LattePanda上即可。
本文提到的 UEFI 源代码:
UEFI 源代码生成的 FFS 文件:
最终加入模块的 LattePanda 的IFWI: