paint-brush
Путешествие по секретам прошивки: от BIOS/UEFI до ОСк@tristejoursoir
833 чтения
833 чтения

Путешествие по секретам прошивки: от BIOS/UEFI до ОС

к Aleksandr Goncharov20m2024/08/22
Read on Terminal Reader

Слишком долго; Читать

Изучите эволюцию от традиционного BIOS до современной прошивки UEFI, узнайте, как управляются последовательности загрузки, и откройте для себя роли служб загрузки и служб времени выполнения. Погрузитесь в сложность загрузчиков ОС и посмотрите, как теперь прошивка поддерживает расширенные функции и приложения.
featured image - Путешествие по секретам прошивки: от BIOS/UEFI до ОС
Aleksandr Goncharov HackerNoon profile picture
0-item
1-item


Вы когда-нибудь задумывались, что происходит в тот момент, когда вы нажимаете кнопку питания на своем компьютере? За этой короткой паузой, перед тем как загорится экран, происходит сложная серия процессов. В этой статье мы погрузимся в увлекательный мир прошивки , исследуя, как различные компоненты взаимодействуют во время процесса загрузки .


Понимая эти связи, вы получите более ясную картину основополагающих элементов, которые оживляют вашу систему. Наше основное внимание будет уделено архитектуре Intel x86 , но многие принципы применимы и к другим архитектурам.


Если вы пропустили первую часть нашей серии, нажмите здесь , чтобы наверстать упущенное. Теперь давайте раскроем тайны, скрывающиеся за прошивкой.

Оглавление:

  • Определения
  • Общая архитектура прошивки
  • Загрузчик первой ступени (FSBL)
    • BIOS (фаза POST)
    • Инициализация платформы UEFI (PI)
    • coreboot
    • Другие решения
  • Загрузчик второго уровня (SSBL)
    • БИОС
    • УЕФИ
  • Загрузчик ОС


Определения

  • Прошивка : специализированный тип программного обеспечения, встроенного в оборудование, обеспечивающего низкоуровневое управление и позволяющего оборудованию правильно функционировать и взаимодействовать с другими компонентами системы.


  • Базовая система ввода-вывода (BIOS) : устаревшая прошивка (первоначально созданная для IBM PC ), отвечающая за инициализацию оборудования после включения платформы. В настоящее время ее часто неопределенно называют полным набором прошивки.


  • Bootloader : общее название прошивки, которая отвечает за загрузку компьютера. Используется как современная концепция вместо BIOS , часто предоставляя фреймворк с кодом начальной загрузки для инициализации процессора и чипсета, а также интерфейсы для третьих сторон (например, разработчиков материнских плат) для выполнения инициализации, специфичной для платформы.


  • Полезная нагрузка : программное обеспечение, которое должно быть выполнено при выходе из загрузчика. Может быть загрузчиком второго этапа, операционной системой, приложением BIOS/UEFI и т. д. Обычно оно отвечает за процесс загрузки в соответствии с дизайном прошивки.


  • Использование терминов BIOS и загрузчик может сбивать с толку, поскольку их значение зависит от контекста. Однако, когда кто-то упоминает прошивку , BIOS или загрузчик , они обычно имеют в виду полный набор прошивок, работающих между операционной системой и оборудованием .


  • EFI против UEFI : Extensible Firmware Interface (EFI) — это оригинальная спецификация, разработанная Intel. Unified Extensible Firmware Interface (UEFI) — преемник EFI , созданный UEFI Forum для стандартизации и расширения оригинальной спецификации. В большинстве случаев EFI и UEFI используются взаимозаменяемо.

Общая архитектура прошивки

Чтобы понять, как взаимодействуют компоненты прошивки, мы рассмотрим всю архитектуру со всеми ее связанными частями. Поток выполнения, показанный на схеме ниже, начинается с вектора сброса , который является частью загрузчика первой ступени . Оттуда он проходит через различные этапы прошивки:



Прошивку или BIOS обычно можно разделить на две основные части, между которыми обычно имеется минимальный интерфейс:


  1. Инициализация оборудования : отвечает за инициализацию аппаратных компонентов системы.
  2. Интерфейс к ОС и пользователю : предоставляет необходимые интерфейсы к операционной системе и пользователю.


