UEFI Device Driver là gì?
UEFI Device Driver bind vào child handle do bus driver tạo, install abstraction protocol. Hiểu protocol chain đến boot menu và lỗi khi device có handle nhưng không lên boot option.
UEFI Device Driver bind vào controller/child handle và install abstraction protocol - giao diện mà các tầng cao hơn (BDS, partition driver, filesystem driver) dùng để truy cập device mà không cần biết chi tiết hardware.
Điểm khác với bus driver: một device driver thuần thường không tạo child handle - nó manage một handle cụ thể và publish protocol lên đó. Trong cách phân loại nghiêm ngặt, driver nào tạo child handle thì đang thực hiện vai trò bus driver cho tầng con đó. Tuy nhiên có những driver mang tính hybrid/bus-like: chúng bind vào một controller vật lý nhưng bên trong có nhiều logical unit (NVMe namespace, SCSI LUN), nên driver sẽ tạo child handle cho từng logical unit.
Device driver nhận handle từ đâu
Device driver không bind vào raw hardware - nó bind vào child handle đã được bus driver tạo. Đây là thứ tự thực tế:
1. Platform firmware publish hardware resource (Root Bridge, Memory Map)
2. Bus driver (PCI Bus Driver) bind vào Root Bridge
→ Tạo child handle cho mỗi PCI device
→ Install EFI_PCI_IO_PROTOCOL + Device Path lên child handle
3. Device driver bind vào child handle
→ Đọc PCI IO để kiểm tra Vendor/Device ID trong Supported()
→ Trong Start(): init hardware, install abstraction protocol
↓
4. Abstraction protocol được publish
→ Partition driver, filesystem driver, BDS tiếp tục từ đây
Nếu bước 2 chưa xong, Supported() của device driver sẽ fail ngay từ đầu vì protocol cần thiết chưa có trên handle.
Protocol device driver thường install
| Mục | Giá trị | Ghi chú |
|---|---|---|
| EFI_BLOCK_IO_PROTOCOL | Storage device | NVMe, SATA, USB Mass Storage driver install Block I/O. Partition driver bind vào đây để tạo partition handle. |
| EFI_BLOCK_IO2_PROTOCOL | Storage device (async) | Version async của Block I/O, hỗ trợ non-blocking I/O. Thường đi kèm Block I/O. |
| EFI_SIMPLE_NETWORK_PROTOCOL | Network interface | NIC driver install. PXE và network boot stack dùng để gửi/nhận packet. |
| EFI_GRAPHICS_OUTPUT_PROTOCOL | Display | GOP driver install. BDS và UEFI Shell dùng để output text/graphics. |
| EFI_SERIAL_IO_PROTOCOL | Serial port | UART driver install. Console redirect và debug output dùng đây. |
| EFI_DISK_IO_PROTOCOL | Block device abstraction | Filesystem driver có thể dùng Disk I/O hoặc Block I/O tùy implementation/layer. |
Protocol chain đến boot menu
Device driver publish protocol, nhưng để device lên boot menu, cần toàn bộ chain đầy đủ:
NVMe Controller Handle (từ PCI Bus Driver)
└─ EFI_PCI_IO_PROTOCOL
└─ Device Path: PciRoot(0)/Pci(0x1D,0x0)
NVMe Driver bind vào → tạo Namespace Handle
└─ EFI_BLOCK_IO_PROTOCOL
└─ EFI_DEVICE_PATH_PROTOCOL: .../NVMe(1,...)
Partition Driver bind vào Namespace Handle → tạo Partition Handle
└─ EFI_BLOCK_IO_PROTOCOL (partition)
└─ EFI_DEVICE_PATH_PROTOCOL: .../HD(1,GPT,...)
└─ EFI_DISK_IO_PROTOCOL (tùy driver stack/platform)
FAT Driver bind vào Partition Handle
└─ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL ← BDS cần để LoadImage
└─ EFI_DEVICE_PATH_PROTOCOL: .../HD(1,GPT,...) ← Device Path của partition handle
← (không có File() node ở đây)
Boot#### / LoadImage File Path
└─ .../HD(1,GPT,...)/File(\EFI\BOOT\BOOTX64.EFI) ← File() node nằm trong boot option
Hybrid/bus-like driver - NVMe namespace là ví dụ
NVMe driver là ví dụ driver hybrid/bus-like: bind vào PCI NVMe controller nhưng tạo child handle cho từng namespace:
// NVMe driver Start() flow
// 1. Bind vào PCI controller handle
gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, ..., BY_DRIVER);
// 2. Init NVMe controller hardware
// 3. Enumerate namespace - mỗi namespace là một logical unit
for (UINTN i = 0; i < NamespaceCount; i++) {
EFI_HANDLE NamespaceHandle = NULL;
// Tạo child handle cho namespace
gBS->InstallProtocolInterface(
&NamespaceHandle,
&gEfiBlockIoProtocolGuid,
EFI_NATIVE_INTERFACE,
&NamespaceCtx[i].BlockIo
);
// Install Device Path: parent path + NVMe namespace node
gBS->InstallProtocolInterface(
&NamespaceHandle,
&gEfiDevicePathProtocolGuid,
EFI_NATIVE_INTERFACE,
NamespaceDevicePath[i]
);
// Link parent-child relationship
gBS->OpenProtocol(
ControllerHandle,
&gEfiPciIoProtocolGuid,
...,
This->DriverBindingHandle,
NamespaceHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
}
Đây là lý do bios/uefi-driver-model.mdx không thể nói cứng “device driver không tạo child handle” - nó phụ thuộc loại device.
Failure pattern - device driver bind nhưng không có effect
Block I/O có nhưng không có partition handle:
Shell> devtree # Không thấy child handle của namespace/disk handle
# → Partition table corrupt, partition type không được nhận, hoặc PartitionDxe chưa bind
Partition handle có nhưng không có Simple File System:
Shell> dh -p EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
# Không thấy handle nào từ partition đó
# → FAT/filesystem driver chưa bind
# → Partition không phải filesystem firmware hỗ trợ
# → ESP không đúng format hoặc filesystem lỗi
Device driver bind nhưng install sai protocol:
- Install protocol lên sai handle (ControllerHandle thay vì NamespaceHandle)
- Install protocol không đầy đủ - thiếu Device Path trên child handle
- BDS không thể resolve Device Path → boot option không được tạo
Supported() pass nhưng Start() fail im lặng:
Shell> dh -v <pci_handle>
# Không thấy BY_DRIVER open từ device driver → Start() fail
Shell> drivers
# Driver có trong list nhưng "I" (Images) không có Controller
# → Supported() pass nhưng Start() trả lỗi ngay
NVMe / SATA không lên boot menu dù detect được:
- Controller bind OK, namespace handle tạo OK
- Partition table corrupt → partition driver fail → không có Simple File System
- GPT partition signature mismatch với Boot#### Device Path
Trace khi device driver có vấn đề
# Bước 1: Driver có bind không?
Shell> drivers
# Xem cột controller/handle managed (tùy Shell version) - nếu = 0 thì Supported() fail hoặc không được gọi
# Bước 2: Protocol chain từ controller handle
Shell> devtree # cây controller → namespace → partition
Shell> dh -v <handle> # protocol list của từng handle
# Bước 3: Protocol chain đến Simple File System
Shell> dh -p EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
# Không thấy handle nào → chain bị đứt ở đâu đó
# Bước 4: Xác định đứt ở đâu bằng devtree + dh -v
Shell> devtree # có partition child handle không?
# Nếu disk/namespace Block I/O có nhưng không có partition child handle
# → partition layer fail (PartitionDxe, partition table)
Shell> dh -v <partition_handle> # có SFSP không?
# Nếu partition handle có nhưng không có SFSP
# → FAT/filesystem driver chưa bind
# EDK II trace - device driver Start()
grep -r "InstallProtocolInterface\|EFI_BLOCK_IO_PROTOCOL" \
edk2/MdeModulePkg/Bus/Nvme/NvmExpressDxe/ --include="*.c" | head -10
Checklist Device Driver
Câu hỏi tự kiểm tra
- Device driver khác bus driver ở điểm nào về việc tạo child handle?
- Tại sao device có Block I/O nhưng vẫn không lên boot menu?
- NVMe driver tạo child handle vì lý do gì - khác với driver thông thường thế nào?
- Nếu
dh -p EFI_SIMPLE_FILE_SYSTEM_PROTOCOLkhông thấy handle nào, bước trace tiếp theo là gì? - Protocol cần thiết để BDS tạo boot option cho một storage device là gì?
Bài liên quan
- UEFI Bus Driver là gì?
- Start() trong UEFI Driver Model là gì?
- Stop() trong UEFI Driver Model là gì?
- BDS là gì?
- Boot####, BootOrder và BootNext là gì?
Nguồn tham khảo public
- UEFI Specification 2.11 - Device Driver
- EDK II - NvmExpressDxe
- EDK II UEFI Driver Writer’s Guide - Device Driver
Thấy nội dung này hữu ích?
Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
Start() trong UEFI Driver Model là gì?
Start() là nơi driver bind vào controller: open BY_DRIVER, install protocol, tạo child handle nếu là bus driver. Hiểu cleanup fail path và anti-pattern làm handle database bẩn.
Stop() trong UEFI Driver Model là gì?
Stop() là cleanup đối xứng của Start(). Hiểu CloseProtocol, uninstall protocol, NumberOfChildren, destroy child handle và anti-pattern làm DisconnectController fail.
UEFI Bus Driver là gì?
UEFI Bus Driver enumerate child device và tạo child handle với Device Path. Hiểu chuỗi protocol từ bus đến boot option và lỗi khi child handle thiếu hoặc Device Path sai.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.