Chapter 9: Driver Model
Learn the architecture that lets UEFI drivers discover hardware, manage devices, and coexist cleanly with other firmware components.
9.1 UEFI Drivers vs. UEFI Applications
Before diving into the driver model, it is important to understand the fundamental difference between the two kinds of UEFI executables.
| Characteristic | UEFI Application | UEFI Driver |
|---|---|---|
| Entry point return | Returns control to the caller; image is unloaded | Typically stays resident in memory |
| Lifetime | Transient – runs and exits | Persistent – remains until explicitly unloaded |
| Typical use | Boot loaders, shell utilities, diagnostics | Hardware abstraction, bus enumeration, service providers |
| Module type in INF | UEFI_APPLICATION |
UEFI_DRIVER |
| Image type in PE header | EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION |
EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER or EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER |
A UEFI application is like a user-mode program: it does its work and terminates. A UEFI driver is like a kernel module: it installs services, manages devices, and stays loaded until the platform no longer needs it.
A driver’s entry point typically does very little – it installs a Driver Binding Protocol and returns
EFI_SUCCESS. The real work happens later when the UEFI core calls the binding protocol’sStart()function.
9.2 The Driver Binding Protocol
The EFI Driver Binding Protocol is the cornerstone of the UEFI driver model. Every well-behaved UEFI driver installs an instance of this protocol. It contains three function pointers and two version fields:
typedef struct _EFI_DRIVER_BINDING_PROTOCOL {
EFI_DRIVER_BINDING_SUPPORTED Supported;
EFI_DRIVER_BINDING_START Start;
EFI_DRIVER_BINDING_STOP Stop;
UINT32 Version;
EFI_HANDLE ImageHandle;
EFI_HANDLE DriverBindingHandle;
} EFI_DRIVER_BINDING_PROTOCOL;
9.2.1 Supported()
EFI_STATUS
EFIAPI
MyDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
The platform firmware calls Supported() to ask the driver: “Can you manage this controller?” The driver must answer quickly and without side effects. A typical implementation:
- Opens the bus protocol on
ControllerHandleusingBY_DRIVERto check for conflicts. - Reads the device’s vendor/device ID from configuration space.
- Compares against a list of known IDs.
- Closes the protocol (since this is just a probe).
- Returns
EFI_SUCCESSif the device is supported, orEFI_UNSUPPORTEDotherwise.
Supported()must not modify hardware state. If it allocates resources, it must free them before returning. The UEFI specification explicitly requiresSupported()to be idempotent.
9.2.2 Start()
EFI_STATUS
EFIAPI
MyDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
After Supported() returns success, the core calls Start() to actually take ownership of the device. This function:
- Opens the bus I/O protocol
BY_DRIVER(claiming exclusive access). - Allocates private data structures.
- Initializes the hardware.
- Installs one or more I/O abstraction protocols on the controller handle (e.g.,
EFI_BLOCK_IO_PROTOCOL,EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL). - Returns
EFI_SUCCESS.
9.2.3 Stop()
EFI_STATUS
EFIAPI
MyDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
);
Stop() is the reverse of Start(). It must:
- Uninstall all protocols that
Start()installed. - Close all protocols opened with
BY_DRIVER. - Free all allocated memory.
- Leave the hardware in a safe state.
9.3 Driver Lifecycle
The following diagram shows the complete lifecycle of a UEFI driver from image loading to unloading.
stateDiagram-v2
[*] --> Loaded : LoadImage()
Loaded --> Initialized : StartImage() calls entry point
Initialized --> BindingInstalled : Entry point installs\nDriver Binding Protocol
BindingInstalled --> Probing : ConnectController() triggers\nSupported() calls
state ProbeResult <<choice>>
Probing --> ProbeResult
ProbeResult --> BindingInstalled : EFI_UNSUPPORTED\n(device not ours)
ProbeResult --> Started : EFI_SUCCESS → Start()
Started --> Stopped : DisconnectController()\ncalls Stop()
Stopped --> BindingInstalled : Can be reconnected\nto new devices
Started --> Unloading : UnloadImage()
BindingInstalled --> Unloading : UnloadImage()
Stopped --> Unloading : UnloadImage()
Unloading --> [*]
Key points
- A single driver image can manage multiple controllers simultaneously. Each controller gets its own
Start()/Stop()cycle. ConnectController()iterates over all installed Driver Binding Protocols, callingSupported()on each, highest version first.- Drivers can be unloaded at any time. The
Unload()function in the Loaded Image Protocol must callStop()on every active controller before the image is freed.
9.4 Component Name Protocol
The EFI Component Name 2 Protocol allows drivers to provide human-readable names for themselves and the controllers they manage. This is what the UEFI Shell’s drivers and devices commands display.
typedef struct _EFI_COMPONENT_NAME2_PROTOCOL {
EFI_COMPONENT_NAME2_GET_DRIVER_NAME GetDriverName;
EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME GetControllerName;
CHAR8 *SupportedLanguages;
} EFI_COMPONENT_NAME2_PROTOCOL;
Implementation example
GLOBAL_REMOVE_IF_UNREFERENCED
EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
{ "en", (CHAR16 *)L"Sample PCI Device Driver" },
{ NULL, NULL }
};
EFI_STATUS
EFIAPI
SampleGetDriverName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mDriverNameTable,
DriverName,
FALSE
);
}
EFI_STATUS
EFIAPI
SampleGetControllerName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
return EFI_UNSUPPORTED; // Simplified -- real drivers should provide names
}
EFI_COMPONENT_NAME2_PROTOCOL gSampleComponentName2 = {
SampleGetDriverName,
SampleGetControllerName,
"en"
};
9.5 Driver Diagnostics Protocol
The EFI Driver Diagnostics 2 Protocol is optional but valuable for production firmware. It allows a management application or the UEFI Shell drvdiag command to run diagnostics on a controller.
typedef struct _EFI_DRIVER_DIAGNOSTICS2_PROTOCOL {
EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS RunDiagnostics;
CHAR8 *SupportedLanguages;
} EFI_DRIVER_DIAGNOSTICS2_PROTOCOL;
The RunDiagnostics() function accepts a diagnostic type:
| Type | Purpose |
|---|---|
EfiDriverDiagnosticTypeStandard |
Quick non-destructive test |
EfiDriverDiagnosticTypeExtended |
Thorough test, may take longer |
EfiDriverDiagnosticTypeManufacturing |
Factory-level test, may be destructive |
9.6 Private Context Data Pattern
Real drivers need to store per-device state. The standard UEFI pattern uses a “private context” structure with a signature and a macro to convert from a protocol pointer back to the context:
#define SAMPLE_DRIVER_SIGNATURE SIGNATURE_32('S','M','P','L')
typedef struct {
UINT32 Signature;
EFI_HANDLE Handle;
EFI_PCI_IO_PROTOCOL *PciIo;
//
// Produced protocol
//
EFI_BLOCK_IO_PROTOCOL BlockIo;
//
// Device-specific state
//
UINT64 DeviceBaseAddress;
UINT32 SectorSize;
UINT64 TotalSectors;
} SAMPLE_DRIVER_PRIVATE_DATA;
#define SAMPLE_PRIVATE_FROM_BLOCK_IO(a) \
CR(a, SAMPLE_DRIVER_PRIVATE_DATA, BlockIo, SAMPLE_DRIVER_SIGNATURE)
The CR() macro (short for “Containing Record”) uses CONTAINING_RECORD logic plus a signature check. When a protocol function is called, you recover your private data like this:
EFI_STATUS
EFIAPI
SampleBlockIoReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
SAMPLE_DRIVER_PRIVATE_DATA *Private;
Private = SAMPLE_PRIVATE_FROM_BLOCK_IO (This);
ASSERT (Private->Signature == SAMPLE_DRIVER_SIGNATURE);
// Now use Private->PciIo, Private->DeviceBaseAddress, etc.
// ...
}
9.7 Complete Example: A Simple UEFI Driver
Below is a complete, compilable UEFI driver that demonstrates the driver binding protocol pattern. This driver does not manage real hardware – it installs a trivial custom protocol on a new handle to demonstrate the full lifecycle.
9.7.1 The Protocol Header (SampleProtocol.h)
#ifndef SAMPLE_PROTOCOL_H_
#define SAMPLE_PROTOCOL_H_
//
// {A7D54E3C-1B29-4F9E-8C4D-6E2A7F3B1D80}
//
#define SAMPLE_PROTOCOL_GUID \
{ 0xa7d54e3c, 0x1b29, 0x4f9e, \
{ 0x8c, 0x4d, 0x6e, 0x2a, 0x7f, 0x3b, 0x1d, 0x80 } }
typedef struct _SAMPLE_PROTOCOL SAMPLE_PROTOCOL;
typedef
EFI_STATUS
(EFIAPI *SAMPLE_GET_VALUE)(
IN SAMPLE_PROTOCOL *This,
OUT UINT32 *Value
);
typedef
EFI_STATUS
(EFIAPI *SAMPLE_SET_VALUE)(
IN SAMPLE_PROTOCOL *This,
IN UINT32 Value
);
struct _SAMPLE_PROTOCOL {
SAMPLE_GET_VALUE GetValue;
SAMPLE_SET_VALUE SetValue;
};
extern EFI_GUID gSampleProtocolGuid;
#endif // SAMPLE_PROTOCOL_H_
9.7.2 The Driver Source (SampleDriver.c)
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/ComponentName2.h>
#include "SampleProtocol.h"
//
// Private data
//
#define SAMPLE_PRIVATE_SIGNATURE SIGNATURE_32('S','m','p','D')
typedef struct {
UINT32 Signature;
EFI_HANDLE Handle;
SAMPLE_PROTOCOL SampleProtocol;
UINT32 StoredValue;
} SAMPLE_PRIVATE_DATA;
#define SAMPLE_PRIVATE_FROM_PROTOCOL(a) \
CR(a, SAMPLE_PRIVATE_DATA, SampleProtocol, SAMPLE_PRIVATE_SIGNATURE)
//
// Protocol function implementations
//
EFI_STATUS
EFIAPI
SampleGetValue (
IN SAMPLE_PROTOCOL *This,
OUT UINT32 *Value
)
{
SAMPLE_PRIVATE_DATA *Private;
if (This == NULL || Value == NULL) {
return EFI_INVALID_PARAMETER;
}
Private = SAMPLE_PRIVATE_FROM_PROTOCOL (This);
*Value = Private->StoredValue;
DEBUG ((DEBUG_INFO, "SampleDriver: GetValue() returning %u\n", *Value));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
SampleSetValue (
IN SAMPLE_PROTOCOL *This,
IN UINT32 Value
)
{
SAMPLE_PRIVATE_DATA *Private;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Private = SAMPLE_PRIVATE_FROM_PROTOCOL (This);
Private->StoredValue = Value;
DEBUG ((DEBUG_INFO, "SampleDriver: SetValue(%u)\n", Value));
return EFI_SUCCESS;
}
//
// Driver Binding Protocol functions
//
EFI_STATUS
EFIAPI
SampleDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
//
// This simple driver creates its own handle rather than binding
// to an existing controller. In a real driver you would probe
// the controller here (e.g., check PCI Vendor/Device IDs).
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
SampleDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
SampleDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
return EFI_UNSUPPORTED;
}
//
// Driver Binding Protocol instance
//
EFI_DRIVER_BINDING_PROTOCOL gSampleDriverBinding = {
SampleDriverSupported,
SampleDriverStart,
SampleDriverStop,
0x10, // Version
NULL, // ImageHandle -- filled in at entry
NULL // DriverBindingHandle -- filled in at entry
};
//
// Component Name
//
GLOBAL_REMOVE_IF_UNREFERENCED
EFI_UNICODE_STRING_TABLE mSampleDriverNameTable[] = {
{ "en", (CHAR16 *)L"Sample UEFI Driver" },
{ NULL, NULL }
};
EFI_STATUS
EFIAPI
SampleComponentNameGetDriverName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mSampleDriverNameTable,
DriverName,
FALSE
);
}
EFI_STATUS
EFIAPI
SampleComponentNameGetControllerName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
return EFI_UNSUPPORTED;
}
EFI_COMPONENT_NAME2_PROTOCOL gSampleComponentName2 = {
SampleComponentNameGetDriverName,
SampleComponentNameGetControllerName,
"en"
};
//
// Module-scoped handle for the protocol we install during entry
//
STATIC EFI_HANDLE mSampleHandle = NULL;
STATIC SAMPLE_PRIVATE_DATA *mPrivate = NULL;
//
// Unload handler
//
EFI_STATUS
EFIAPI
SampleDriverUnload (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
if (mSampleHandle != NULL) {
Status = gBS->UninstallProtocolInterface (
mSampleHandle,
&gSampleProtocolGuid,
&mPrivate->SampleProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
}
if (mPrivate != NULL) {
FreePool (mPrivate);
mPrivate = NULL;
}
//
// Uninstall Driver Binding and Component Name
//
Status = EfiLibUninstallDriverBindingComponentName2 (
&gSampleDriverBinding,
&gSampleComponentName2
);
return Status;
}
//
// Entry point
//
EFI_STATUS
EFIAPI
SampleDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Install Driver Binding and Component Name protocols
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gSampleDriverBinding,
ImageHandle,
NULL, // ComponentName (v1) -- not provided
&gSampleComponentName2
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Allocate private data and install our custom protocol
//
mPrivate = AllocateZeroPool (sizeof (SAMPLE_PRIVATE_DATA));
if (mPrivate == NULL) {
return EFI_OUT_OF_RESOURCES;
}
mPrivate->Signature = SAMPLE_PRIVATE_SIGNATURE;
mPrivate->StoredValue = 42; // Default value
mPrivate->SampleProtocol.GetValue = SampleGetValue;
mPrivate->SampleProtocol.SetValue = SampleSetValue;
mSampleHandle = NULL;
Status = gBS->InstallProtocolInterface (
&mSampleHandle,
&gSampleProtocolGuid,
EFI_NATIVE_INTERFACE,
&mPrivate->SampleProtocol
);
if (EFI_ERROR (Status)) {
FreePool (mPrivate);
mPrivate = NULL;
return Status;
}
mPrivate->Handle = mSampleHandle;
DEBUG ((DEBUG_INFO, "SampleDriver: Loaded and protocol installed.\n"));
return EFI_SUCCESS;
}
9.7.3 The Module INF File (SampleDriver.inf)
[Defines]
INF_VERSION = 0x00010017
BASE_NAME = SampleDriver
FILE_GUID = 3E4D7A2C-58B1-4A9F-B0C6-8D2E1F5A3C70
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SampleDriverEntryPoint
UNLOAD_IMAGE = SampleDriverUnload
[Sources]
SampleDriver.c
SampleProtocol.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiBootServicesTableLib
DebugLib
MemoryAllocationLib
UefiLib
[Protocols]
gSampleProtocolGuid ## PRODUCES
[Guids]
[Depex]
TRUE
9.7.4 The GUID Declaration
In your package .dec file, add:
[Protocols]
gSampleProtocolGuid = { 0xa7d54e3c, 0x1b29, 0x4f9e, \
{ 0x8c, 0x4d, 0x6e, 0x2a, 0x7f, 0x3b, 0x1d, 0x80 } }
9.8 Building and Loading the Driver in QEMU
Step 1: Add the driver to your DSC file
[Components]
YourPkg/Drivers/SampleDriver/SampleDriver.inf
Step 2: Build
stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py TOOL_CHAIN_TAG=GCC5
Step 3: Copy the built EFI binary to a virtual FAT disk
cp Build/QemuQ35/DEBUG_GCC5/X64/SampleDriver.efi /path/to/virtual/disk/
Step 4: Load in the UEFI Shell
Shell> load SampleDriver.efi
Image 'FS0:\SampleDriver.efi' loaded at 7E4C6000 - Success
Shell> drivers
Drv Version Bus Image Driver Name
=== ======== ==== ============================== ============================
7F 0x10 SampleDriver.efi Sample UEFI Driver
Step 5: Test with a client application
Write a small UEFI application that locates and exercises the protocol:
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include "SampleProtocol.h"
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SAMPLE_PROTOCOL *Sample;
UINT32 Value;
Status = gBS->LocateProtocol (&gSampleProtocolGuid, NULL, (VOID **)&Sample);
if (EFI_ERROR (Status)) {
Print (L"ERROR: Could not locate SampleProtocol: %r\n", Status);
return Status;
}
Status = Sample->GetValue (Sample, &Value);
Print (L"Current value: %u\n", Value);
Status = Sample->SetValue (Sample, 100);
Print (L"Set value to 100: %r\n", Status);
Status = Sample->GetValue (Sample, &Value);
Print (L"New value: %u\n", Value);
return EFI_SUCCESS;
}
9.9 Driver Categories in Practice
The UEFI specification defines several driver categories based on the bus they manage:
graph TD
A[UEFI Core / DXE Dispatcher] --> B[Bus Drivers]
A --> C[Device Drivers]
A --> D[Service Drivers]
B --> B1[PCI Bus Driver]
B --> B2[USB Bus Driver]
B --> B3[SCSI Bus Driver]
C --> C1[GOP Driver]
C --> C2[NIC Driver]
C --> C3[AHCI / NVMe Driver]
D --> D1[Variable Service Driver]
D --> D2[Timer Arch Driver]
D --> D3[Monotonic Counter Driver]
style A fill:#1a1a2e,stroke:#e94560,color:#fff
style B fill:#16213e,stroke:#0f3460,color:#fff
style C fill:#16213e,stroke:#0f3460,color:#fff
style D fill:#16213e,stroke:#0f3460,color:#fff
| Category | Behavior | Example |
|---|---|---|
| Bus driver | Enumerates child devices, creates child handles | PCI bus driver discovers PCI functions |
| Device driver | Manages a single device, installs I/O protocols | Network driver installs EFI_SIMPLE_NETWORK_PROTOCOL |
| Service driver | Provides a platform service, no device binding | Variable driver provides GetVariable()/SetVariable() |
Bus drivers and child handles
Bus drivers are special because they create child handles. When a PCI bus driver finds a device at Bus 0, Device 2, Function 0, it creates a new handle and installs EFI_PCI_IO_PROTOCOL on it. Device drivers then bind to these child handles.
graph LR
PCI[PCI Root Bridge Handle] -->|PCI Bus Driver Start| CH1[Child Handle\nBus 0 Dev 2 Fn 0]
PCI -->|PCI Bus Driver Start| CH2[Child Handle\nBus 0 Dev 3 Fn 0]
CH1 -->|NIC Driver Start| NIC[EFI_SIMPLE_NETWORK_PROTOCOL]
CH2 -->|GOP Driver Start| GOP[EFI_GRAPHICS_OUTPUT_PROTOCOL]
9.10 Driver Best Practices
-
Keep
Supported()fast. It is called frequently duringConnectController(). Avoid heavy I/O. -
Clean up completely in
Stop(). Every resource allocated inStart()must be freed inStop(). Test by loading, connecting, disconnecting, and unloading repeatedly. -
Use the
CR()macro and signatures. They catch memory corruption early with a clearASSERTrather than a mysterious crash. -
Provide Component Name. It costs little and makes debugging dramatically easier.
-
Set the Version field appropriately. Higher-versioned drivers override lower ones for the same device. Use version
0x10for development and increment for production releases. -
Handle
RemainingDevicePathcorrectly. If it isNULL, start all children. If it points to an end node, start no children but verify the controller. If it points to a specific device path, start only that child. -
Test hot-plug scenarios. If your driver manages a bus that supports hot-plug (USB, Thunderbolt), test repeated connect/disconnect cycles under memory pressure.
9.11 Debugging Driver Issues
Common problems and their symptoms:
| Symptom | Likely Cause |
|---|---|
| Driver loads but no device appears | Supported() returns EFI_UNSUPPORTED for all controllers – check your matching logic |
Start() fails with EFI_ACCESS_DENIED |
Another driver already opened the protocol BY_DRIVER – use dh -v <handle> in the shell to investigate |
| Crash in protocol function | CR() signature mismatch – likely memory corruption or wrong protocol pointer |
Stop() fails with EFI_IN_USE |
A consumer still has the protocol open – all openers must close before uninstall |
Shell drivers shows no name |
Component Name Protocol not installed or language mismatch |
Useful UEFI Shell commands for driver debugging
Shell> drivers # List all loaded drivers
Shell> devices # List all device handles
Shell> devtree # Show device tree hierarchy
Shell> dh -d -v 7F # Detailed dump of handle 0x7F
Shell> connect 7F # Connect driver 0x7F to all devices
Shell> disconnect 7F # Disconnect driver 0x7F from all devices
Shell> unload 7F # Unload driver image 0x7F
Shell> reconnect -r # Reconnect all drivers to all devices
Complete source code: The full working example for this chapter is available at
examples/UefiMuGuidePkg/DriverExample/.
Summary
The UEFI driver model provides a clean, protocol-based architecture for managing hardware and services. The Driver Binding Protocol’s three-function pattern – Supported(), Start(), Stop() – enforces a disciplined approach to device discovery and lifecycle management. Combined with Component Name and Driver Diagnostics, this model produces drivers that are discoverable, testable, and hot-plug capable.
In the next chapter, we will explore the protocol and handle database in depth – the foundation upon which this entire driver model rests.
Hands-on exercise: Modify the SampleDriver to accept a string value instead of a
UINT32. Add aGetString()/SetString()pair to the protocol, allocate storage dynamically, and ensureStop()frees the string memory. This exercise reinforces the private data pattern and memory lifecycle management.