Протокол - основний спосіб взаємодії коду з середовищем, у якому він виконується.
Стандарт UEFI задає близько 70 різних протоколів, починаючи від EFI Loaded Image Protocol, який надає доступ до інформації про запущену програму, і аж до EFI UDP4 Protocol.
Тут я опишу низку протоколів, з якими нам випала можливість стикнутися, але спершу напевно варто почати з спільної штуки для них усіх — спосіб отримання, який є спільним для усіх.
Перш за все, кожен протокол має пов’язаний із собою “пристрій”, який реалізовує функціонал цього протоколу, так EFI_BLOCK_IO_PROTOCOL пов’язаний із блочним пристрроєм, власне з якого і відбувається читання та у який відбувається запис. Кожен такий “пристрі” амє свій власний хендл. Один хендл може підтримувати одразу декілька, так партиція на диску з файловою системою з сімейства FAT підтримує одразу і EFI_BLOCK_IO_PROTOCOL і EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.
Оскільки більшість протоколів надають якийсь функціонал, хтось має реалізовувати його. Саме це і є однією з основних функцією драйверів, причому реалізацію протоколів вони можуть прив’язувати як до вже існуючих хендлів, так і створювати нові, які фактично не відповідають жодному фізичному пристрою, так наприклад, EFI_UNICODE_COLLATION_PROTOCOL надає інтерфейс для операцій порівняння стрічок.
Основним способом доступу до інтерфейсів є функція HandleProtocol:
typedef
EFI_STATUS
(EFIAPI *EFI_HANDLE_PROTOCOL) (
IN EFI_HANDLE Handle,
IN EFI_GUID *Protocol,
OUT VOID **Interface
);
Дана функція надається у BootServices, разом з рядом інших функцій. Результатом виконяння функції буде вказівник на інтерфейс протоколу (вказівник на який передається третім аргументом у функцію), який був заданий за допомогою свого унікального ідентифікатора. Якщо ж з переданий хендл не релізовує запитаний протокол, функцію поверне помилку.
Використання такої функції може бути не дуже зручним, оскільки для використання потрібно мати хендл, на якому варто шукати бажаний протокол, що не завжди є можливим. Для цього у BootServices існують функції LocateHandleBuffer, яка знаходить усі хенли відповідно до запиту та LocateProtocol, яка знаходить перший екземпляр протоколу серед усіх хендлів. Так друга функція може допомогти у знаходженні EFI_UNICODE_COLLATION_PROTOCOL, оскільки нам не дуже важливи хто реалізовує функціонал цього протоколу, а от для знаходження EFI_SIMPLE_FILE_SYSTEM_PROTOCOL використання цієї функції сумнівне, оскільки на пристрої може міститися декілька сумісних файлових систем, і яку з них буде повернуто — діло випадку.
Багато функцій у різних протоколах мають повернути якісь значення у буфер за своєю логікою. Так функція GetInfo з EFI_FILE_PROTOCOL повертає запитану інформацію про файл, записуючи її у переданий буфер. Необхідний розмір буфера для виділення пам’яті наперед дізнатися інколи буває важко, оскількки деяка інформація містить до прикладу сстрічки з шляхом / назвою файла. Для подолання цієї проблеми, функції за недостатнього розміру буфера, повертають у передану зміну розмір, необхідний щоб вмістити запитувану інформацію.
Більше інфоррмації про ці та багато іншох протоколів можна знайту у специфікаціях UEFI:
і так, вона займає 2000 сторінок…