Дизайн прошивки платформы может быть либо монолитным , объединяющим аппаратную инициализацию и функциональность загрузки, либо он может следовать модульному и поэтапному потоку загрузки . Выбор дизайна зависит от системных требований и может быть предпочтительным для определенных устройств.


На следующей схеме показано, как взаимодействуют различные компоненты прошивки и как их можно использовать вместе для поддержки процесса загрузки (стрелки указывают последовательность выполнения):



Если эти диаграммы сейчас кажутся сложными, не волнуйтесь. Пересмотрите их еще раз после прочтения этой статьи, и они станут понятнее.

Загрузчик первой ступени (FSBL)

Эта часть прошивки предназначена для инициализации компьютеров и встроенных систем с упором на минимальную инициализацию оборудования : делать только то, что абсолютно необходимо, а затем передавать управление загрузчику второго этапа для загрузки операционной системы. FSBL не загружает операционные системы с носителей, отличных от флэш-чипа . Поскольку она инициализирует только базовое оборудование и не обрабатывает загрузочные носители, такие как жесткие диски, SSD или USB-флеш-накопители, для фактической загрузки операционной системы требуется другая часть программного обеспечения.


Основные обязанности FSBL :


  1. ЦП : переключение из 16-битного реального режима в 32-битный защищенный режим ( примечание : или в виртуальном режиме 8086 в случае BIOS).
  2. Использование кэша : вызов FSP-T для настройки кэша как ОЗУ для среды C.
  3. Порт отладки : инициализация настроенного порта отладки путем вызова методов инициализации, специфичных для платы.
  4. Инициализация памяти : вызов FSP-M для инициализации основной памяти системы и сохранения важной информации о системной памяти.
  5. GPIO : настройка контактов ввода-вывода общего назначения (GPIO) для взаимодействия с внешними устройствами.
  6. Кремний : выполнение ранней инициализации платформы и использование FSP-S для завершения инициализации чипсета, ЦП и контроллера ввода-вывода.
  7. Перечисление PCI : перечисление устройств PCI и выделение ресурсов, таких как адреса памяти и IRQ.
  8. Подготовка полезной нагрузки : настройка таблиц SMBIOS и ACPI , включая информацию о подготовке (таблицы загрузки ядра, HOB), необходимую для передачи полезной нагрузке.
  9. Загрузка и передача управления : загрузка и передача управления полезной нагрузке.

BIOS (фаза POST)

На заре вычислительной техники программное обеспечение с открытым исходным кодом не пользовалось большой популярностью, и большинство реализаций BIOS были проприетарными. Существует лишь несколько доступных открытых решений, предоставляющих исходный код BIOS POST, например , Super PC/Turbo XT BIOS и GLaBIOS . Эти проекты были разработаны для работы на системах IBM 5150/5155/5160 и большинстве клонов XT.


Однако более известные реализации BIOS с открытым исходным кодом, такие как OpenBIOS и SeaBIOS , не выполняют инициализацию оборудования, поскольку они не предназначены для работы на голом оборудовании. Но они широко используются в качестве загрузчиков второго уровня и работают изначально в виртуальных средах, таких как QEMU и Bochs.


В любом случае, маловероятно, что вам придется работать напрямую с этими ранними BIOS или глубоко вникать в их специфику. Но если вы заинтересованы в исследовании, упомянутые репозитории являются хорошей отправной точкой.


Что касается современных тенденций развития, то, по всей видимости, разработка собственных решений BIOS не ведется, и такие проекты устарели по сравнению с современными альтернативами.

Инициализация платформы UEFI (PI)

