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 文件:
我们选择在Volume03:02-01 Index 137 的地方插入(理论上 UEFI模块在BIOS中的位置不影响加载顺序,这里只是为了方便查找随便选择的位置),下面就是完成后的结果:
最后,使用“SaveImage as…”重新保存命名为zMessage.fd,然后烧录到LattePanda上即可。 本文提到的UEFI 源代码: UEFI 源代码生成的FFS 文件:
最终加入模块的LattePanda 的IFWI:
工作的视频可以在这里看到:
|