MachineHunter
Posted on June 26, 2022
In this series, I will show you how to build custom DXE Driver by EDK2 and execute it on UP2 Pro (Single Board Computer). To check if it was executed successfully, this DXE Driver will store current time in UEFI Variable so that, you can check if the time was stored correctly from UEFI Shell.
Preparing EDK2
sudo apt install build-essential uuid-dev iasl nasm git python python3-distutils python3-apt acpica-tools
- go to your project's folder and
git clone https://github.com/tianocore/edk2.git
-
cd edk2
andgit submodule update --init
make -C BaseTools
source edksetup.sh
BaseTool is a set of tools to build UEFI modules and format the module to EFI_SECTION, FFS, FV and so on. By executing edksetup.sh
, you can execute commands in BaseTool without specifying 'PATH'. You might want to take a brief look at the link to know what kind of tools are in BaseTools and what kind of arguments you can specify.
Configuration of EDK2 for making DXE Drivers
1: Editing target.txt
Edit edk2/Conf/target.txt
like this (Comments excluded).
ACTIVE_PLATFORM = MdeModulePkg/MdeModulePkg.dsc
TARGET = DEBUG
TARGET_ARCH = X64
TOOL_CHAIN_CONF = Conf/tools_def.txt
TOOL_CHAIN_TAG = GCC5
BUILD_RULE_CONF = Conf/build_rule.txt
You might want to execute build
in edk2/
and see if it returns - Done -
. If you got any fails at this point, then some configs on your edk2 are wrong.
2: Making necessary files
Make folder for your DXE Driver inside edk2/MdeModulePkg/
and prepare two files inside it like this.
MyDxe
├── MyDxe.c
└── MyDxe.inf
3: Editing MdeModulePkg.dsc
Add your module under the [Component]
section inside edk2/MdeModulePkg/MdeModulePkg.dsc
like followings.
[Components]
MdeModulePkg/MyDxe/MyDxe.inf # add only this
MdeModulePkg/Application/HelloWorld/HelloWorld.inf
MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
Configuring MyDxe.inf
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = MyDxe
FILE_GUID = <put your GUID generated by uuidgen>
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = MyDxeEntry
[Sources]
MyDxe.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
UefiLib
PrintLib
[Protocols]
[Depex]
TRUE
I'm not using any Protocols in this DXE Driver so I left [Protocols]
blank. If this DXE Driver has to be executed after specific Protocols are installed, you have to put that into [Depex]
, but I'm not using any Protocols so I just put TRUE
. For further details, you can check CodeRush's post in Win-Raid Forum.
Source Code of DXE Driver (MyDxe.c)
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiRuntimeServicesTableLib.h>
EFI_STATUS EFIAPI MyDxeEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
UINT32 myvarSize = 30;
CHAR8 myvarValue[30] = {0};
CHAR16 myvarName[30] = L"MyDxeStatus";
EFI_TIME time;
// 11223344-5566-7788-99aa-bbccddeeff00
EFI_GUID myvarGUID = { 0x11223344, 0x5566, 0x7788, { 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00 }};
gRT->GetTime(&time, NULL);
AsciiSPrint(myvarValue, 12, "%2d/%2d %2d:%2d", time.Month, time.Day, time.Hour, time.Minute);
gRT->SetVariable(
myvarName,
&myvarGUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
myvarSize,
myvarValue);
return EFI_SUCCESS;
}
This will create UEFI variable named "MyDxeStatus" and stores current time derived by GetTime
function in the Runtime Services. To prepare format string, I used AsciiSPrint
from
PrintLib Library.
Build DXE Driver
You can execute build
to build this driver. If there were no errors, it will show Done
at the end and output files can be found in edk2/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/MyDxe/MyDxe/OUTPUT
.
Generating FFS File from the DXE Driver
If you want to add this DXE Driver into BIOS image, you have to convert this into Fimware FileSystem (FFS) format. FFS is consisted of EFI_SECTION Files, which in most case are below 4 sections.
- DXE dependency section
- PE32 image section
- User interface section
- Version section
You can refer to EDK2 Build Specification for the information related to these. But anyway, you have to first generate these section files and then, combine them to construct FFS File. Generating section files can be done by using GenSec
command from BaseTools. Also, there is GenFfs
command from BaseTools to combine them into FFS file.
Inside edk2/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/MyDxe/MyDxe/OUTPUT/
, I made a folder "FFS" and put the generated files there. Section files are generated by the following commands.
GenSec MyDxe.efi -S EFI_SECTION_PE32 -o FFS/MyDxe.pe32
GenSec MyDxe.efi -S EFI_SECTION_USER_INTERFACE -o FFS/MyDxe.ui -n "MyDxe"
GenSec MyDxe.efi -S EFI_SECTION_VERSION -o FFS/MyDxe.ver
cd FFS
GenFfs -t EFI_FV_FILETYPE_DRIVER -d 1 -g "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -i MyDxe.pe32 -i MyDxe.ui -i MyDxe.ver -o MyDxe.ffs
You need to generate GUID for this FFS and specify it in GenFfs
. In this DXE Driver, I didn't use DEPEX so I didn't put that, but if you have, you can execute GenSec MyDxe.depex -S EFI_SECTION_DXE_DEPEX -o FFS/MyDxe.depex
(MyDxe.depex is already built with build
command in the OUTPUT folder) and specify that with -i
option in GenFfs
command.
Posted on June 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.