Процесс загрузки следует поэтапному потоку, начиная слева и двигаясь вправо на следующем рисунке. Временная шкала процесса загрузки платформы разделена на следующие фразы, как указано желтыми полями:



  • Безопасность (SEC) : первая фаза после вектора сброса , ее основная функция — настройка временной оперативной памяти (CPU Cache-As-RAM или SRAM).
  • Инициализация Pre-EFI (PEI) : эта фаза отправляет специализированные драйверы, называемые модулями инициализации Pre-EFI (PEIM) . Эти модули выполняют необходимую инициализацию оборудования, такую как настройка ЦП и чипсета, а также настройка основной памяти (DRAM) .
  • Driver Execution Environment (DXE) : на этом этапе выполняется остальная часть инициализации системы. Фаза DXE предоставляет службы UEFI и поддерживает различные протоколы и драйверы, необходимые для работы системы.
  • Выбор загрузочного устройства (BDS) : на этом этапе реализуется политика загрузки платформы, определяется последовательность загрузки и выбирается соответствующее загрузочное устройство/загрузчик.
  • Transient System Load (TSL) : на этом этапе система запускает приложения, использующие службы UEFI, для подготовки ОС. Он включает переход из среды UEFI в операционную систему, завершающийся вызовом ExitBootServices() .
  • Время выполнения (RT) : на этом этапе операционная система полностью работоспособна и управляет системой, находящейся под ее контролем.
  • После жизни (AL) : Эта фаза касается сценариев, когда оборудование или ОС выходят из строя/выключаются/перезагружаются. Прошивка может попытаться выполнить действия по восстановлению, однако спецификация UEFI PI не определяет конкретных требований или поведения для этой фазы.


Этот процесс и его фазы выполнения охвачены спецификацией UEFI Platform Initialization (PI) . Однако есть также интерфейс UEFI (обозначенный жирной синей линией на рисунке), который не является частью предыдущего документа и описан в спецификации UEFI . Хотя названия и частое использование UEFI могут сбивать с толку, эти два документа имеют разную направленность:


  • UEFI PI Spec : фокусируется на интерфейсах между низкоуровневыми компонентами прошивки и подробно описывает, как эти модули взаимодействуют для инициализации платформы.


  • UEFI Spec : определяет интерфейсы для взаимодействия между операционной системой (ОС) и прошивкой. Это будет обсуждаться далее в контексте Second-Stage Bootloader . Обратите внимание, что спецификация UEFI опирается на спецификацию PI.


По сути, обе спецификации касаются интерфейсов, но на разных уровнях. Для получения подробной информации вы можете получить доступ к обеим спецификациям на сайте UEFI Forum .


UEFI PI изначально был разработан как унифицированное решение прошивки, не учитывающее различие между загрузчиками первой и второй стадии. Однако, когда мы называем UEFI загрузчиком первой стадии , он включает фазы SEC , PEI и раннюю фазу DXE . Причина, по которой мы разделяем DXE на раннюю и позднюю фазы, заключается в их различных ролях в процессе инициализации.


На ранней фазе DXE драйверы обычно выполняют необходимую инициализацию CPU/PCH/платы, а также создают архитектурные протоколы DXE (AP) , которые помогают изолировать фазу DXE от аппаратного обеспечения, специфичного для платформы. AP инкапсулируют детали, специфичные для платформы, позволяя поздней фазе DXE работать независимо от аппаратных характеристик.



Coreboot

Скоро появятся подробные статьи о том, как работает Coreboot. Подписывайтесь на мои социальные сети — они будут опубликованы очень скоро!

Другие решения

  • Intel Slim Bootloader (SBL) : чистый загрузчик первой стадии, который обеспечивает только инициализацию основных аппаратных компонентов, за которой следует загрузка полезной нагрузки. Однако он работает только на платформах Intel x86 и не поддерживает AMD x86 или другие архитектуры.
  • Das U-Boot : загрузчик как первого, так и второго этапа. Однако поддержка загрузки напрямую с вектора сброса x86 платформы (известного как bare mode) ограничена по сравнению с другими прошивками. Он более популярен на встраиваемых системах и устройствах на базе ARM. Как загрузчик второго этапа, U-Boot реализует подмножество UEFI , но фокусируется на встраиваемых системах.

Загрузчик второго уровня (SSBL)

После завершения первоначальной настройки оборудования вступает в действие второй этап . Его основная роль — настроить программный интерфейс между операционной системой и прошивкой платформы , гарантируя, что ОС сможет управлять системными ресурсами и взаимодействовать с аппаратными компонентами.


SSBL стремится максимально скрыть различия в оборудовании , упрощая разработку ОС и приложений, обрабатывая большинство интерфейсов на уровне оборудования. Эта абстракция позволяет разработчикам сосредоточиться на функциональности более высокого уровня, не беспокоясь о базовых различиях в оборудовании.


