Inserting Modules into LattePanda BIOS

One advantage of UEFI is its modularity, meaning you can write a module that, once compiled, can be inserted into an existing BIOS and executed. Previously, the implementation methods of each IBV varied greatly, and there was almost no way to achieve universality except for inserting in a special form like PCI ROM. The demonstration here is to write a DXE module in the EDK2 environment and then insert it into LattePanda.

First, design the code, and you can write it by referring to the module \\OvmfPkg\\8254TimerDxe.

The code is very simple, the entry is the InitializezMessage() function, which registers the OnMyReadyToBoot function when the ReadyToBootEvent event is triggered. The code is as follows:

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;}

Thus, when the BIOS is ready to boot, it jumps into the OnMyReadyToBoot() function, which simply loops and displays a string.

/**  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);}

Then add it to the compilation, modify \\OvmfPkg\\OvmfPkgX64.dsc as follows:

!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

Modify \\OvmfPkg\\OvmfPkgX64.fdf as follows:

!ifdef $(CSM_ENABLE)  INF  OvmfPkg/8259InterruptControllerDxe/8259.inf  INF  OvmfPkg/8254TimerDxe/8254Timer.inf!else  INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf!endif#LABZ_Debug_StartINF  OvmfPkg/ zMessage / zMessage.inf#LABZ_Debug_EndINF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.infINF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.infINF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf

Use the following command to test on QEMU:

qemu-system-x86_64 -bios ovmf.fd  -net none 

You can see that the defined string is output on the screen during the boot process.

The generated FFS file is located in \\Build\\OvmfX64\\DEBUG_VS2019\\FV\\Ffs\\00002237-2024-0513-A7F3-1449F9E0E4BDzMessage directory (for convenience, we specified the module’s GUID in the INF to start with 0000). The file name is 00002237-2024-0513-A7F3-1449F9E0E4BD.ffs. This is our compiled module.

Next, use MMTOOL to open the IFWI file provided by LattePanda:

Inserting Modules into LattePanda BIOS

We choose to insert at Volume 03:02-01 Index 137 (theoretically, the position of the UEFI module in the BIOS does not affect the loading order, this is just a randomly chosen position for convenience). Below is the completed result:

Inserting Modules into LattePanda BIOS

Finally, use “Save Image as…” to save it again as zMessage.fd, and then flash it to LattePanda.

The test video

Leave a Comment

Your email address will not be published. Required fields are marked *