How to Load and Unload UEFI Drivers in UEFI Shell
The Unified Extensible Firmware Interface (UEFI) Shell provides an interactive pre-boot environment that allows firmware and hardware engineers to execute commands, manage storage, and test binaries. This article explains how developers dynamically load and unload custom UEFI test drivers using native UEFI Shell commands, verify driver binding, and manage handle databases without rebuilding or reflashing the system firmware.
Preparing the Environment
Before managing test drivers dynamically, you must access the UEFI
Shell and prepare the compiled driver file (.efi):
Build the Driver: Compile your driver using an environment such as the EDK II (EFI Development Kit II) targeting your platform's architecture (typically
X64orAARCH64).Transfer to Media: Copy the resulting
.efibinary onto a FAT32-formatted USB drive or a dedicated EFI System Partition (ESP).Boot into the Shell: Boot your target system or virtual machine (e.g., QEMU with OVMF) into the UEFI Shell.
Navigate to the File System: Identify the mapped drive corresponding to your storage device by running
map -r. Change to that drive and verify the file exists:fs0: ls
Dynamically Loading a Driver
To load an executable UEFI driver into system memory, use the
load command.
load MyTestDriver.efi
When this command runs, the UEFI Boot Service
LoadImage() loads the binary into memory, and
StartImage() executes its entry point. If the driver is an
EFI Driver Model-compliant driver, the entry point installs the
EFI_DRIVER_BINDING_PROTOCOL onto the driver's image
handle.
If the operation is successful, the shell outputs a confirmation showing the assigned handle:
load: Image 'fs0:\MyTestDriver.efi' loaded at [Handle] - Success
To automatically connect the newly loaded driver to compatible controllers, run:
connect -r
Verifying and Inspecting the Driver
Once loaded, you must verify that the driver initialized correctly and bound to the intended hardware handles.
List Installed Drivers: Use the
driverscommand to see all active drivers and find your driver's Handle ID:driversInspect Handles and Protocols: Use the
dh(Dump Handle) command with your driver's handle identifier (e.g.,B4) to inspect the protocols it produces:dh -v B4Verify Device Binding: Check which devices the driver is managing using the
devicescommand:devices
Dynamically Unloading a Driver
Unloading a driver allows developers to test deinitialization routines, ensure memory cleanup, and test code revisions without rebooting.
To unload a driver, pass its handle identifier to the
unload command:
unload B4
When unload executes:
- The shell calls the driver's
Stop()function on all managed controller handles. - The driver uninstalls any installed protocols and frees allocated pools and pages.
- The shell calls
UnloadImage()to purge the binary from memory.
To force an unload if a device handle remains bound, you can first manually disconnect the driver:
disconnect [DeviceHandle] [DriverHandle]
unload [DriverHandle]
Common Error Codes
EFI_NOT_FOUND/EFI_UNSUPPORTED: Often occurs when required protocol dependencies are missing from the system.EFI_ALREADY_STARTED: Occurs when attempting to bind a driver to a controller handle that is already being managed by an active driver.EFI_ACCESS_DENIED: Typically returned during anunloadoperation if the driver does not implement anUnloadpointer in itsEFI_LOADED_IMAGE_PROTOCOL, preventing safe removal.