Основные обязанности SSBL :


  1. Извлечение информации о платформе : получает информацию о платформе из загрузчика первой ступени , включая отображение памяти, SMBIOS, таблицы ACPI, флэш-память SPI и т. д.


  2. Запуск платформенно-независимых драйверов : включает драйверы для SMM, SPI, PCI, SCSI/ATA/IDE/DISK, USB, ACPI, сетевых интерфейсов и т. д.


  3. Реализация служб (также известная как интерфейс) : предоставляет набор служб, которые облегчают взаимодействие между операционной системой и аппаратными компонентами.


  4. Меню настройки : предлагает меню настройки конфигурации системы, позволяющее пользователям настраивать параметры, связанные с порядком загрузки, аппаратными параметрами и другими параметрами системы.


  5. Логика загрузки : механизм поиска и загрузки полезной нагрузки (вероятно, операционной системы) с доступного загрузочного носителя.

БИОС

Интерфейс в BIOS известен как BIOS services/functions/interrupt calls . Эти функции предоставляют набор процедур для доступа к оборудованию, но конкретные детали того, как они выполняются на конкретном оборудовании системы, скрыты от пользователя.


В 16-битном реальном режиме к ним можно легко получить доступ, вызвав программное прерывание с помощью инструкции языка ассемблера INT x86. В 32-битном защищенном режиме почти все службы BIOS недоступны из-за различного способа обработки значений сегментов .




Давайте возьмем, например, Disk Services ( INT 13h ), который предоставляет секторные службы чтения и записи жесткого диска и гибкого диска с использованием адресации Cylinder-Head-Sector (CHS) , в качестве примера того, как можно использовать этот интерфейс. Допустим, мы хотим прочитать 2 сектора (1024 байта) и загрузить их по адресу памяти 0x9020 , тогда можно выполнить следующий код:


 mov $0x02, %ah # Set BIOS read sector routine mov $0x00, %ch # Select cylinder 0 mov $0x00, %dh # Select head 0 [has a base of 0] mov $0x02, %cl # Select sector 2 (next after the # boot sector) [has a base of 1] mov $0x02, %al # Read 2 sectors mov $0x00, %bx # Set BX general register to 0 mov %bx, %es # Set ES segment register to 0 mov $0x9020, %bx # Load sectors to ES:BX (0:0x9020) int $0x13 # Start reading from drive jmp $0x9020 # Jump to loaded code


Если вам интересно, как эта служба написана в SeaBios, взгляните на src/disk.c .

Фаза загрузки

  • Начинает поиск загрузочного устройства (это может быть жесткий диск, CD-ROM, гибкий диск и т. д.), считывая первый 512-байтовый сектор (нулевой сектор) с устройства.


  • Последовательность начальной загрузки в BIOS загружает первую действительную основную загрузочную запись (MBR) , которую она находит, в физическую память компьютера по физическому адресу 0x7C00 (подсказка: 0x0000:0x7c00 и 0x7c0:0x0000 относятся к одному и тому же физическому адресу).


  • BIOS передает управление первым 512 байтам полезной нагрузки. Этот загруженный сектор , который слишком мал, чтобы вместить весь код полезной нагрузки, служит для загрузки остальной части полезной нагрузки с загрузочного устройства . На этом этапе полезная нагрузка может использовать интерфейс, предоставляемый BIOS.


Примечательно, что спецификации BIOS не существовали в ранние дни. BIOS является фактическим стандартом — он работает так же, как работал на реальных IBM PC в 1980-х годах. Остальные производители просто провели обратную разработку и создали IBM-совместимые BIOS. В результате не было никаких правил, запрещающих производителям BIOS изобретать новые функции BIOS или иметь дублирующиеся функциональные возможности.

Унифицированный расширяемый интерфейс прошивки (UEFI)

Как упоминалось ранее, UEFI сам по себе является всего лишь спецификацией и имеет множество реализаций. Наиболее широко используемой является TianoCore EDK II , эталонная реализация спецификаций UEFI и PI с открытым исходным кодом . Хотя EDKII сам по себе недостаточен для создания полностью функциональной загрузочной прошивки, он обеспечивает прочную основу для большинства коммерческих решений.


Для поддержки различных загрузчиков первого этапа и предоставления интерфейса UEFI используется проект UEFI Payload . Он опирается на выполненную начальную настройку и информацию о платформе, предоставленную загрузочной прошивкой, для подготовки системы к среде UEFI.


