Внутренняя кухня UEFI: что это такое и как мы готовим его в YADRO
- четверг, 13 марта 2025 г. в 00:00:16
Привет, Хабр. На связи Сергей Пушкарёв, я руковожу отделом разработки BIOS в YADRO. Расскажу об устройстве UEFI и его применении в компании. Мы разрабатываем и выпускаем разные аппаратные платформы: серверы, системы хранения данных, клиентское и телеком-оборудование.
Один из «кирпичиков», который обеспечивает инициализацию и функционирование оборудования, — это BIOS. В статье кратко разберем историю этой системы и ее современную реализацию — UEFI. Также поговорим о подходе к разработке и отладке этого ПО в YADRO. Вы узнаете, зачем нам нужна «синяя коробка» Intel, как мы прошиваем BIOS и проводим диагностику «в полях».
BIOS — это системное программное обеспечение, которое встроено прямо в материнскую плату и хранится в энергонезависимой памяти: как правило, это SPI Flash. Даже если на материнской плате нет жесткого диска или другого накопителя данных, BIOS уже присутствует. Сейчас BIOS правильнее называть UEFI, но по инерции многие продолжают называть эту систему BIOS.
В начале 80-х годов компания IBM разработала для своих компьютеров микропрограмму, которая обеспечивала инициализацию оборудования. Также она предоставляла базовые сервисы для операционной системы того времени — DOS.
Примеры таких сервисов: работа с клавиатурой, дисками и выводом изображения на экран. Эта система получила название BIOS, то есть базовая система ввода-вывода. Это была закрытая проприетарная разработка, но со временем появились клоны IBM PC. И поскольку компания IBM запатентовала только конкретную реализацию BIOS, но не программные интерфейсы, то конкуренты начали копировать эту технологию, и она стала стандартом де-факто в мире настольных компьютеров.
Первые PC были системами с 16-битной адресацией и реальным режимом работы, они поддерживали максимум один мегабайт памяти, адресуемой посегментно. Использовать язык высокого уровня для написания ПО первичной инициализации таких систем было неэффективно, а порой и невозможно, поэтому для разработки BIOS использовали максимально низкоуровневый язык программирования — ассемблер.
В середине 90-х годов компания Intel начала разрабатывать процессоры с архитектурой Itanium. Анализируя BIOS, инженеры поняли, что его возможностей недостаточно для инициализации сложных систем с большим объемом памяти и 64-битными процессорами. В результате была разработана новая спецификация программной инициализации под названием EFI.
В 2005 году Intel передала спецификацию и реализацию консорциуму UEFI Forum — некоммерческой организации, в которую входят Intel, IBM, Microsoft и другие компании. После этого EFI получил название Unified EFI (UEFI). Основной задачей UEFI Forum стала разработка спецификации UEFI и продвижение этой системы «в массы» для постепенной замены BIOS.
На скриншоте — результат эволюции BIOS. Именно с этой системой мы работаем сейчас. UEFI может работать не только на процессорной архитектуре x86, но и на ARM, RISC-V, LoongArch и других.
Рассмотрим преимущества UEFI. Прежде всего, это наличие спецификации. Существует четкая спецификация на интерфейсы, которые прошивка предоставляет внешним сущностям. Например, загрузчику операционной системы.
Прошивка может взаимодействовать с загрузчиками операционных систем, самими операционными системами или программами, которые занимаются инициализацией оборудования. Например, если вы вставляете PCIe-видеокарту, то при работе UEFI запускается специальный драйвер UEFI Option ROM, который инициализирует эту видеокарту и предоставляет сервисы для вывода изображения. Все — от формата Option ROM и до программного интерфейса вывода изображения — стандартизовано спецификацией.
Спецификация есть как на внешние, так и на внутренние интерфейсы — последняя называется PI Specification. Она регламентирует, как прошивка должна быть устроена и как хранит данные. Поэтому фрагментация между прошивками минимальна. Например, если вы сравните прошивки, разработанные разными компаниями, такими как AMI или Insyde, они будут устроены очень похоже. Прошивки YADRO также следуют этому подходу.
В написании прошивок много нюансов. Это интересная, но непростая работа. И мы ищем неравнодушных коллег в команду. Сейчас открыты такие вакансии:
→ Старший/ ведущий разработчик на C++ (Linux/OpenBMC)
Существует также спецификация ACPI, которая определяет, как операционная система управляет энергосбережением и обнаруживает оборудование. Хотя ACPI изначально не была связана с UEFI, в итоге спецификацию передали под управление UEFI Forum. Теперь ее развитие происходит в рамках этого консорциума.
Еще одним элементом UEFI является встроенный командный интерпретатор. Это приложение может быть встроено в прошивку или запущено с внешнего носителя, например с флешки. Оно похоже на командную оболочку DOS.
Одно из ключевых преимуществ UEFI — наличие референсной реализации, известной как Tianocore EDK2. Этот проект, размещенный на GitHub, представляет собой одновременно и референсную имплементацию спецификации UEFI, и пакет разработчика UEFI.
В проекте содержится множество драйверов и описание программных интерфейсов, что делает его отличной базой для разработки отдельных приложений, драйверов или даже полной прошивки. Tianocore EDK2 также предлагает кроссплатформенную сборку проектов с помощью удобных абстракций.
Безопасность — еще одно важное преимущество UEFI. Во времена BIOS вопросы безопасности практически не рассматривались. При передаче управления загрузчику операционной системы не было уверенности, что это действительно легитимная ОС, а не вредоносный код.
UEFI решает эту проблему с помощью технологии Secure Boot, которая проверяет цифровую подпись загрузчика или других программ, таких как Option ROM на PCIe-адаптерах. Для этого в прошивке хранятся сертификаты или открытые ключи, а файлы подписываются закрытым ключом. Перед передачей управления UEFI проверяет подпись файла. Это позволяет гибко управлять безопасностью системы: например, можно подписать загрузчик Linux своим ключом для более полного контроля над платформой. А прошивка предоставит интерфейс, чтобы сохранить внутри себя открытую часть ключа.
Аспект безопасности очень важен, поскольку в теории злоумышленники могут подменить Option ROM видеокарты или другого устройства вредоносным кодом, который будет исполняться независимо от операционной системы. Такой зловред невозможно удалить, даже переустановив ОС, так как он находится на внешнем устройстве.
Еще одно преимущество UEFI — HII. Эта архитектура предназначена для создания пользовательских интерфейсов. UEFI поддерживает юникод «из коробки» благодаря использованию стандарта UCS-2, где каждый символ фиксированного размера занимает 2 байта. Это обеспечивает поддержку мультиязычности.
Строки интерфейса хранятся в отдельных файлах, что упрощает локализацию и позволяет ее автоматизировать.
Кроме того, HII использует меню, основанное на байт-коде. Это позволяет разработчикам не задумываться о том, как нарисовать элементы интерфейса. Они просто описывают функционал кнопки, а система сборки преобразует это описание в байт-код, который исполняется во время работы прошивки.
Вендоры, которые разрабатывают Option ROM для PCIe-устройств, также могут создавать свои меню. Их легко интегрировать в BIOS, и меню не будетт выглядеть чужеродно. Такой подход позволяет создавать универсально выглядящие интерфейсы для настройки, например RAID-контроллеров или других устройств, без необходимости вручную прорабатывать их визуальную составляющую.
GPT — это способ разбить диск на логические разделы. Во времена BIOS использовалась разметка MBR, которую разработала IBM. Эта разметка стала стандартом де-факто, но с развитием компьютерной техники производители столкнулись с несколькими ограничениями MBR:
Первое — нельзя использовать больше четырех логических разделов, хотя это и можно было обойти с помощью «костылей» в виде «вторичных» разделов.
Второе, более фундаментальное ограничение, — MBR не умеет работать с дисками объемом более 2 ТБ. Разметка GPT, которая пришла вместе с UEFI, сняла это ограничение и позволила использовать диски объемом до 18 эксабайт со 128 разделами.
Исходя из этого можно выделить еще одно преимущество UEFI — модульность. Прошивка состоит из множества исполняемых файлов, запуск которых можно гибко настроить. Во время сборки при помощи так называемых DEPEX-выражений можно задать условия, при которых конкретный драйвер будет запускаться только после выполнения определенных задач.
Поскольку UEFI написан в основном на языке C, то его легко портировать. Отдельные драйверы можно адаптировать для работы на различных процессорных архитектурах: x86, ARM, RISC-V и других.
Она строится на последовательности стадий, каждая из которых выполняет свою часть работы, записывает результаты и передает управление следующей стадии. Каждая последующая стадия использует информацию, полученную на предыдущей, — вплоть до стадии Runtime, на которой уже загружена и работает операционная система. Затем большая часть сервисов BIOS завершает работу, хотя некоторая их часть продолжает функционировать на протяжении всей работы системы.
Для наглядности рассмотрим эти стадии на примере загрузки BIOS на процессорах Intel.
Первая стадия — SEC. Код BIOS хранится в энергонезависимой памяти на материнской плате, и его выполнение начинается прямо оттуда. На этом этапе система стартует в реальном режиме, как это было в 80-х годах. Однако, в отличие от старого BIOS, в UEFI практически сразу выполняется переход в 32-битный защищенный режим. Но на этом этапе оборудование еще не инициализировано: ни памяти, ни других ресурсов нет. Мы не можем использовать стек, поэтому эта стадия все еще пишется на ассемблере.
Для исправления этой ситуации используется специальный режим Cache-As-RAM, который позволяет использовать кеш процессора как временную оперативную память. Обычно кеш недоступен для прямой работы, но в этом режиме часть кеша выделяется под стек и под кучу (heap), что делает возможным работу с памятью на языке C.
Следующий шаг — поиск специального файла PEI Core, который является диспетчером стадии PEI. Эта стадия занимается базовой инициализацией оборудования, которая нужна для полноценной работы прошивки.
В начале стадии PEI-драйверы выполняются прямо с микросхемы SPI Flash, установленной на материнской плате. Так экономится память, которая на этом этапе очень ограничена — не забываем про Cache-As-RAM. Код на SPI Flash отображается на физические адреса, и к нему можно обращаться так, как если бы он находился в оперативной памяти.
Механизм XIP позволяет выполнять код прямо с SPI Flash, но с важным ограничением: в код нельзя записывать данные. Драйвер можно написать на языке C, но глобальные данные, объявленные в коде, остаются неизменяемыми. Если попытаться записывать такие данные, то ничего не произойдет, так как весь код доступен только для чтения. Нужно учитывать этот нюанс при разработке драйверов стадии PEI.
Основная задача этой стадии на процессорах Intel — инициализация оперативной памяти. Это сложный процесс, он требует больших объемов закрытого кода, из-за чего его практически невозможно реализовать самостоятельно, даже если у вас есть все необходимые спецификации.
После инициализации памяти сохраняется информация о конфигурации системы, например о типе и расположении планок памяти.
Переходим на следующую стадию — DXE. На этом этапе выполняется переход в 64-битный защищенный режим, а управление передается диспетчеру DXE, который называется DXE Core.
DXE — это фаза, на которой выполняется большая часть работы по инициализации оборудования.
Отмечу важную деталь, которая связана с архитектурой x86. В ней существует специальный режим работы процессора: SMM. Это наиболее привилегированный режим, который может функционировать даже во время работы операционной системы. В UEFI используются специальные SMM-драйверы, которые копируются в отдельную область памяти (SMRAM) и исполняются там. Инициализация режима SMM происходит именно на стадии DXE.
Во время стадии DXE выполняются ключевые задачи, такие как PCIe Enumeration — процесс, во время которого выделяются ресурсы для всех PCIe-устройств и резервируются ресурсы для Hotplug. Только после этого устройства становятся полностью доступными для работы.
Драйверы стадии DXE предоставляют программные интерфейсы, которые в терминологии UEFI называются протоколами. Протокол представляет собой идентификатор интерфейса и таблицу функций, которые можно вызывать.
Когда все драйверы на стадии DXE завершили работу, происходит переход к фазе BDS, и пользователь может войти в меню BIOS. Если пользователь не совершает никаких действий, происходит автоматическая загрузка с одного из доступных носителей или по сети.
Особенность UEFI — обязательная поддержка файловой системы FAT32. Для загрузки с диска или флешки в UEFI на носителе должен быть раздел FAT32 с загрузчиком. Он представляет собой исполняемый файл, аналогичный тем, которые находятся в самой прошивке.
После запуска загрузчик выполняет свою работу, загружает операционную систему, и она переходит в фазу Runtime. На этом этапе большая часть прошивки завершает работу, но остаются специальные драйверы, которые продолжают функционировать вместе с операционной системой.
Эти драйверы предоставляют рантайм-сервисы, которые описаны в спецификации UEFI. Они выполняют роль моста между операционной системой и прошивкой. Хотя таких сервисов немного, они обеспечивают важные функции:
Чтение и запись настроек прошивки, а также создание загрузочных записей. Например, при установке Windows появляется загрузочная запись вида «Windows Boot Manager», которая создается установщиком операционной системы.
ResetSystem — функция для выключения или перезагрузки системы.
Функции для работы с системным временем, такие как GetTime и SetTime. Они позволяют устанавливать или получать системное время без прямого обращения к RTC. Работа с RTC выполняется драйверами прошивки, а не операционной системой.
ACPI — это технология для управления энергосбережением и обнаружения оборудования. Она состоит из набора аппаратных регистров и таблиц, которые создаются прошивкой и используются операционной системой. Эти таблицы написаны на специальном языке ASL и исполняются интерпретатором, встроенным в операционную систему.
Прошивка создает таблицы, а операционная система их использует. Например, для обнаружения оборудования существует таблица, в которой описано количество процессорных ядер и их распределение. Если загрузить ядро Linux с параметром acpi=off и при этом в прошивке не реализованы альтернативные методы обнаружения оборудования (например, нет поддержки режима CSM), то система покажет только одно процессорное ядро, даже если CPU многоядерный.
Вернемся к режиму SMM. Его преимущества особенно заметны в серверных продуктах благодаря технологии RAS. Это набор обработчиков ошибок оборудования. В SMM работают драйверы, которые реагируют на прерывания, так как доступ в режим SMM возможен только через SMI. Из обычного кода, в том числе из кода ядра ОС, напрямую попасть в SMM нельзя.
Например, работающий сервер выдает ошибку памяти. Если система настроена правильно, то оборудование генерирует SMI, которое переводит процессор в режим SMM. В нем запускается соответствующий обработчик, который предпринимает действия для устранения или учета ошибки.
Режим SMM также абстрагирует доступ к оборудованию, обеспечивая дополнительную безопасность. Например, при инициализации оборудования BIOS может настроить поведение системы так, что запись в определенный порт ввода-вывода вызывает прерывание SMI. В зависимости от записанных данных вызывается соответствующий обработчик.
В наших прошивках запись настроек на SPI Flash доступна только из режима SMM. Runtime-драйверы предоставляют интерфейсы, такие как GetVariable и SetVariable. Операционная система вызывает функцию SetVariable, Runtime-драйвер подготавливает данные и пишет в определенный порт ввода-вывода, что приводит к генерации SMI. Процессор переходит в режим SMM, и в соответствующем обработчике данные уже записываются на SPI Flash.
UEFI обладает рядом архитектурных особенностей. Код в основном однопоточный и выполняется на BSP. Это не отдельный процессор, а просто одно из ядер, которое назначается для выполнения кода.
Хотя функции для работы с многопоточностью есть, они используются редко. Например, если необходимо инициализировать определенные регистры на каждом ядре процессора, можно запустить функцию, которая будем выполнена на каждом процессорном ядре. Однако настоящей многопоточности в UEFI нет, так как сервисы на это не рассчитаны. Попытка использовать многопоточность для драйверов приведет к сбоям.
Еще одной особенностью является отказ от использования прерываний, за исключением прерываний таймера. Они позволяют вызывать определенные функции, например раз в секунду. Однако вместо того, чтобы использовать прерывания в драйверах, таких как USB, применяется метод опроса (polling). Код драйвера просто циклически проверяет, не поступило ли событие от контроллера.
У этого подхода есть недостатки: однопоточность и использование метода опроса вместо прерываний снижают производительность, поэтому сервер с большим количеством оборудования, которое требует инициализации, может загружаться медленно.
В UEFI у точки входа в приложение есть свои особенности. В отличие от операционной системы, здесь нет динамической линковки. Вместо этого используются либо статически слинкованные библиотеки, либо программные интерфейсы (протоколы).
Точка входа принимает два параметра:
ImageHandle — дескриптор исполняемого файла, который позволяет идентифицировать запущенный модуль,
System Table — таблица, содержащая функции и служебные данные.
В коде часто используются объекты gBS и gRT, которые предоставляют boot-сервисы (сервисы времени загрузки) и runtime-сервисы (сервисы времени выполнения). Boot-сервисы используются на стадии загрузки операционной системы, а runtime-сервисы доступны как в процессе работы BIOS, так и после загрузки ОС.
Простой пример кода на UEFI выше демонстрирует вывод строки «Hello, World». Результат выполнения сохраняется в переменной Status, типа EFI_STATUS. Этот тип стандартизирован и позволяет определить, успешно ли завершилась функция или произошла ошибка. Значение EFI_SUCCESS (0) означает успех, а для ошибок используются фиксированные коды. Пользовательские коды ошибок обычно не добавляются, так как хватает стандартного набора ошибок.
Для вывода текста на экран используется программный интерфейс, который называется SimpleText Output Protocol. Указатель на этот протокол передается как первый параметр, что напоминает неявную передачу указателя this в методах C++, только в UEFI это делается явно. Обычно протоколы ищутся через функцию LocateProtocol, которая доступна через таблицу Boot Services. Однако протокол вывода текста встроен прямо в таблицу System Table, и это упрощает его использование. «Под капотом» в данном случае будет использоваться специальный драйвер ConSplitterDxe, который выведет строку на все доступные устройства, например на экран и в последовательный порт.
Файлы UEFI имеют формат PE, который также используется в операционной системе Windows. Разница лишь в заголовке и некоторых деталях структуры. В Windows у подобных файлов — расширение .exe, в UEFI их структура практически такая же, но расширение файлов — .efi.
Для идентификации сущностей в UEFI используется GUID (Globally Unique Identifier). Это 16-байтовое число, которое однозначно идентифицирует объекты, такие как протоколы и другие сущности внутри прошивки.
Давайте погрузимся во внутреннее устройство прошивки. На скриншотах ниже — прошивка нашего сервера, которая открыта в утилите UEFITool. Эта утилита разработана нашим соотечественником (@CodeRush, спасибо за утилиту 🙂). Она позволяет разобрать прошивку на компоненты благодаря строгой стандартизации. Как я уже упоминал, существует спецификация Platform Initialization, которая определяет, как именно данные должны быть организованы в прошивке.
Одна из ключевых особенностей UEFI — в том, что обычно параметры прошивки и код хранятся на одной и той же SPI FLASH. Область, где хранятся параметры, называется NVRAM. Устройство NVRAM имеет интересную особенность: при записи данных старые значения не перезаписываются, а новые данные добавляются в конец свободной области. При этом у старых данных снимается флаг валидности, а у новых — устанавливается.
Такой подход обеспечивает транзакционность: если во время записи питание внезапно отключится (например, кто-то выдернул кабель питания из розетки), система сохранит работоспособность.
Однако у этого метода есть один недостаток. Поскольку данные записываются в конец, то место в памяти постепенно заканчивается. В таком случае запускается специальная процедура — восстановление, использующая в своей работе программный интерфейс FTW. Она сжимает данные и переносит их в начало памяти, освобождая место для новых записей.
Процедура работает следующим образом:
Система устанавливает флаг, сигнализирующий о начале процесса восстановления.
Содержимое NVRAM копируется в резервную область, служащую бэкапом. Это защищает данные на случай отключения питания.
После сжатия данных флаг процесса снимается.
Если питание пропадает в середине процесса, система использует резервную область, чтобы восстановить данные.
Еще один компонент прошивки — Volume. Фактически это нечто среднее между логическим разделом на диске и каталогом в файловой системе. Внутри Volume могут находиться как файлы, так и другие Volume.
File в UEFI идентифицируется с помощью GUID:
Содержимое File организовано в виде множества секций:
У каждой секции есть заголовок, который обычно занимает 4 байта. В заголовке указан размер секции и то, какие данные в ней содержатся. В некоторых случаях размер секции может быть больше, а заголовок может включать GUID, который указывает, что секцию нужно обрабатывать определенным образом.
Но в этом примере секция вполне обычная: в случае секции типа PE32 Image Section заголовок состоит из 4 байт, а затем размещается исполняемый EFI-файл. Этот файл запускается диспетчером стадии DXE: DXE Core.
Первая особенность нашей работы — это распределенная команда. Серверы, на которых мы разрабатываем прошивки, могут находиться в Москве, а разработчики — в других городах: от Владивостока до Калининграда и от Архангельска до Смоленска. Это накладывает определенные ограничения и требует специального подхода к работе.
Системы, для которых мы разрабатываем прошивки, делятся на два типа: с BMC и без него.
BMC — это система на кристалле, которая установлена на материнской плате. Она инициализируется при подаче дежурного питания, независимо от работы хоста. BMC обычно работает под управлением специализированной версии Linux и, среди прочего, выполняет следующие задачи:
управление вентиляторами,
мониторинг оборудования,
управление включением/выключением/перезагрузкой хоста,
обеспечение доступа к видеовыходу хоста (IP-KVM) и последовательному порту хоста (Serial-over-LAN),
подключение устройства ввода (IP-KVM) и образов носителей (Virtual Media).
О подходе YADRO к BMC и участии компании в проекте OpenBMC читайте в статье →
В контексте разработки UEFI BMC полезна тем, что позволяет подключиться к системе и прошить SPI Flash, на которой хранится прошивка UEFI.
Мы используем BMC для прошивки BIOS и управления питанием хоста. Отладка происходит через передачу отладочных сообщений в COM-порт, который в случае серверных платформ фактически представляет собой аппаратный блок внутри BMC. Это позволяет удаленно просматривать логи хоста.
Также за счет того, что BMC выполняет роль LPC-моста, у этой системы есть возможность принимать и протоколировать отправляемые из BIOS POST-коды стадий ранней загрузки. Затем их можно просмотреть из интерфейса BMC.
Если система зависает или не отвечает, мы можем использовать управляемые розетки для полного обесточивания сервера, фактически «вынимаем» вилку из розетки. К консоли BMC можно подключиться удаленно с помощью SSH либо подключиться к промежуточному серверу, к которому подключены USB-to-COM адаптеры, а затем запустить консоль BMC. Так можно удаленно прошивать и отлаживать систему.
Если BMC отсутствует, то процесс разработки усложняется. Для таких систем, как ноутбуки и планшеты KVADRA, мы работаем локально. В этом случае используется USB-to-COM для отладки и программатор для прошивки SPI Flash. Флешку можно либо извлечь, либо подключиться к ней с помощью специальных клещей. У некоторых платформ есть разъем для прошивки, что упрощает процесс.
Дополнительно мы можем использовать вспомогательное оборудование, такое как эмулятор SPI Flash. Это устройство подключается к материнской плате вместо физической микросхемы (или иногда вместе с нею) и позволяет загружать образы BIOS через специальную утилиту. У нее есть версия под Linux, что позволяет использовать терминал для запуска эмулятора. Таким образом, систему можно запустить без физической прошивки реальной SPI Flash и сэкономить на этом время.
Если BMC нет, мы также можем при необходимости реализовать удаленную отладку с помощью аппаратного IP-KVM. Например, можно использовать piKVM, который работает на базе Raspberry Pi. Это удобное и надежное решение.
Наш BIOS, основанный на EDK2, поддерживает кроссплатформенную сборку. Прошивка может быть собрана под Windows, Linux или macOS. Часть команды работает под Windows с компилятором Microsoft (Visual Studio), другая — использует GCC на Linux.
В продакшене прошивки собираются под Linux с помощью GCC. Для CI/CD мы используем Jenkins.
Для отладки прошивка собирается со специальными флагами, благодаря которым сборка содержит множество дополнительных сообщений. Эти сообщения выводятся, как правило, в COM-порт. В релизной версии прошивки эти сообщения удаляются.
Процесс разработки выглядит так:
Реализуем функционал.
Собираем прошивку с отладочными сообщениями.
Тестируем прошивку на аппаратной платформе, проверяя отладочные логи и корректность работы функционала.
Отправляем код на ревью.
После ревью код добавляется в основную ветку. Jenkins выполняет сборку прошивки, а ссылка на сборку прикрепляется к соответствующей задаче в таск-менеджере, который мы используем в компании.
Добавленный функционал или исправленный баг проверяют сотрудники отдела QA.
Часть функционала можно отладить в QEMU. В рамках EDK2 существует проект OVMF, который позволяет запускать прошивку в виртуальной среде. Это полезно для тестирования интерфейсов и ускорения разработки. Например, часть меню в прошивках для устройств KVADRA мы сначала тестировали в QEMU, а затем переносили на реальное оборудование.
В сложных случаях используется аппаратная отладка. Если сервер поддерживает разъем XDP, мы подключаем устройство Intel BlueBox для отладки:
Также Intel предлагает способ отладки через USB-кабель, называемый DCI, это решение закрыто и специфично для Intel.
Однако большую часть задач по отладке мы решаем с использованием UART, поскольку это проще и быстрее.
Возможны случаи появления проблем с BIOS, когда оборудование, например, уже введено в эксплуатацию. Здесь для локализации неисправностей полезны POST-коды. Этот механизм практически не изменился со времен классических BIOS. POST-код — это число, которое прошивка передает на определенном этапе своей работы.
Обычно POST-коды отправляются в порт 80h, откуда через интерфейс LPC/eSPI они попадают в BMC. В BMC можно посмотреть журнал POST-кодов. Это особенно полезно при диагностике проблем с памятью, так как инициализация памяти — сложный процесс, включающий множество функций, которые вызываются последовательно. Каждая из этих функций сопровождается отправкой post-кода. Если процесс завис, по последнему POST-коду можно понять, на каком этапе произошел сбой.
BMC также предоставляет журналы логов, что упрощает диагностику. Например, при возникновении ошибки памяти информация о ней может быть передана в BMC, где будет зафиксировано, какая именно планка памяти и по какому адресу вызвала проблему. Там можно быстро определить источник неисправности и принять меры.
В реальных условиях средств диагностики на сервере обычно немного, поэтому прошивка должна быть максимально протестирована перед вводом в эксплуатацию. Если сервер не может загрузиться из-за ошибки в прошивке, он становится фактически неработоспособным. Это делает тщательное тестирование и отладку прошивки критически важными этапами разработки.
Мы разобрались с UEFI, современной реализацией BIOS, в общих чертах и узнали, как инженеры YADRO занимаются разработкой и отладкой этой важной системы. Архитектура UEFI была призвана максимально упростить разработку, но создание прошивок содержит множество нюансов и подводных камней. Обо всем в рамках одной статьи рассказать сложно, поэтому пишите в комментариях, про что вы хотели бы еще узнать. И мы напишем продолжение.
Tianocore EDK2: референсная реализации UEFI
Спецификации: