Protocol trong UEFI là gì?
Protocol là interface install lên handle trong DXE, cho phép driver giao tiếp không phụ thuộc implementation. Hiểu Protocol giúp debug driver binding và locate fail.
Trong UEFI, Protocol là một interface được install lên handle trong handle database. Driver hoặc application khác locate protocol đó theo GUID để sử dụng service - mà không cần biết implementation bên dưới là gì.
Protocol trong DXE đóng vai trò tương tự PPI trong PEI: giúp các module tìm nhau và gọi service qua interface chuẩn, nhưng Protocol gắn với handle database và Boot Services.
Cấu trúc một Protocol
Mỗi Protocol gồm hai thứ: một GUID để định danh và một struct chứa function pointers.
// Simplified - xem Protocol/BlockIo.h để có đầy đủ function pointer typedefs
typedef struct _EFI_BLOCK_IO_PROTOCOL {
UINT64 Revision;
EFI_BLOCK_IO_MEDIA *Media;
EFI_BLOCK_RESET Reset;
EFI_BLOCK_READ ReadBlocks;
EFI_BLOCK_WRITE WriteBlocks;
EFI_BLOCK_FLUSH FlushBlocks;
} EFI_BLOCK_IO_PROTOCOL;
// GUID định danh protocol này
extern EFI_GUID gEfiBlockIoProtocolGuid;
Driver install struct này lên handle. Consumer locate theo GUID rồi gọi function qua pointer - không cần biết driver nào đứng sau.
Install Protocol
InstallProtocolInterface - install một protocol lên handle:
// Tạo handle mới và install protocol lên đó
EFI_HANDLE Handle = NULL;
Status = gBS->InstallProtocolInterface(
&Handle, // NULL → tạo handle mới
&gEfiBlockIoProtocolGuid,
EFI_NATIVE_INTERFACE,
&mBlockIoProtocol // con trỏ đến implementation
);
InstallMultipleProtocolInterfaces - install nhiều protocol lên cùng một handle, thường dùng hơn vì code gọn và firmware có thể xử lý cleanup tốt hơn nếu một bước install fail:
Status = gBS->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiBlockIoProtocolGuid, &mBlockIoProtocol,
&gEfiDevicePathProtocolGuid, &mDevicePath,
NULL // terminate
);
Dùng InstallMultipleProtocolInterfaces khi install nhiều protocol lên cùng một handle để code gọn hơn và để firmware xử lý cleanup tốt hơn nếu một bước install fail.
Ba cách lookup Protocol
Đây là điểm người mới hay nhầm nhất - có ba API lookup với mục đích khác nhau:
| Mục | Giá trị | Ghi chú |
|---|---|---|
| LocateProtocol() | Tìm protocol đầu tiên trong toàn database | Không quan tâm handle nào. Dùng cho global service hoặc protocol chỉ kỳ vọng có một instance, ví dụ ConIn, ConOut. |
| HandleProtocol() | Lấy protocol từ handle cụ thể | Wrapper đơn giản của OpenProtocol. Không track ai đang dùng - dùng hạn chế. |
| OpenProtocol() | Mở protocol với attribute rõ ràng | Đúng cách cho driver. Track open count, hỗ trợ EFI_OPEN_PROTOCOL_BY_DRIVER để disconnect hoạt động đúng. |
LocateProtocol - tìm nhanh không cần biết handle:
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
Status = gBS->LocateProtocol(
&gEfiSimpleTextOutProtocolGuid,
NULL,
(VOID **)&ConOut
);
OpenProtocol - cách đúng cho driver, có attribute tracking:
EFI_PCI_IO_PROTOCOL *PciIo;
Status = gBS->OpenProtocol(
ControllerHandle,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo,
This->DriverBindingHandle, // ai đang mở
ChildHandle, // child handle liên quan
EFI_OPEN_PROTOCOL_BY_DRIVER // attribute
);
EFI_OPEN_PROTOCOL_BY_DRIVER báo cho firmware biết driver đang giữ protocol này - khi Stop() được gọi, firmware biết driver nào cần cleanup.
Notify khi Protocol mới xuất hiện
Tương tự NotifyPpi trong PEI, DXE có RegisterProtocolNotify:
EFI_EVENT Event;
VOID *Registration; // token để dùng với LocateHandle(ByRegisterNotify, ...)
// Đăng ký callback - sẽ tự chạy khi gEfiDiskIoProtocolGuid được install
Status = gBS->CreateEvent(
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
MyDiskIoNotify, // callback function
NULL,
&Event
);
gBS->RegisterProtocolNotify(
&gEfiDiskIoProtocolGuid,
Event,
&Registration
);
Hữu ích khi driver cần react với protocol mới xuất hiện mà không biết trước thứ tự dispatch - ví dụ file system driver chờ Disk I/O Protocol. Khi không cần notify nữa, nhớ gọi gBS->CloseEvent(Event) để tránh leak.
RegisterProtocolNotify() chỉ signal event khi protocol được install. Trong callback, driver thường phải dùng LocateHandle(ByRegisterNotify, ...) với Registration để lấy các handle mới liên quan - callback không tự nhận protocol pointer.
Architectural Protocols
Một số Protocol đặc biệt gọi là Architectural Protocol - đây là các protocol nền tảng mà DXE Core hoặc các phase sau như BDS cần dựa vào để hệ thống tiếp tục boot. Nhiều architectural protocol được cung cấp bởi DXE driver chuyên trách. Nếu một protocol bắt buộc không xuất hiện, DXE/BDS có thể dừng hoặc không thể chuyển sang bước tiếp theo.
| Mục | Giá trị | Ghi chú |
|---|---|---|
| EFI_CPU_ARCH_PROTOCOL | CPU abstraction | Interrupt enable/disable, flush cache, memory attributes. |
| EFI_TIMER_ARCH_PROTOCOL | Hardware timer | Dùng cho event-based timing trong DXE. |
| EFI_BDS_ARCH_PROTOCOL | Boot Device Selection | DXE Core gọi BDS qua protocol này khi dispatch xong. |
| EFI_SECURITY_ARCH_PROTOCOL | Security policy | Authenticate image trước khi load. Liên quan Secure Boot. |
| EFI_RUNTIME_ARCH_PROTOCOL | Runtime service registration | Quản lý virtual address mapping cho runtime driver. |
Khi debug DXE Core không tiến được, kiểm tra xem các Architectural Protocol này có được install đầy đủ không.
Một ví dụ thực tế: protocol chain của storage
ControllerHandle (PCI device)
├─ EFI_PCI_IO_PROTOCOL ← PCI bus driver install
└─ EFI_DEVICE_PATH_PROTOCOL
ChildHandle (NVMe controller)
├─ EFI_NVM_EXPRESS_PASS_THRU ← NVMe driver install
├─ EFI_BLOCK_IO_PROTOCOL
└─ EFI_DEVICE_PATH_PROTOCOL
ChildHandle (Partition)
├─ EFI_BLOCK_IO_PROTOCOL ← Partition driver install
├─ EFI_DISK_IO_PROTOCOL
└─ EFI_DEVICE_PATH_PROTOCOL
ChildHandle (Volume)
├─ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL ← FAT driver install
└─ EFI_DEVICE_PATH_PROTOCOL
BDS cần EFI_SIMPLE_FILE_SYSTEM_PROTOCOL để mở file .efi. Nếu bất kỳ mắt xích nào ở trên thiếu, chain sẽ bị đứt và boot menu sẽ không thấy device đó.
Checklist khi debug Protocol
Lỗi hiểu nhầm hay gặp
Protocol không phải global singleton. Nhiều driver có thể install cùng một GUID lên các handle khác nhau. LocateProtocol chỉ trả về cái đầu tiên tìm thấy. Nếu cần protocol của một device cụ thể, phải tìm theo handle.
HandleProtocol và OpenProtocol không giống nhau. HandleProtocol là legacy wrapper, không track open count - dùng trong driver sẽ làm disconnect/reconnect hoạt động sai.
Protocol và PPI không interchangeable. Protocol thuộc DXE, PPI thuộc PEI. Không thể locate Protocol bằng PEI service và ngược lại.
Câu hỏi tự kiểm tra
- Protocol trong UEFI gồm GUID và interface struct để làm gì?
- Protocol được install lên đâu trong handle database?
LocateProtocol()khácOpenProtocol()ở điểm nào?- Vì sao driver model nên dùng
OpenProtocol()thay vìHandleProtocol()? InstallMultipleProtocolInterfaces()hữu ích khi nào?- Vì sao một GUID protocol có thể xuất hiện trên nhiều handle khác nhau?
- Storage protocol chain cần những protocol nào để BDS thấy boot device?
RegisterProtocolNotify()signal event xong, driver thường cần làm gì tiếp?
Bài liên quan
- Handle Database là gì?
- GUID là gì?
- DXE là gì?
- UEFI Driver Model là gì?
- Driver Binding Flow là gì?
- PPI là gì?
Nguồn tham khảo public
- UEFI Specification 2.11 - Protocol Interface Services
- EDK II MdePkg - UefiBootServicesTableLib.h
- EDK II MdePkg - Protocol/BlockIo.h
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.
DXE là gì trong UEFI?
DXE là phase firmware sau PEI, nơi driver được dispatch, protocol được install và Boot Services trở nên đầy đủ. DXE xây dựng môi trường để BDS có thể chọn và khởi động OS.
Handle Database trong UEFI là gì?
Handle Database là nơi DXE quản lý quan hệ giữa handle và protocol, giúp debug driver binding, locate fail và boot device chain.
Driver Binding Flow là gì?
Giải thích Supported, Start, Stop trong UEFI Driver Model và cách nó ảnh hưởng quá trình enumerate thiết bị.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.