Полезная нагрузка UEFI использует фазы DXE и BDS , которые разработаны как независимые от платформы. Она предлагает общую полезную нагрузку, которая может адаптироваться к различным платформам. В большинстве случаев она не требует какой-либо настройки или специфичных для платформы корректировок и может использоваться как есть, используя информацию о платформе из загрузчика первой ступени .


Варианты полезной нагрузки UEFI :


  1. Legacy UEFI Payload : Требует библиотеку синтаксического анализа для извлечения необходимой информации о платформе, специфичной для реализации. Если загрузчик обновляет свой API, полезная нагрузка также должна быть обновлена.



  2. Universal UEFI Payload : следует спецификации Universal Scalable Firmware (USF) , используя Executable and Linkable Format (ELF) или Flat Image Tree (FIT) в качестве общего формата образа. Вместо того, чтобы разбирать их самостоятельно, он ожидает получить Hand Off Blocks (HOB) при входе в payload.


В то время как Legacy UEFI Payload работает отлично, сообщество EDK2 пытается переключить отрасль на Universal UEFI Payload . Выбор между payload зависит от компонентов вашей прошивки. Например, невозможно запустить Legacy Payload с поддержкой SMM на Slim Bootloader без моего патча . С другой стороны, использование Universal Payload с coreboot требует слоя shim для перевода таблиц coreboot в HOBs , функция доступна только в форке StarLabs EDK2 .

Интерфейс

Каждая UEFI-совместимая система предоставляет системную таблицу , которая передается каждому коду, работающему в среде UEFI (драйверы, приложения, загрузчики ОС). Эта структура данных позволяет исполняемому файлу UEFI получать доступ к таблицам конфигурации системы , таким как ACPI , SMBIOS и набору служб UEFI .



Структура таблицы описана в MdePkg/Include/Uefi/UefiSpec.h :


 typedef struct { EFI_TABLE_HEADER Hdr; CHAR16 *FirmwareVendor; UINT32 FirmwareRevision; EFI_HANDLE ConsoleInHandle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; EFI_HANDLE ConsoleOutHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; // // A pointer to the EFI Runtime Services Table. // EFI_RUNTIME_SERVICES *RuntimeServices; // // A pointer to the EFI Boot Services Table. // EFI_BOOT_SERVICES *BootServices; UINTN NumberOfTableEntries; EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE;


Службы включают в себя следующие типы: службы загрузки , службы времени выполнения и службы, предоставляемые протоколами .


UEFI абстрагирует доступ к устройству, настраивая протоколы UEFI . Эти протоколы представляют собой структуры данных, содержащие указатели функций , и идентифицируются глобально уникальным идентификатором (GUID) , который позволяет другим модулям находить и использовать их. Их можно обнаружить через службы загрузки.


Драйвер UEFI создает эти протоколы, а фактические функции (не указатели!) содержатся в самом драйвере. Этот механизм позволяет различным компонентам в среде UEFI взаимодействовать друг с другом и гарантирует, что ОС может взаимодействовать с устройствами до загрузки собственных драйверов.



Хотя некоторые протоколы предопределены и описаны в спецификации UEFI, поставщики встроенного ПО также могут создавать свои собственные пользовательские протоколы для расширения функциональности платформы.


Загрузочные службы

Предоставляют функции, которые могут использоваться только во время загрузки. Эти службы остаются доступными до тех пор, пока не будет вызвана функция EFI_BOOT_SERVICES.ExitBootServices() ( MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c ).


Указатели на все службы загрузки хранятся в таблице служб загрузки ( MdePkg/Include/Uefi/UefiSpec.h ):


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_MEMORY_MAP GetMemoryMap; EFI_ALLOCATE_POOL AllocatePool; EFI_FREE_POOL FreePool; ... EFI_HANDLE_PROTOCOL HandleProtocol; ... EFI_EXIT_BOOT_SERVICES ExitBootServices; ... } EFI_BOOT_SERVICES;


Службы времени выполнения

Минимальный набор служб все еще доступен, пока работает операционная система. В отличие от служб загрузки, эти службы остаются действительными после того, как любая полезная нагрузка (например, загрузчик ОС) взяла под контроль платформу через вызов EFI_BOOT_SERVICES.ExitBootServices() .


Указатели на все службы времени выполнения хранятся в таблице служб времени выполнения ( MdePkg/Include/Uefi/UefiSpec.h ):


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_TIME GetTime; EFI_SET_TIME SetTime; ... EFI_GET_VARIABLE GetVariable; EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; EFI_SET_VARIABLE SetVariable; ... EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; EFI_RESET_SYSTEM ResetSystem; ... } EFI_RUNTIME_SERVICES;


На рисунке ниже показана временная шкала для служб загрузки и выполнения, поэтому вы можете точно видеть, когда каждая из них активна.



Фаза выбора загрузочного устройства (BDS)

Спецификация UEFI определяет механизм политики загрузки, называемый менеджером загрузки UEFI . Он попытается загрузить приложения UEFI в определенном порядке. Этот порядок и другие параметры можно настроить, изменив глобальные переменные NVRAM (энергонезависимая память с произвольным доступом) . Давайте обсудим самые важные из них:


  • Boot#### ( #### заменяется уникальным шестнадцатеричным значением) — параметр загрузки/загрузки.
  • BootCurrent — параметр загрузки, используемый для запуска текущей работающей системы.
  • BootNext — параметр загрузки только для следующей загрузки. Заменяет BootOrder только для одной загрузки и удаляется менеджером загрузки после первого использования. Позволяет изменить поведение следующей загрузки без изменения BootOrder .
  • BootOrder — упорядоченный список загрузки вариантов загрузки. Менеджер загрузки пытается загрузить первый активный вариант в этом списке. Если не удается, он пробует следующий вариант и т. д.
  • BootOptionSupport — типы параметров загрузки, поддерживаемые менеджером загрузки.
  • Timeout — тайм-аут менеджеров загрузки прошивки в секундах перед автоматическим выбором значения запуска из BootNext или BootOrder .


Эти переменные можно легко получить из Linux с помощью efibootmgr(8) :


 [root@localhost ~]# efibootmgr BootCurrent: 0000 Timeout: 5 seconds BootOrder: 0000,0001,2001,2002,2003 Boot0000* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi) Boot0001* Windows Boot Manager HD(1,GPT,6f185443-09fc-4f15-afdf-01c523565e52,0x800,0x32000)/File(\EFI\Microsoft\Boot\bootmgfw.efi)57a94e544f5753000100000088900100780000004200430044039f0a42004a004500430054003d007b00390064006500610038003600320063002d1139006300640064002d0034006500370030102d0061006300630031002d006600330032006200330034003400640034003700390035007d00000033000300000710000000040000007fff0400 Boot0002* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000) Boot2001* EFI USB Device RC Boot2002* EFI DVD/CDROM RC Boot2003* EFI Network RC


Давайте рассмотрим загрузку, опираясь на фрагмент кода выше. UEFI начнет итерацию списка BootOrder . Для каждой записи в списке он ищет соответствующую переменную Boot####Boot0000 для 0000, Boot2003 для 2003 и т. д. Если переменная не существует, он переходит к следующей записи. Если переменная существует, он считывает содержимое переменной. Каждая переменная параметра загрузки содержит дескриптор EFI_LOAD_OPTION , который представляет собой байтовый буфер полей переменной длины (это просто структура данных).


Структура данных описана в [MdePkg/Include/Uefi/UefiSpec.h][ https://github.com/tianocore/edk2/blob/edk2-stable202405/MdePkg/Include/Uefi/UefiSpec.h#L2122 )


 typedef struct _EFI_LOAD_OPTION { /// The attributes for this load option entry. UINT32 Attributes; /// Length in bytes of the FilePathList. UINT16 FilePathListLength; /// The user readable description for the load option. /// Example: 'ARCHLINUX' / 'Windows Boot Manager' / `EFI USB Device` // CHAR16 Description[]; /// A packed array of UEFI device paths. /// Example: 'HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi)' // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; /// The remaining bytes in the load option descriptor are a binary data buffer that is passed to the loaded image. /// Example: '57a9...0400' in Boot0001 variable // UINT8 OptionalData[]; } EFI_LOAD_OPTION;


На этом этапе прошивка проверит путь к устройству ( EFI_DEVICE_PATH_PROTOCOL ). В большинстве случаев наш компьютер загружается с устройства хранения данных (жесткий диск/SSD/NVMe и т. д.). Таким образом, путь к устройству будет содержать узел HD(Partition Number, Type, Signature, Start sector, Size in sectors) .


  • Тип — указывает формат, используемый для схемы разбиения, с ключевыми словами MBR (1) или GPT (2).
  • Подпись — 4-байтовая подпись MBR, если тип — MBR , или 16-байтовый UUID , если тип — GPT .


Примечание : Если вам интересно, как преобразовать другие пути, прочтите спецификацию UEFI v2.10, 10.6.1.6 Справочник по узлу текстового устройства .


UEFI проверит диск и определит, есть ли на нем раздел, соответствующий узлу. Если он существует, он должен быть помечен определенным Глобальным уникальным идентификатором (GUID) , который отмечает его как раздел системы EFI (ESP) . Этот раздел отформатирован с файловой системой, спецификация которой основана на конкретной версии файловой системы FAT и называется EFI File System ; на самом деле, это просто обычная FAT12/16/32 .


  • Собственная загрузка : если Device Path содержит явный путь к File(\Path\To\The\File.efi) , то UEFI будет искать этот конкретный файл. Например, параметр Boot0000 содержит File(\EFI\ARCHLINUX\grubx64.efi) .
  • Резервная загрузка : если Device Path просто указывает на диск, то в таких ситуациях прошивка будет использовать резервный путь загрузки , основанный на архитектуре — \EFI\BOOT\BOOT{arch}.EFI ( BOOTx64.EFI для amd64 или BOOTia32.EFI для i386 / IA32 ). Этот механизм позволяет загрузочному съемному носителю (например, USB-накопителю) работать в UEFI; они просто используют резервный путь загрузки . Например, опция Boot0002 будет использовать этот механизм.


Примечание: Все параметры Boot#### , упомянутые выше, относятся к параметрам загрузки, отображаемым в примере вывода efibootmgr .


В обоих случаях диспетчер загрузки UEFI загрузит приложение UEFI (это может быть загрузчик ОС , оболочка UEFI, служебное программное обеспечение, настройка системы и т. д.) в память. В этот момент управление передается точке входа приложения UEFI . В отличие от BIOS , приложение UEFI может вернуть управление прошивке (кроме ситуации, когда приложение берет на себя управление системой). Если это происходит или что-то идет не так, диспетчер загрузки переходит к следующей записи Boot#### и следует точно такому же процессу.


В спецификации упоминается, что менеджер загрузки может автоматически поддерживать переменные базы данных. Это включает удаление переменных опций загрузки, на которые нет ссылок или которые не могут быть проанализированы. Кроме того, он может переписать любой упорядоченный список, чтобы удалить любые опции загрузки без соответствующих переменных опций загрузки.


Вышеприведенный текст описывает загрузку UEFI . Кроме того, прошивка UEFI может работать в режиме Compatibility Support Module (CSM) , который эмулирует BIOS.

Загрузчик ОС

Часть программного обеспечения, запускаемая прошивкой (обычно загрузчиком второго уровня ) и использующая ее интерфейс для загрузки ядра ОС . Может быть таким же сложным, как ОС, предлагая такие функции, как:


  • Чтение из различных файловых систем (HFS+, ext4, XFS и т.д.)
  • Взаимодействие по сети (например, TFTP, HTTP)
  • Загрузка ядер, совместимых с Multiboot
  • Цепная загрузка
  • Загрузка начальных виртуальных дисков ( initrd )
  • И многое другое!


Общие конструкции этих программ выходят за рамки этой статьи. Для подробного сравнения популярных загрузчиков ОС вы можете обратиться к вики ArchLinux и статье в Википедии .


Система Windows использует собственный загрузчик ОС, известный как диспетчер загрузки Windows (BOOTMGR) .


Прошивка больше не является маленьким, сложным фрагментом кода. Она превратилась в огромный объем сложного кода , и современные тенденции только способствуют этому. На ней можно запустить Doom , Twitter и множество других интересных приложений.


Понимание общей архитектуры помогает организовать эти компоненты в вашем сознании. Изучая дизайн существующей прошивки, вы получаете представление об увлекательном процессе, который разворачивается каждый раз при включении компьютера. Эта нисходящая перспектива не только проясняет роль каждой части, но и подчеркивает сложную и развивающуюся природу современных систем прошивки.

Ресурсы