What is the Unified Extensible Firmware Interface, and what role does UEFI in Windows? On this page, we’ll clearly explain to you what UEFI is, what’s the difference between UEFI and BIOS boot modes, and how to set up a computer and enable UEFI mode on your own on Windows computers. Don’t worry about having UEFI boot issues, and you can also follow the troubleshooting tutorials to fix UEFI errors like an expert.
Go and follow to set up UEFI on your PC now.
In this article, you’ll learn:
- What Is UEFI?
- UEFI vs. Legacy BIOS, Which Is Better and What’s The Difference?
- How to Set Up UEFI and Use It on Windows 10/11? [Full Guide]
- Troubleshooting: Fix and Get Rid of UEFI Errors
UEFI, also known as the Unified Extensible Firmware Interface, is a publicly available specification that defines a software interface between an operating system and platform firmware. UEFI replaces the legacy Basic Input/Output System (BIOS) firmware interface originally present in all IBM PC-compatible personal computers, with most UEFI firmware implementations providing support for legacy BIOS services. — by
Wikipedia
Definition of UEFI
According to Wikipedia, UEFI is a specification that connects the computer’s firmware to its operating system. And UEFI is regarded as a successor to replace the traditional BIOS Legacy. UEFI works on the computer’s motherboard via a specific firmware, and it’s pre-installed while manufacturing.
Why Is UEFI Important and How Does It Work
In a word, UEFI runs first when you try to boot up the computer, and it connects hardware with OS so to allow your operating system to boot up and load hard drive information successfully.
Here is a list that explains how does Operating System process UEFI:
- UEFI is the first program that runs while booting a computer.
- UEFI checks if hardware components are attached.
- UEFI wakes up the components and connects them to the Operating System.
Operating Systems that Support UEFI:
- Windows 11 (Requires UEFI & Secure Boot Only)
- Windows 10 (x64)
- Windows 8.1 (x64)
- Windows 7 (x64)
- Windows Vista SP1 (x64)
- Windows Server 2022 (x64)
- Windows Server 2019 (x64)
- Windows Server 2016 (x64)
- Windows Server 2012 (x64)
- Windows Server 2008 R2 (x64)
- Windows Server 2008 (x64)
Note: Microsoft introduced UEFI for x64 Windows operating systems. So if your computer OS is x86 or 32 bit, you’ll need to set the BIOS Legacy boot mode on your computer instead of using UEFI.
History of UEFI:
- Mid-1990: Original EFI came out.
- 1998: EFI was renamed Extensible Firmware Interface.
- July 2005: EFI version 1.10 was contributed to the United EFI Forum, then developed as Unified Extensible Firmware Interface (UEFI).
- January 31st, 2006: UEFI 2.0
- January 7th, 2007: UEFI 2.1
- March 2021: UEFI 2.9 (The latest version)
How Do I Access UEFI Firmware Settings
Note that the UEFI firmware settings are only available on computers with motherboards that support UEFI boot. So how do you access the UEFI firmware settings?
You have two options here:
Option 1: Use F2/F10 or F12 Keys to Access UEFI Settings
- Turn on the computer, press the F2/F10/F12 or Del/Esc key when the Windows logo shows.
- Let the computer enters BIOS settings, and then go to the Boot tab.
There you’ll get a clear view of the UEFI firmware settings on your PC. Note that the hotkeys could be different on brands of computers. Here is at a list of hotkeys that you can apply to quickly enter UEFI settings:
- Dell: F2 or F12.
- HP: ESC or F10.
- Acer: F2 or Delete.
- ASUS: F2 or Delete.
- Lenovo: F1 or F2.
- MSI: Delete.
- Toshiba: F2.
- Samsung: F2.
- Surface: Press and hold the volume up button.
Option 2. Access UEFI from Settings
- Open Settings, click «Update & security > Recovery > Advanced startup» and click «Restart now».
- Click «Troubleshoot > UEFI Firmware Settings >Restart».
From the UEFI firmware settings, you can either switch UEFI boot mode to BIOS Legacy or configure the computer to better support UEFI. But what’s the difference between UEFI and BIOS, and which is better for you?
Move forward to the next part, and you’ll get the answers.
UEFI vs. Legacy BIOS, Which Is Better and What’s The Difference?
As you know that BIOS is also called Legacy BIOS, which was older than the UEFI, and now UEFI has surpassed BIOS in many aspects. In this part, we’ll show you the difference between these two firmware settings and which is better for you. Also, you’ll learn when to use UEFI and when to use Legacy BIOS on your PC.
UEFI VS BIOS, What’s the Difference
Similarity:
UEFI does the same job as BIOS. Both of them start up first and connect the operating systems and firmware hardware before loading the OS.
Differences:
From this comparison table, you’ll get to learn the major differences between UEFI and BIOS:
Comparison | UEFI | (Legacy) BIOS |
---|---|---|
Boot Procedure | UEFI -> EFI Boot Loader -> Kernel -> Operating System | BIOS -> MBR -> Bootloader -> Kernel -> Operating System |
Disk Device Compatibility | GPT Disk | MBR Disk |
Support Drive Size | 8ZB | 2TB |
Secure Boot | Yes | No |
Supported Bit Mode |
|
|
Location of Initialization and Startup Information | In a .efi file on an EFI System Partition | On the firmware |
Boot Speed | Faster | Slower |
Video Comparison: UEFI VS BIOS
When to Use UEFI? And When to Use BIOS?
Some of you may have a basic idea about whether your computer is suitable to use UEFI boot. Also, it doesn’t matter if you don’t know when to use UEFI. Here are two lists of situations that help you to understand when to use UEFI and when to use BIOS:
01
When to Use UEFI:
- OS hard drive is 3TB or larger
- Update OS to the latest Windows 11
- The operating system is 32-bit or 64-bit
- The computer motherboard supports both UEFI and BIOS
02
When to Use BIOS:
- The hard drive is 2TB or smaller
- The computer motherboard only supports BIOS.
UEFI or Legacy, which is suitable for SSD?
- When you need to install the latest Windows OS on SSD, use UEFI.
- If SSD is less than 2TB, and doesn’t for new OS installation, use BIOS for older operating systems.
LEARN MORE
For more details about UEFI and BIOS, you can refer to this page: UEFI VS BIOS: Difference between BIOS and UEFI.
How to Set Up UEFI and Use It on Windows 10/11? [Full Guide]
So how do I set up my computer with UEFI to install Windows 11? Or, can I configure my computer with UEFI mode? Follow the full guide here, and you’ll be able to set up UEFI and configure your computer ready for installing the latest Windows operating system or specific purposes:
Guide 1. Confirm If I Need UEFI for Windows 10/11
Before getting started to set up UEFI, it’s essential to confirm that you need UEFI for your PC. Let’s get started here:
First, Confirm If I Need UEFI
Note that UEFI only supports 64-bit operating systems. So please make sure that your computer is 64-bit. And if you’re trying to install the latest Windows 11, you’ll need to enable UEFI.
Second, Tell If Windows Is Using UEFI
You can either follow the guide above to access UEFI settings or check system information as shown here to confirm if your computer is using UEFI or BIOS:
Step 1. Press Windows + R keys, type MSInfo32, and click «OK».
Step 2. Find the BIOS Mode, and you’ll see if your operating system is using Legacy or UEFI.
LEARN MORE
Aside from this, the most common way to check Windows boot mode is to reboot the PC and use hotkeys such as F2/F10/F11, etc., to enter the BIOS settings. You can follow this link to learn if Windows Is Using UEFI or Legacy on your PC.
Guide 2. Convert OS Disk to GPT for UEFI Boot
After getting to know your boot mode in Windows, it’s time that you take action to check the disk type in Windows. Note that the UEFI boot mode is only compatible with GPT disk type.
It’s necessary that you check and configure your OS disk to GPT. Here is how to do so:
First, Confirm if Windows Is MBR or GPT
You can simply go to Windows Disk Management, right-click the OS disk and select «Properties», then go to the Volumes tab and check the disk type in:
You May Also Like:
Aside from checking disk type in Disk Management, you can also apply EaseUS Partition Master or CMD for help. Follow to learn How to Tell if Windows is MBR or GPT with the other two ways.
If your Windows disk is with MBR, you’ll need to convert it to GPT with the next guide here.
Next, Convert MBR Disk to GPT with Third-Party Disk Conversion Software, No Data Loss
Experienced Windows users may know how to convert a disk from MBR to GPT by using Disk Management or CMD command. Though workable, these two methods require deleting all partitions, which will cause serious data loss.
To take care of all your disk data, you can apply third-party disk conversion software – EaseUS Partition Master for help.
Step 1. Install and launch EaseUS Partition Master on your computer.
Step 2. Open the Disk Converter tab, select «MBR => GPT» and click «Next» to continue.
Step 3. Choose the target MBR disk, and click «Convert» to start the conversion.
LEARN MORE
If you prefer a step-by-step guide, follow this link, and you’ll learn how to successfully Convert MBR to GPT for Windows 11.
Guide 3. Change BIOS Mode from Legacy to UEFI Windows 10/11
After configuring your OS disk to GPT, it’s time that you switch the BIOS mode from Legacy to UEFI. Here are the steps:
Step 1. Restart the PC and press the F2 key to enter the BIOS setup utility.
Step 2. Go to the Boot or System configuration tab, and click «Boot».
Step 3. Under the Boot tab, select «UEFI/BIOS Boot Mode» and hit Enter.
Step 4. Use the up or down arrow to switch the boot mode from Legacy to «UEFI».
Step 5. Save the changes by pressing F10 and closing BIOS settings.
Bonus Tip:
If you need a full guide to turning on or turning off UEFI boot mode, you may follow this page to learn How to Enable or Disable UEFI Mode.
Note that if you are about to install Windows 11 on your disk, it’s also necessary that you turn on the Secure Boot for UEFI Boot Mode.
Step-by-Step Guide:
How to Enable Secure Boot for Windows 11
Bonus Tip: Install Windows 11 on GPT with UEFI
Suppose that you have followed the above 3 guides to complete setting up UEFI mode, it’s time that you start installing Windows 11 on your PC. Here are the steps:
Step 1. Download Windows 11 ISO and create a Windows installation media on an empty USB.
Step 2. Reboot the PC and, press F2 to enter BIOS settings, set the computer to boot from the installation USB.
Step 3. Configure Language, Time and currency format, Keyboard or input method, and click «Next».
Step 4. Click «Install Now» and select «I don’t have a product key» to continue.
Step 5. Select Windows 11 edition and click «Next».
Follow the on-screen guidelines to complete the process.
Complete GUIDE:
If you prefer an even more detailed guide that can assist you in completing Windows 11 installation on the converted GPT disk, please follow this link to learn How to Install Windows 11 on GPT.
Troubleshooting: Fix and Get Rid of UEFI Errors
During the process of setting up UEFI for new Windows operating systems, you may encounter multiple types of UEFI errors happening to your computer. If you are having one of the following listed errors, follow the respective solution to fix them now:
Error 1: Can’t Delete EFI Partition
Cause: «Delete Volume» option is greyed out due to the Windows protection mechanism.
Fix: Full Guide to Remove UEFI NTFS Partition (EFI Partition)
Error 2: Windows 11/10 Fails to Boot Because There Is a Problem with the Master Boot Record
Cause: MBR corrupted, UEFI Boot mode is not enabled, more.
Fix: See How to Fix UEFI Boot on Windows 11/10.
Error 3: UEFI Bootloader Gets Corrupted, Windows Won’t Be Able to Boot Up
Cause: EFI/UEFI boot loader gets corrupted or damaged.
Fix: Repair UEFI Bootloader for Windows 11
Error 4: Want to Restart Unbootable or Dead Computer with UEFI Bootable Disk
Cause: Computer can’t boot due to virus attack, MBR damage, bad sector, or corrupted system files.
Fix: Create UEFI Bootable USB and Fix PC Unbootable Error
If you have further computer boot issues caused by UEFI or other reasons, relax. You can directly customize tech support service to help you fix computer not booting or computer not turning on issues with success.
29 апреля 2025
Что такое EFI / UEFI ?
Как только мы включаем компьютер, в нем немедленно начинает работать миниатюрная операционная система, которую мы знаем как BIOS. Она занимается тестированием устройств, памяти, загрузкой операционных систем, распределением ресурсов аппаратуры. Многие функции этого набора программ (их объем обычно около 256-512 Кб) позволяют поддерживать старые операционные системы вроде MS-DOS, предоставляя им множество возможностей. Со времен PC/AT-8086 BIOS менялся очень мало, а ко времени запуска первых Пентиумов его развитие почти остановилось. Собственно, менять в нем стало нечего, кроме двойного BIOS, поддержки сетевых средств и возможности перепрошивки. А вот минусов стало много: стартовый вход в реальный режим процессора, 16-разрядная адресация и 1 Мб доступной памяти, невозможность иметь «ремонтную» консоль. И, конечно, вечная проблема поддержки жестких дисков. Даже сейчас гарантированно поддерживаются диски до 2,2 Тб, не более.
Компания Intel еще в 2005 года решила поменять BIOS на EFI/UEFI (Unified Extensible Firmware Interface). Система EFI — более продвинутая базовая операционная система. На некоторых платформах Unix и Windows UEFI уже давно работает, но массового перехода пока не свершилось, несмотря на благие намерения. А они таковы:
- Наличие пресловутой консоли для ремонта системных параметров и установки ОС;
- Раздел EFI даёт возможность совершать некоторые действия, не загружая ОС (просмотр фильмов, запуск музыки);
- Вход в Интернет и, следовательно, наличие установленных драйверов сети, стека TCP/IP и т.д.);
- Присутствие графического режима и пользовательских скриптов;
- Поддержка гигантских по объему дисков;
- Хранение UEFI на разделах нового формата (GPT);
- Полная поддержка всей аппаратуры с момента старта.
UEFI может использовать универсальную исполняющую машину вроде JVM для использования аппаратно-независимого кода, а это открывает огромные горизонты для создания «загрузочного» ПО.
Существует и критика этой технологии. В частности, внедрение ее может привести к отсечению от рынка операционных систем новых игроков: для этого всегда найдется в коде какая-нибудь технологическая лазейка. Как, например, невозможность загружать ОС Windows 98 из современных BIOS. Но, что хуже, придется забыть о миллионах программ MS-DOS и других систем, которые опирались в своей работе на функции BIOS. Возможно, они еще будут эмулироваться, но в этом есть сомнения. А среди них наверняка есть и важные программы, которые некому будет переписывать. Впрочем, все это решаемые вопросы – хотя бы за счет виртуальных операционных систем. Но вот то, что появятся новые виды вирусов – это точно, и мы сможем увидеть это довольно скоро.
Напомним, что специалисты «Serty-Service» готовы помочь в настройке BIOS.
# Основная информация
(U)EFI или (Унифицированный) Расширяемый Интерфейс микропрограммного обеспечения — это спецификация для платформ x86, x86-64, ARM и Itanium, которая определяет программный интерфейс между операционной системой и микропрограммным обеспечением платформы/BIOS. Оригинальный EFI был разработан в середине 1990-х годов компанией Intel для разработки встроенного ПО/BIOS для платформ Itanium. В 2005 году Intel передала спецификацию новой рабочей группе под названием Unified EFI Forum, состоящей из таких компаний, как AMD, Microsoft, Apple и сама Intel. Все современные ПК поставляются с прошивкой UEFI, UEFI широко поддерживается как коммерческими, так и операционными системами с открытым исходным кодом. Обратная совместимость предусмотрена для устаревших операционных систем.
# Основы UEFI
# Загрузка образов UEFI
Если вы используете VirtualBox для виртуализации, то UEFI уже включен, нет необходимости загружать образ вручную. Вам просто нужно включить его в настройках виртуальной машины, нажав флажок «Настройки» / «Системы» / «Включить EFI (только специальные операционные системы)».
В противном случае для эмуляции и виртуальных машин вам понадобится образ прошивки OVMF.fd. Это может быть сложно найти, поэтому вот несколько альтернативных ссылок для загрузки:
- TianoCore (opens new window)
- OVMF-blobs (opens new window)
- RPM packages (opens new window)
- Debian packages (opens new window)
- Gentoo packages (opens new window)
- Arch packages (opens new window)
В Linux вы также можете установить их с помощью диспетчера пакетов вашего дистрибутива, например:
# Debian / Ubuntu
# RedHat / CentOS
# macOS
Используйте репозиторий OVMF-blobs.
# Windows
Используйте репозиторий OVMF-blobs или загрузите RPM-версию, затем с помощью 7-Zip распакуйте файл OVMF.fd из загруженного архива.
# UEFI против BIOS
Распространенным заблуждением является то, что UEFI является заменой BIOS. На самом деле, как устаревшие материнские платы, так и материнские платы на основе UEFI поставляются с ПЗУ BIOS, которые содержат встроенное ПО, которое выполняет начальную настройку системы при включении питания, прежде чем загружать какой-либо сторонний код в память и переходить к нему. Различия между устаревшей прошивкой BIOS и прошивкой UEFI BIOS заключаются в том, где они находят этот код, как они готовят систему перед переходом к ней и какие удобные функции они предоставляют для вызова кода во время работы.
# Инициализация платформы
BIOS выполняет всю инициализацию платформы (конфигурация контроллера памяти, конфигурация шины PCI и BAR-mapping, инициализация видеокарты и т.д.), но затем переходит в обратно совместимую среду Real Mode. Загрузчик должен включить A20-gate, настроить GDT и IDT, переключиться в Protected Mode, а для процессоров x86-64 настроить подкачку и переключиться в Long Mode.
Прошивка UEFI выполняет те же шаги, но также подготавливает среду Protected Mode с плоской сегментацией, а для процессоров x86-64-среду Long mode с отображением идентификаторов подкачки. A20-gate также включён.
Кроме того, процедура инициализации платформы прошивки UEFI стандартизирована. Это позволяет распространять прошивку UEFI независимо от поставщика платы.
# Механизм загрузки
BIOS загружает 512-байтовый двоичный объект из загрузочного устройства типа MBR(Master Boot Record) в память по физическому адресу 7C00 и переходит к нему. Загрузчик не может вернуться обратно в BIOS. Прошивка UEFI загружает приложение UEFI произвольного размера (исполняемый файл PE) из раздела FAT на загрузочном устройстве с разделом GPT на некоторый адрес, выбранный во время выполнения. Затем он вызывает основную точку входа этого приложения. Приложение может вернуть управление встроенному ПО, которое продолжит поиск другого загрузочного устройства или вызовет меню диагностики.
# Обнаружение системы
BIOS сканирует память на наличие таких структур, как таблицы EBDA, SMBIOS и ACPI. Он использует PIO для связи с корневым контроллером PCI и сканирования шины PCI. Возможно, что в памяти могут присутствовать избыточные таблицы (например, таблица MP в SMBIOS содержит информацию, которая также присутствует в DSDT ACPI), и загрузчик может выбрать, какие из них использовать.
Когда UEFI вызывает функцию точки входа UEFI-приложения, она передает структуру «Системной таблицы», которая содержит указатели на все таблицы ACPI системы, карту памяти и другую информацию, относящуюся к ОС. Устаревшие таблицы (например, SMBIOS) могут отсутствовать в памяти.
# Удобные функции
BIOS подключает различные прерывания, которые загрузчик может запускать для доступа к системным ресурсам, таким как диски и экран. Эти прерывания не стандартизированы, за исключением исторических условностей. Каждое прерывание использует другое для передачи регистра.
UEFI устанавливает в памяти множество вызываемых функций, которые группируются в наборы, называемые «протоколами», и которые можно обнаружить через системную таблицу. Поведение каждой функции в каждом протоколе определяется спецификацией. Приложения UEFI могут определять свои собственные протоколы и сохранять их в памяти для использования другими UEFI-приложениями. Функции вызываются с помощью стандартизированного, современного стандарта системных вызовов, поддерживаемого многими компиляторами языка C.
# Среда разработки
Устаревшие загрузчики могут быть разработаны в любой среде, которая может генерировать двоичные образы: NASM, GCC и т.д. Приложения UEFI могут быть разработаны на любом языке, который может быть скомпилирован и связан в исполняемый файл PE и поддерживает соответствующие вызовы, используемые для доступа к функциям, установленным в памяти прошивкой UEFI. На практике это означает одну из двух сред разработки: Intel TianoCore EDK2, GNU-EFI или POSIX-UEFI.
TianoCore — это большая, сложная среда с собственной системой сборки. Его можно настроить для использования вместе с GCC, MinGW, Microsoft Visual C++ и т.д. Его можно использовать не только для компиляции UEFI-приложений, но и для компиляции прошивки UEFI, которая будет перенесена в ПЗУ BIOS.
GNU-EFI — это набор библиотек и заголовков для компиляции приложений UEFI с собственным GCC системы (не работает с LLVM CLang). Он не может быть использован для компиляции прошивки UEFI. Поскольку это всего лишь пара библиотек, с которыми можно связать UEFI-приложение, его гораздо проще использовать, чем TianoCore.
POSIX-UEFI очень похож на GNU-EFI, но он распространяется в основном как исходный код, а не как двоичная библиотека, имеет имена, подобные ANSI C, и работает с GCC, а также с LLVM CLang. Он поставляется с файлом Makefile.
# Эмуляция
Bochs поставляется с BIOS с открытым исходным кодом по умолчанию. Кроме того, SeaBIOS, популярный BIOS, который был портирован как на эмулированные машины Bochs, так и на машины с эмуляцией QEMU. Оба этих BIOSs реализуют большинство функций BIOS, которые можно было бы ожидать. Тем не менее, они довольно значительно отличаются по эксплуатации от коммерческих BIOS на реальных машинах.
OVMF, популярная прошивка UEFI с открытым исходным кодом, была перенесена на эмулируемую машину QEMU (но не Bochs). Поскольку он реализует спецификацию UEFI, он ведет себя очень похоже на коммерческую прошивку UEFI на реальных машинах. (Сам OVMF построен с помощью TianoCore, но доступны готовые образы.)
# Загрузчик BIOS или приложение для UEFI?
Если вы ориентируетесь на устаревшие системы, для которых UEFI недоступен или ненадежен, вам следует разработать загрузчик для BIOS. Это требует глубокого знания 16-битной адресации и функций обратной совместимости процессора x86 или x86-64. Если вы ориентируетесь на современные системы, вам следует разработать UEFI-приложение. Многие прошивки UEFI могут быть сконфигурированы для эмуляции BIOS, но среди этих эмулируемых сред существует еще больше различий, чем среди реальных BIOS.
# UEFI 0-3 класса и CSM
ПК классифицируются как класс UEFI 0, 1, 2 или 3. Машина класса 0-это устаревшая система с BIOS, т.е. Вообще не система UEFI.
Машина класса 1 — это система с UEFI, которая работает исключительно в режиме модуля поддержки совместимости (CSM). CSM — это спецификация того, как прошивка UEFI может эмулировать устаревший BIOS. Прошивка UEFI в режиме CSM загружает Legacy-загрузчики. Система UEFI класса 1 может вообще не декларировать поддержку UEFI, поскольку она не доступна загрузчику. Это только UEFI «внутри» BIOS.
Машина класса 2 — это система UEFI, которая может запускать UEFI-приложения, но также включает в себя возможность запуска в режиме CSM. Большинство современных ПК — это машины класса UEFI 2. Иногда выбор для запуска UEFI-приложений против CSM — это тот или иной параметр в конфигурации BIOS, и в других случаях BIOS решит, какой из них использовать, после выбора загрузочного устройства и проверки того, у него Legacy-загрузчик или UEFI-приложение.
Машина класса 3 — это система UEFI, которая не поддерживает CSM. Машины класса 3 UEFI запускают только UEFI-приложения и не реализуют CSM для обратной совместимости с Legacy-загрузчиками.
# Безопасная загрузка (Secure Boot)
Безопасная загрузка — это схема цифровой подписи для приложений UEFI, состоящая из четырех компонентов:
- PK: Ключ платформы
- KEK: Ключ для обмена ключей
- db: Белый список
- dbx: Чёрный список
Прошивка UEFI, поддерживающая безопасную загрузку, всегда находится в одном из трех состояний:
- Setup mode, Secure Boot off
- User mode, Secure Boot off
- User mode, Secure Boot on
В режиме настройки любое приложение UEFI может изменять или удалять PK, добавлять/удалять ключи из KEK, а также добавлять/удалять записи белого списка или черного списка из db или dbx.
В пользовательском режиме, независимо от того, включена или выключена Безопасная загрузка:
- PK может быть изменен или удален только приложением UEFI, у которого уже есть текущий PK.
- Ключи могут быть добавлены/удалены из KEK только приложением UEFI, имеющим PK.
- Записи белого списка и черного списка могут быть добавлены/удалены из db и dbx только приложением UEFI, у которого есть любой из ключей в KEK.
Наконец, в пользовательском режиме с включенной безопасной загрузкой приложения UEFI должны соответствовать одному из следующих четырех требований для запуска:
- Подписано, с подписью в db, а не в dbx
- Подписано ключом в db, а не в dbx
- Подписано ключом в КЕК
- Не подписано, но хэш приложения находится в db, а не в dbx
Обратите внимание, что приложения UEFI не подписываются PK, если только PK также не находится в KEK.
Не все прошивки UEFI поддерживают безопасную загрузку, хотя это является обязательным требованием для Windows 8. Некоторые прошивки UEFI поддерживают безопасную загрузку, и нет возможности отключить их, что создает проблему для независимых разработчиков, которые не имеют доступа к PK или любому из ключей в KEK и, следовательно, не могут установить свой собственный ключ или подпись приложения или хэш в базу данных белого списка. Независимые разработчики должны разрабатывать используя системы, которые либо не поддерживают безопасную загрузку, либо имеют возможность отключить безопасную загрузку.
# Как использовать UEFI
Традиционные операционные системы, такие как Windows и Linux, имеют существующую программную архитектуру и большую базу кода для выполнения конфигурации системы и обнаружения устройств. С их сложными уровнями абстракции они не получают прямой выгоды от UEFI. В результате их загрузчики UEFI мало что делают, кроме подготовки среды для их запуска.
Независимый разработчик может найти больше пользы в использовании UEFI для написания полнофункциональных приложений UEFI, а не в том, чтобы рассматривать UEFI как временную среду запуска, которую можно выбросить во время процесса загрузки. В отличие от устаревших загрузчиков, которые обычно взаимодействуют с BIOS только для запуска ОС, приложение UEFI может реализовать сложное поведение с помощью UEFI. Другими словами, независимый разработчик не должен спешить покидать «UEFI-land».
Хорошей отправной точкой является написание приложения UEFI, которое использует системную таблицу для извлечения карты памяти и использует протокол «File» для чтения файлов с дисков в формате FAT. Следующим шагом может быть использование системной таблицы для поиска таблиц ACPI.
# Разработка с POSIX-UEFI
Простой способ компиляции приложений EFI в Linux (или любой другой системе, совместимой с POSIX) — это POSIX-UEFI. Он не только предоставляет хорошо известный libc-подобный API для вашего приложения EFI, но и генерирует Makefile, который поможет обнаружить и настроить набор инструментов для вас. Работает как с GNU gcc, так и с LLVM CLang.
Он имеет POSIX-измененные типы (например, uintn_t вместо UINTN), и ему не нужны стандартные заголовки EFI. Но если вы установите их из EDK2 или GNU-EFI, вы также сможете безопасно включить их, конфликтов имен не будет. Тем не менее, эти интерфейсы правильно определены, и все поля имеют точно такое же имя, как и в EDK2, так что это большое преимущество перед GNU-EFI.
Типичный «Hello World» на UEFI выглядит примерно так:
А Makefile выглядит вот так:
Теперь просто запусти сборку командой make и на выходе получишь файл main.efi
# Разработка с GNU-EFI
GNU-EFI можно использовать для разработки как 32-разрядных, так и 64-разрядных приложений UEFI. В этом разделе будут рассмотрены только 64-разрядные приложения UEFI и предполагается, что сама среда разработки работает в системе x86_64, поэтому кросс-компилятор не требуется.
GNU-EFI включает в себя следующие вещи:
- crt0-efi-x86_64.o: CRT0 (код инициализации среды выполнения C), обеспечивающий точку входа, которую микропрограмма UEFI вызовет при запуске приложения, которое, в свою очередь, вызовет функцию «efi_main», записанную разработчиком.
- libgnuefi.a: Библиотека, содержащая одну функцию (_relocate), которая используется CRT0.
- elf_x86_64_efi.lds: Скрипт компоновщика, используемый для связывания двоичных файлов ELF в приложения UEFI.
- efi.h и другие заголовки: Удобные заголовки, которые предоставляют структуры, типы и константы, улучшают читаемость при доступе к системной таблице и другим ресурсам UEFI.
- libefi.a: Библиотека, содержащая удобные функции, такие как вычисление CRC, вычисление длины строки и простая печать текста.
- efilib.h: Заголовок для libefi.a.
Как минимум, 64-разрядное приложение UEFI должно будет связываться с crt0-efi-x86_64.o и libgnuefi.a с помощью скрипта компоновщика elf_x86_64_efi.lds. Скорее всего, вы захотите также использовать предоставленные заголовки и библиотеки удобства, и в этом разделе предполагается, что и в дальнейшем.
Типичный «Hello World» на UEFI выглядит примерно так:
Несколько заметок:
- efi.h включен, поэтому мы можем использовать такие типы, как EFI_STATUS, EFI_HANDLE и EFI_SYSTEM_TABLE.
- При создании 32-разрядного приложения UEFI EFIAPI пуст; GCC скомпилирует функцию «efi_main», используя стандартные вызовы C. При создании 64-разрядного приложения UEFI EFIAPI расширяется до «attribute((ms_abi))», и GCC скомпилирует функцию «efi_main», используя стандарт о вызовах Microsoft x64, как указано в UEFI. Только функции, которые будут вызываться непосредственно из UEFI (включая main, но также и обратные вызовы), должны использовать стандарт о вызовах UEFI.
- «InitializeLib» и «Print» — это удобные функции, предоставляемые libefi.a с прототипами в efilib.h. «InitializeLib» позволяет libefi.a хранить ссылку на ImageHandle и SystemTable, предоставляемые BIOS. «Print» использует эти сохраненные ссылки для вывода строки, обращаясь к функциям, предоставляемым UEFI в памяти. (Позже мы увидим, как найти и вызвать функции, предоставляемые UEFI, вручную.)
Программа скомпилированна и слинкована как показано ниже:
В результате вы получите файл main.efi, которые будет весить 44 КБ.
# Эмуляция с QEMU и OVMF
Любой последней версии QEMU с последней версией OVMF будет достаточно для запуска приложения UEFI. Исполняемые файлы QEMU доступны для многих платформ, а образ OVMF (OVMF.fd) можно найти на веб-сайте TianoCore. QEMU (без загрузочного диска) можно вызвать, как показано ниже. Чтобы предотвратить попытку загрузки по PXE (сети) в последних версиях QEMU при отсутствии загрузочного диска, используйте -net none.
Рекомендуется использовать OVMF (для QEMU 1.6 или новее) с параметром pflash. В приведенных ниже инструкциях предполагается, что у вас есть образ OVMF, разделённый на отдельные разделы CODE и VARS.
Если вы предпочитаете работать через терминал или через SSH/telnet, вы можете запустить QEMU без графической поддержки, используя флаг -nographic.
Если OVMF не найдет загрузочный диск с правильно названным приложением UEFI (подробнее об этом позже), он попадет в оболочку UEFI.
Вы можете просмотреть список доступных команд с помощью команды help.
# Создание образа диска
Чтобы запустить приложение UEFI, вам нужно будет создать образ диска и представить его в QEMU. Прошивка UEFI ожидает, что приложения UEFI будут храниться в файловой системе FAT12, FAT16 или FAT32 (называемой системным разделом EFI) на диске с разделением GPT. Многие прошивки поддерживают только FAT32, так что это то, что вы захотите использовать. В зависимости от вашей платформы существует несколько различных способов создания образа диска, содержащего ваше приложение UEFI, но все они начинаются с создания обнуленного файла образа диска. Минимальный размер раздела FAT32 составляет 33 548 800 байт, плюс вам понадобится место для первичной и вторичной таблиц GPT, а также некоторое свободное пространство, чтобы раздел можно было правильно выровнять. В этих примерах мы создадим образ диска размером 48 000 000 байт (93750 512-байтовых секторов или 48 МБ).
# Приложение uefi-run
Приложение uefi-run полезно для быстрого тестирования. Оно создает временный образ FAT, содержащий ваше приложение EFI, и запускает qemu.
uefi-run в настоящее время не собран для какого-либо дистрибутива. Вы можете установить его с помощью cargo (менеджер пакетов Rust) («cargo install uefi-run»).
# Linux, необходим root-доступ
Этот подход требует root-доступ и использует gdisk, losetup и mkdosfs.
Во-первых, используйте gdisk для создания таблицы разделов GPT с одним системным разделом EFI.
Теперь у вас есть образ диска с таблицей разделов GUID и неформатированный раздел EFI, начиная с сектора 2048. Если вы не отклонились от команд, показанных выше, образ диска будет использовать 512-байтовые секторы, поэтому раздел EFI начинается с байта 1 048 576 и имеет длину 46 934 528 байт.
Используйте losetup для представления раздела в Linux.
(Если /dev/loop0 уже используется, вам нужно будет выбрать другое loopback-устройство.)
Отформатируйте раздел в FAT32 с помощью mkdosfs.
Теперь раздел можно смонтировать, чтобы мы могли копировать в него файлы. В этом примере мы используем каталог «/mnt», но вы также можете создать локальный каталог для временного использования.
Скопируйте все приложения UEFI, которые вы хотите протестировать, в файловую систему.
Наконец, размонтируйте раздел и освободите loopback-устройство.
uefi.img теперь представляет собой образ диска, содержащий первичные и вторичные таблицы GPT, содержащие один раздел типа EFI, содержащий файловую систему FAT32, содержащую одно или несколько приложений UEFI.
# Linux, без root-доступа
Этот подход использует parted, mformat, mcopy и может выполняться с правами пользователя.
Во-первых, используйте parted для создания первичных и вторичных заголовков GPT, а также одного раздела EFI, охватывающего тот же диапазон, что и описанный выше подход.
Теперь создайте новый временный файл образа, который будет содержать данные раздела EFI, и используйте mformat для форматирования его с помощью FAT16.
Используйте mcopy для копирования любых приложений UEFI, которые вы хотите протестировать, в файловую систему.
Наконец, запишите образ раздела в образ основного диска.
uefi.img теперь представляет собой образ диска, содержащий первичные и вторичные таблицы GPT, содержащие один раздел типа EFI, содержащий файловую систему FAT16, содержащую одно или несколько приложений UEFI.
# FreeBSD, требуется root-доступ
Этот подход требует привилегий root и использует mdconfig, gpart, newfs_msdos и mount_msdosfs.
Сначала создайте узел устройства, который представляет обнуленный образ диска в виде блочного устройства. Это позволит нам работать над ним, используя стандартные инструменты разделения и форматирования.
В этом примере новым блочным устройством является md0. Теперь создайте пустые первичные и вторичные таблицы GPT на устройстве.
Теперь мы можем добавить раздел на диск. Мы укажем раздел «EFI», что просто означает, что GPT установит GUID этого раздела для специального типа «EFI». Не все BIOS требуют этого, и раздел по-прежнему можно будет монтировать и просматривать в обычном режиме в Linux, FreeBSD и Windows.
Затем создайте файловую систему FAT16 на новом разделе. Вы можете указать различные параметры для файловой системы, если хотите, но это не обязательно. В идеале вы бы создали раздел FAT32 для лучшей совместимости прошивки, но FreeBSD, похоже, создает разделы FAT32, которые OVMF не может прочитать.
Теперь раздел можно смонтировать, чтобы мы могли копировать в него файлы. В этом примере мы используем каталог /mnt, но вы также можете создать локальный каталог для временного использования.
Скопируйте все приложения UEFI, которые вы хотите протестировать, в файловую систему.
Наконец, размонтируйте раздел и освободите устройство.
uefi.img теперь представляет собой образ диска, содержащий первичные и вторичные таблицы GPT, содержащие один раздел типа EFI, содержащий файловую систему FAT16, содержащую одно или несколько приложений UEFI.
# macOS, не требуется root-доступ
В Mac OS есть один инструмент (hdiutil), который одновременно создает образ диска и копирует файлы.
Допустим, вы создаете UEFI для x86_64. По определению имя файла должно быть BOOTX64.EFI и этот файл должны находиться в папке /EFI/BOOT.
Во-первых, давайте создадим временную папку, которая будет содержать все файлы и папки, необходимые для загрузки UEFI.
Во-вторых, давайте скопируем приложение в нужную директорию:
Наконец, давайте создадим образ диска, разделенный GPT, отформатированный с помощью fat32 (-fs fat32), при необходимости переопределим файл назначения (-ov), определим размер диска (-размер 48m), имя тома (-volname NEWOS), формат файла, в котором будет закодирован диск (-формат UDTO — тот же, что используется для DVD/CD), и исходную папку, содержащую файлы, которые будут скопированы на новый диск:
uefi.cdr готов к использованию в QEMU.
# Запуск UEFI-приложений
Как только ваш образ диска будет готов, вы можете вызвать QEMU, как показано ниже.
Когда OVMF попадет в оболочку UEFI, вы увидите дополнительную запись в «Mapping table» с пометкой «FS0». Это указывает на то, что прошивка обнаружила диск, обнаружила раздел и смогла смонтировать файловую систему. Вы можете изучить файловую систему, переключившись на нее с помощью синтаксиса в стиле DOS «FS0:», как показано ниже.
Вы можете запустить приложение UEFI, введя его имя.
Обратите внимание, что оболочка UEFI возобновилась после завершения работы приложения. Конечно, если бы это был правильный загрузчик, он никогда бы не возобновился, а скорее запустил ОС.
Некоторые коммерческие прошивки UEFI предоставляют оболочки UEFI или возможность запуска выбранных пользователем приложений UEFI, таких как прошивка, поставляемая с линейкой ноутбуков HP EliteBook. Однако большинство из них не предоставляют эту функциональность конечному пользователю.
# Отладка
OVMF может быть построен в режиме отладки, и он будет выводить сообщения журнала на порт ввода-вывода 0x402. Вы можете использовать некоторые флаги, подобные приведенным ниже, для захвата выходных данных.
Обратите внимание, что релизные сборки не будут выводить отладочные сообщения или будут иметь уменьшенный вывод.
# Запуск на реальном железе
# NVRAM переменные
Прошивка UEFI представит большинство своих параметров конфигурации через текстовое или графическое меню конфигурации, как и BIOS. Выбор, сделанный в этих меню, сохраняется в чипе NVRAM между перезагрузками. Однако, в отличие от BIOS, разработчик прошивки имеет возможность предоставить некоторые или все эти «переменные NVRAM» операционной системе и конечному пользователю с помощью удобных функций, размещенных в оперативной памяти прошивкой при загрузке.
Модуль ядра Linux efivarfs будет использовать эти функции для перечисления переменных NVRAM в файле /sys/firmware/efi/efivars. Переменные NVRAM также могут быть сброшены из самой оболочки UEFI с помощью команды dmpstore. Порядок загрузки устройства всегда доступен через переменные NVRAM.
# Загружаемые UEFI-приложения
Переменные NVRAM порядка загрузки определяют, где прошивка будет искать приложения UEFI, которые будут запущены при загрузке. Хотя это можно изменить (например, установщик ОС может настроить загрузочную запись для жесткого диска, на который она была установлена), прошивка обычно ищет приложение UEFI с именем «BOOT.efi» (для 32-разрядных приложений) или «BOOTX64.efi» (для 64-разрядных приложений), хранящееся в пути «/EFI/BOOT» в файловой системе загрузочного устройства. Это путь и имя по умолчанию для OVMF.
В отличие от приложения UEFI, запущенного из оболочки, если загрузочное приложение UEFI возвращает в BIOS, оно продолжит поиск других загрузочных устройств.
# Открытая функциональность
Реальные ПК различаются по объему возможностей UEFI, которые они предоставляют пользователю. Например, даже машина класса 3 может не упоминать UEFI в своей конфигурации BIOS и не предлагать оболочку UEFI. Кроме того, некоторые поставщики BIOS делают свои экраны конфигурации прошивки UEFI идентичными экранам конфигурации BIOS. Машины класса 2 могут представлять несколько запутанные меню загрузки и параметры конфигурации. Например, один производитель ноутбуков включает параметр конфигурации для включения/отключения UEFI (т.е. Переключения между поведением UEFI и CSM) под названием «OS: Windows 8». Другой ноутбук, если ему не удастся найти загрузочное приложение UEFI на выбранном загрузочном устройстве (или если это приложение вернет состояние, отличное от EFI_SUCCESS), вернется к поведению CSM, а затем пожалуется, что на диске поврежден MBR.
Чтобы упростить тестирование на реальном оборудовании, вы можете установить загрузочное приложение UEFI на внутренний жесткий диск системы, которое предоставляет меню загрузки, например rEFInd. Это также может быть удобно для сценариев с несколькими загрузками.
# Разработчики прошивки для ПК
На платформах x86 и x86-64 следующие разработчики BIOS предлагают прошивку UEFI:
- AMI (Aptio).
- Phoenix (SecureCore, TrustedCore, AwardCore).
- Insyde (InsydeH20).
# Системы Apple
Системы Apple реализуют EFI 1.0, в отличие от UEFI, с тем отличием, что приложения UEFI загружаются из файловых систем HFS+ вместо FAT12/16/32. Кроме того, эти приложения UEFI должны быть «подписаны» (либо непосредственно, либо путем нахождения в подписанном каталоге) для загрузки. Blessing устанавливает флаги в файловой системе HFS+, которые проверяет прошивка Apple перед загрузкой приложения. Пакет hfsutils с открытым исходным кодом включает поддержку файлов в файловых системах HFS, но не каталогов и не HFS+.
# UEFI-приложения в деталях
# Бинарный формат
Исполняемые файлы UEFI-это обычные образы PE32 / PE32+ (Windows x32 / x64) с определенной подсистемой. Каждое приложение UEFI в основном представляет собой исполняемый файл Windows (или DLL) без таблиц символов.
Типы UEFI-образов
Тип | Описание | Подсистема |
---|---|---|
Приложения | Загрузчики ОС и другие утилиты. | 10 |
Драйвер службы загрузки | Драйверы, используемые встроенным ПО при загрузке (например, драйверы дисков, сетевые драйверы). | 11 |
Драйвер среды выполнения | Драйверы, которые могут оставаться загруженными даже после загрузки ОС и выхода из службы загрузки. | 11 |
Образы UEFI также должны указывать тип машинного кода, который они содержат. Загрузчик UEFI откажется загружать несовместимый образ.
Типы машин
Название | Значение |
---|---|
x86 | 0x014c |
x86_64 | 0x8664 |
Itanium x64 | 0x0200 |
UEFI Byte Code | 0x0EBC |
ARM | 0x01C2 |
AArch (ARM x64) | 0xAA64 |
RISC-V x32 | 0x5032 |
RISC-V x64 | 0x5064 |
RISC-V x128 | 0x5128 |
ARM означает, что вы можете использовать инструкции Thumb/Thumb 2, но интерфейсы UEFI находятся в режиме ARM.
# Инициализация
Приложения должны либо загрузить ОС и выйти из служб загрузки, либо вернуться из основной функции (в этом случае загрузчик будет искать следующее загружаемое приложение).
Драйверы должны инициализироваться, а затем возвращать 0 при успешном выполнении или код ошибки. Компьютер может не загрузиться, если не загрузится необходимый драйвер.
# Память
Карта памяти, возвращаемая UEFI, будет отмечать области памяти, используемые драйверами.
После завершения загрузки ОС ядру разрешается повторно использовать память, в которую был загружен загрузчик.
Типы памяти — Efi{Loader/BootServices/RuntimeServices}{Code/Data}.
После выхода из служб загрузки вы можете повторно использовать любую память, доступную только для чтения, которую использовали драйверы загрузки.
Однако память, используемая драйверами среды выполнения, никогда не должна быть затронута — драйверы среды выполнения остаются активными и загруженными до тех пор, пока работает компьютер.
Один из способов увидеть разбивку PE-файла, содержащего приложение UEFI, — это
Его выход довольно длинный. Среди прочего, он показывает подсистему, то есть тип образа UEFI, упомянутый ранее.
# Соглашение о вызовах
UEFI определяет следующие соглашения о вызовах:
- cdecl для x86 UEFI-функций
- Microsoft’s 64-bit calling convention для x86-64 UEFI-функций
- SMC для ARM UEFI-функций
Это оказывает два влияния на разработчиков приложений UEFI:
- Основная точка входа приложения UEFI должна ожидать вызова с соответствующим соглашением о вызове.
- Любые функции, предоставляемые UEFI, которые вызывает приложение UEFI, должны вызываться с соответствующим соглашением о вызовах.
Обратите внимание, что функции, строго внутренние для приложения, могут использовать любое соглашение о вызовах, которое выберет разработчик.
# POSIX-UEFI, GNU-EFI and GCC
cdecl — это стандартное соглашение о вызовах, используемое GCC, поэтому для записи основной точки входа или вызова функций UEFI в приложении UEFI x86, разработанном с использованием GNU-EFI, не требуется никаких специальных атрибутов или модификаторов. Однако для x86-64 функция точки входа должна быть объявлена с модификатором «attribute((ms_abi))», и все вызовы функций, предоставляемых UEFI, должны выполняться через функцию «uefi_call_wrapper». Этот преобразователь вызывается с помощью cdecl, но затем преобразуется в соглашение о вызове Microsoft x86-64 перед вызовом запрошенной функции UEFI. Это необходимо, поскольку более старые версии GCC не поддерживают указание соглашений о вызовах для указателей функций.
Для POSIX-UEFI, который также использует GCC, ваша точка входа выглядит как стандартная main(), и никакого специального ABI не требуется. Кроме того, среда сборки заботится о флагах компилятора для вас, поэтому вы можете просто вызывать функции UEFI без «uefi_call_wrapper», независимо от того, используете ли вы gcc или другой кросс-компилятор.
Для удобства разработчиков как POSIX-UEFI, так и GNU-EFI предоставляют макрос «EFIAPI», который расширяется до «cdecl» при таргетинге на x86 и «attribute(ms_abi))» при таргетинге на x86-64. Кроме того, функция «uefi_call_wrapper» просто передаст вызов на x86. Это позволяет использовать один и тот же исходный код для x86 и x86-64. Например, следующая основная функция будет компилироваться с правильным соглашением о вызове как на x86, так и на x86-64, и вызов через функцию «uefi_call_wrapper» выберет правильное соглашение о вызове для использования при вызове функции UEFI (в данном случае вывод строки).
# Биндинги языка
Приложения UEFI обычно пишутся на языке C, хотя биндинги могут быть написаны для любого другого языка, который компилируется в машинный код. Assembler также является опцией; для FASM доступен файл uefi.inc, который позволяет писать приложения UEFI, как показано ниже.
Поскольку приложение UEFI содержит обычный машинный код x86 или x86-64, inline assembly также является опцией в компиляторах, которые ее поддерживают.
# EFI байткод
UEFI также включает спецификацию виртуальной машины, основанную на формате байтового кода, называемом EFI Byte Code (EBC), который может использоваться для написания независимых от платформы драйверов устройств, но не приложений UEFI. По состоянию на 2015 год использование EBC было ограниченным.
# Основные проблемы
# Мое приложение UEFI зависает/сбрасывается примерно через 5 минут
Когда управление передается вашему приложению UEFI с помощью встроенного ПО, оно устанавливает таймер на 5 минут, после чего встроенное ПО повторно активируется, поскольку предполагается, что ваше приложение зависло. Прошивка в этом случае обычно пытается сбросить систему (хотя прошивка OVMF в VirtualBox просто приводит к тому, что экран становится черным и зависает). Чтобы противодействовать этому, вам необходимо обновить таймер до истечения времени ожидания. Кроме того, вы можете полностью отключить его с помощью такого кода, как
Очевидно, что это не проблема для большинства загрузчиков, но может вызвать проблему, если у вас есть интерактивный загрузчик, который ожидает ввода пользователя.
# Мой загрузчик зависает, если я использую определенные пользователем значения EFI_MEMORY_TYPE
Для функций управления памятью в EFI ОС должна иметься возможность использовать значения «тип памяти» выше 0x80000000 для своих собственных целей. В выпуске прошивки OVFM EFI «r11337» (для Qemu и т.д.) Есть ошибка, при которой прошивка предполагает, что тип памяти находится в диапазоне значений, определенных для собственного использования EFI, и использует тип памяти в качестве индекса массива. Конечным результатом является ошибка «array index out of bounds»»; где более высокие значения типа памяти (например, разрешённые значения выше 0x80000000) приводят к сбою 64-разрядной версии прошивки (page fault) и приводят к тому, что 32-разрядная версия прошивки сообщает о неправильных значениях «attribute». Эта же ошибка также присутствует в любой версии прошивки EFI, используемой VirtualBox (которая выглядит как более старая версия OVFM); и я подозреваю (но не знаю), что ошибка может присутствовать в самых разнообразных прошивках, которые были получены из проекта TianoCore (а не только OVFM).
# Внешние ссылки
- UEFI Specifications (opens new window)
- Intel TianoCore EDK2 (opens new window)
- OVMF firmware images (opens new window)
- Phoenix UEFI Wiki (opens new window)
- Sereval articles about UEFI (opens new window)
- PE specification covering the (U)EFI binary format (opens new window)
- Blog about UEFI, with bits about UEFI development (opens new window)
- Presentation guiding through simple UEFI application setup (opens new window)
- Presentation giving an overview of windows uefi booting (opens new window)
- POSIX-UEFI (opens new window)
- Wikipedia Article on EFI (opens new window)
Уровень сложностиСредний
Время на прочтение17 мин
Количество просмотров16K
Вы когда-нибудь задумывались, что происходит, когда вы нажимаете кнопку питания на компьютере? За той краткой паузой, прежде чем экран загорится, скрывается сложный процесс. В этой статье мы погрузимся в увлекательный мир прошивок (firmware) и исследуем, как разные компоненты взаимодействуют во время загрузки системы. Поняв эти связи, вы получите четкое представление о том, как основные элементы приводят вашу систему в действие. Мы сосредоточимся на Intel архитектуре x86, хотя многие принципы применимы и к другим архитектурам.
Если вы пропустили первую часть нашей серии, прочитайте её для лучшего понимания темы. А теперь давайте раскроем тайны, скрытые за прошивкой.
Содержание
-
Определения
-
Общая архитектура прошивок
-
First-Stage Boot Loader (FSBL)
-
BIOS (POST фаза)
-
UEFI Platform Initialization (PI)
-
coreboot
-
Другие решения
-
-
Second-Stage Boot Loader (SSBL)
-
BIOS
-
UEFI
-
-
OS Boot Loader
Определения
Firmware (Прошивка): специализированный тип ПО, встроенный в аппаратное оборудование (hardware), который обеспечивает низкоуровневое управление и позволяет оборудованию правильно функционировать и взаимодействовать с другими компонентами системы.
Basic Input/Output System (BIOS): устаревшая прошивка (изначально созданная для IBM PC), ответственная за инициализацию оборудования после включения платформы. В наше время этот термин часто используется в общем смысле для обозначения полного набора прошивок.
Bootloader: общее название для прошивки, отвечающей за загрузку компьютера. Это современный концепт, заменяющий BIOS, часто представляет из себя фреймворк с кодом начальной загрузки для инициализации процессора и чипсета, а также интерфейсы для сторонних разработчиков (например, разработчиков материнской платы) для выполнения специфичной для платформы инициализации.
Payload: программное обеспечение, которое выполняется сразу после Bootloader’а. Это может быть second stage bootloader, операционная система, BIOS/UEFI приложение и другое. Обычно она управляет процессом загрузки в соответствии с архитектурой прошивки.
Использование терминов BIOS и bootloader может быть запутанным, поскольку их значения зависят от контекста. Однако, когда говорят о firmware (прошивке), BIOS или bootloader, обычно имеют в виду полный набор прошивок, работающий между операционной системой и аппаратным оборудований.
EFI vs UEFI: Extensible Firmware Interface (EFI) это изначальная спецификация, разработанная компанией Intel. Unified Extensible Firmware Interface (UEFI) является преемником EFI, созданная UEFI Forum’ом для стандартизации и расширения исходной спецификации. Практически всегда EFI и UEFI используются взаимозаменяемо.
Общая архитектура прошивок
Чтобы понять как взаимодействуют компоненты прошивки, рассмотрим всю архитектуру и все ее взаимосвязанные части. Процесс загрузки, показанный на диаграмме ниже, начинается с reset vector, который является частью First-Stage Bootloader. Оттуда он проходит через различные стадии прошивки:
Firmware или BIOS обычно делится на две основные части с минимальным интерфейсом между ними:
-
Инициализация оборудования: Отвечает за инициализацию аппаратных компонентов системы.
-
Интерфейс к ОС и пользователю: Предоставляет необходимые интерфейсы для операционной системы и пользователя.
Проектирование прошивки платформы может быть монолитным, объединяя инициализацию оборудования и функциональность загрузки, или оно может следовать модульному и ступенчатому процессу загрузки. Выбор дизайна зависит от требований системы и может быть предпочтителен для определенных устройств.
Следующая диаграмма иллюстрирует, как различные компоненты прошивки взаимодействуют друг с другом и могут использоваться вместе для поддержки процесса загрузки (стрелки указывают последовательность выполнения):
Если эти диаграммы кажутся вам сложными, не переживайте. Посмотрите на них снова после прочтения статьи, и они станут понятнее.
First-Stage Boot Loader (FSBL)
Этот компонент прошивки предназначен для инициализации компьютеров и встроенных (embedded) систем с фокусом на минимальную инициализацию оборудования: выполнить только необходимое и затем передать управление Second-Stage Bootloader, чтобы загрузить операционную систему. FSBL не загружает операционные системы с накопителей отличных от флеш-памяти (flash chip). Поскольку он только инициализирует базовое оборудование и не работает с носителями загрузки, такими как жесткие диски, SSD или USB-флешки, для фактической загрузки операционной системы требуется другой компонент программного обеспечения.
Основные задачи FSBL:
-
Процессор: Переход с 16-битного Real Mode на 32-битный Protected Mode (или в Virtual 8086 mode в случае BIOS).
-
Использование кэша: Вызов FSP-T для настройки Cache-As-RAM для Си окружения.
-
Debug Port: Инициализация желаемоего debug port’а с помощью методов инициализации, специфичных для платы.
-
Инициализация памяти: Вызов FSP-M для инициализации основной памяти системы и сохранения важной информации о системной памяти.
-
GPIO: Настройка General-Purpose Input/Output (GPIO) контактов для взаимодействия с внешними устройствами.
-
Silicon: Ранняя инициализация платформы и использование FSP-S для завершения инициализации чипсета, процессора и контроллера ввода-вывода.
-
PCI Enumeration: Перечисление (enumerating) устройств PCI и распределение ресурсов, таких как адреса памяти и IRQs.
-
Подготовка к Payload: Настройка SMBIOS и ACPI таблиц, включая подготовку информации (coreboot tables, HOBs), необходимой для передачи управления в payload.
-
Передача управления: Нахождение, загрузка и передача управления payload’у.
BIOS (POST фаза)
В ранние дни компьютеров программное обеспечение с открытым исходным кодом не было широко популярным, и большинство реализаций BIOS были проприетарными. Существует лишь несколько доступных решений с открытым кодом, предоставляющих исходный код для POST фазы BIOS, такие как Super PC/Turbo XT BIOS и GLaBIOS. Эти проекты были разработаны для работы на системах IBM 5150/5155/5160 и большинстве XT клонов.
Однако более известные реализации BIOS с открытым исходным кодом, такие как OpenBIOS и SeaBIOS, не выполняют инициализацию оборудования, поскольку они не предназначены для работы на чистом оборудовании (bare hardware). Вместо этого они широко используются в качестве Second-Stage Bootloader’ов и работают в виртуальных средах, таких как QEMU и Bochs.
В любом случае, вам вряд ли придется работать непосредственно с этими ранними BIOSами или глубоко изучать их особенности. Но если вам интересно, упомянутые репозитории будут хорошей отправной точкой для изучения.
Что касается текущих тенденций в разработке, то, похоже, нет продолжающейся разработки проприетарных решений BIOS, и такие проекты стали устаревшими на фоне современных альтернатив.
UEFI Platform Initialization (PI)
Процесс загрузки следует поэтапной последовательности (staged flow), начиная с левого края и перемещаясь вправо на диаграмме ниже. Timeline процесса загрузки платформы делится на следующие фазы, как показано жёлтыми рамками:
-
Security (SEC): Первая фаза после reset vector. Основная функция этой фазы — настройка временной оперативной памяти (CPU Cache-As-RAM или SRAM).
-
Pre-EFI Initialization (PEI): Эта фаза запускает драйверы, называемые Pre-EFI Initialization Modules (PEIMs). Эти модули выполняют важные задачи по инициализации оборудования, такие как настройка CPU и чипсета, а также настройка основной памяти (DRAM).
-
Driver Execution Environment (DXE): В этой фазе выполняется остальная часть инициализации системы. Фаза DXE предоставляет UEFI сервисы и поддерживает различные протоколы и драйверы, необходимые для функционирования системы.
-
Boot Device Select (BDS): Эта фаза реализует политику загрузки платформы, определяя последовательность загрузки и выбирая подходящее загрузочное устройство.
-
Transient System Load (TSL): В этой фазе система запускает приложения, использующие UEFI сервисы, чтобы подготовить ОС к запуску. Это включает переход от среды UEFI к операционной системе и завершается
ExitBootServices()
вызовом. -
Run Time (RT): В этой фазе операционная система полностью функционирует, управляя системой под своим контролем.
-
After Life (AL): Эта фаза занимается сценариями, когда оборудование или ОС крашится / выключается / перезагружается. Прошивка может попытаться выполнить действия по восстановлению, однако спецификация UEFI PI не определяет конкретные требования или поведение для этой фазы.
Этот процесс и его фазы охватыватся в UEFI Platform Initialization (PI) Specification. Однако существует также UEFI Interface (обозначен жирной синей линией на рисунке), который не входит в предыдущий документ и описан в UEFI Specification. Несмотря на то что названия и частое использование UEFI могут сбивать с толку, эти два документа сфокусированы на разных аспектах:
-
UEFI PI Spec: Ориентирован на интерфейсы между низкоуровневыми компонентами прошивки и деталями того, как эти модули взаимодействуют для инициализации платформы.
-
UEFI Spec: Определяет интерфейсы для взаимодействия между операционной системой (OS) и прошивкой. Это будет рассмотрено более подробно в контексте Second-Stage Bootloader. При этом UEFI Specification опирается на PI Specification.
По сути, обе спецификации касаются интерфейсов, но на разных уровнях. Для детальной информации вы можете получить доступ к обеим спецификациям на официальном сайте UEFI Forum.
UEFI PI изначально был разработан как универсальное решение для firmware, не учитывая различие между first-stage и second-stage bootloader’ами. Однако когда мы говорим о UEFI как о First-Stage Bootloader, это включает фазы SEC, PEI и early DXE. Причина, по которой мы делим DXE на early и late стадии, заключается в их различных ролях в процессе инициализации.
В early DXE фазе драйверы обычно выполняют основную инициализацию CPU/PCH/материнской платы и также создают DXE Architectural Protocols (APs), которые помогают изолировать фазу DXE от аппаратного оборудования платформы. APs инкапсулируют детали, специфичные для платформы, позволяя late DXE фазе работать независимо от специфики аппаратного оборудования.
Coreboot
Подробные статьи о том, как работает Coreboot, будут выпущены в ближайшее время. Подписывайтесь на мои социальные сети — они будут опубликованы очень скоро!
Другие решения
-
Intel Slim Bootloader (SBL): first-stage bootloader, который обеспечивает только инициализацию основных аппаратных компонентов, после чего загружает payload. Однако он работает только на Intel x86 платформах и не поддерживает AMD x86 или другие архитектуры.
-
Das U-Boot: как first-stage, так и second-stage bootloader. Однако поддержка загрузки напрямую с x86 reset vector платформы (известного как bare mode) ограничена по сравнению с другими прошивками. Он более популярен во встроенных (embedded) системах и устройствах на базе ARM. Как second-stage bootloader, U-Boot реализует часть спецификации UEFI, но с фокусом на встроенные системы.
Second-Stage Boot Loader (SSBL)
После завершения начальной инициализации hardware, на сцену выходит second-stage bootloader. Его основная задача — создать программный интерфейс между операционной системой и прошивкой платформы через который ОС могла управлять системными ресурсами и взаимодействовать с аппаратными компонентами. SSBL стремится максимально скрыть различия в аппаратном оборудовании, упрощая разработку ОС и приложений. Эта абстракция позволяет разработчикам сосредоточиться на функционале более высокого уровня, не беспокоясь о различиях в аппаратных компонентах.
Основные задачи SSBL:
-
Получение информации о платформе: Извлечение информации о платформе от First-Stage Bootloader, включая memory mapping, SMBIOS, ACPI таблицы, SPI флеш-память.
-
Запуск независимых от платформы драйверов: Включает драйверы для SMM, SPI, PCI, SCSI/ATA/IDE/DISK, USB, ACPI, сетевых интерфейсов и так далее.
-
Реализация сервисов (aka интерфейса): Обеспечивает набор сервисов, упрощающих коммуникацию между операционной системой и аппаратными компонентами.
-
Меню настройки: Предоставляет меню настройки для конфигурации системы, позволяя пользователям настраивать параметры, связанные с порядком загрузки, предпочтениями в аппаратном оборудовании и другими системными параметрами.
-
Логика загрузки: Механизм для поиска и загрузки payload’а (вероятно, операционной системы) с доступных загрузочных носителей.
BIOS
Интерфейс в BIOS известен как сервисы / функции / прерывания BIOS. Эти функции предоставляют набор процедур для доступа к hardware, но конкретные детали их реализации на определенном оборудовании скрыты от пользователя.
В 16-битном Real Mode к этим функциям можно легко получить доступ, вызвав программное прерывание через инструкцию x86 ассемблера INT. В 32-битном Protected mode почти все сервисы BIOS недоступны из-за другого способа обработки сегментов.
Для примера рассмотрим сервисы для взаимодействия с диском (INT 13h
), которые предоставляют возможность чтения и записи на жесткие диски и дискеты на основе Cylinder-Head-Sector (CHS) адресации. Предположим, что нам нужно прочитать 2 сектора (1024 байта) и загрузить их по адресу в памяти 0x9020. Для этого можно выполнить следующий код:
mov $0x02, %ah # Выбрать функцию чтения сектора BIOS
mov $0x00, %ch # Выбрать цилиндр 0
mov $0x00, %dh # Выбрать головку 0 [начинается с 0]
mov $0x02, %cl # Выбрать сектор 2 (следующий после загрузочного
# сектора) [начинается с 1]
mov $0x02, %al # Прочитать 2 сектора
mov $0x00, %bx # Установить general регистр BX в 0
mov %bx, %es # Установить segment регистр ES в 0
mov $0x9020, %bx # Загрузить сектора по адресу ES:BX (0:0x9020)
int $0x13 # Начать чтение с диска
jmp $0x9020 # Перейти к загруженному коду
Если вам интересно, как эта служба реализована в SeaBIOS, взглядите на src/disk.c.
BOOT фаза
-
Начинается поиск загрузочного устройства (это может быть жесткий диск, CD-ROM, дискета и т.д.) путем считывания первых 512 байт (нулевого сектора) с устройств.
-
BIOS загружает первый валидный Master Boot Record (MBR), который она находит, в физическую память компьютера по физическому адресу 0x7C00 (примечание: 0x0000:0x7c00 и 0x7c0:0x0000 указывают на один и тот же физический адрес).
-
BIOS передает управление первым 512 байтам payload’а. Этот загруженный сектор, который слишком мал, чтобы содержать весь код payload’а, предназначен для загрузки остальной части payload с загрузочного устройства. На этом этапе payload может использовать интерфейс, предоставляемый BIOS.
Стоит отметить, что спецификация BIOS не существовала в ранние дни. BIOS является де факто стандартом — он работает так, как работал на реальных IBM PC в 1980-х годах. Остальные производители просто обратным инженерным путем (reverse engineering) создавали IBM-совместимые BIOSы. В результате не было регулирования, предотвращающего BIOS производителей от изобретения новых функций BIOS или со схожей функциональностью.
Unified Extensible Firmware Interface (UEFI)
Как уже упоминалось, UEFI сам по себе является лишь спецификацией и имеет множество реализаций. Наиболее широко используемой является TianoCore EDKII, открытая референсная реализация спецификаций UEFI и PI. Хотя EDKII сам по себе не является полностью функциональной прошивкой, он предоставляет надежный фундамент для большинства коммерческих решений.
Чтобы поддерживать различные First-Stage Bootloaderы и предоставить UEFI интерфейс, был разработан проект под названием UEFI Payload. Он использует первоначальную настройку и информацию о платформе, предоставленную загрузочной прошивкой (first-stage), для подготовки системы к UEFI среде.
UEFI Payload состоит из DXE и BDS фаз, которые спроектированы как платформо-независимые. Он предлагает общий (generic) payload, который может адаптироваться к различным платформам. В большинстве случаев даже не требуется никакой дополнительной настройки или специфичных для платформы изменений — он может использоваться «как есть», получая информацию о платформе от First-Stage Bootloader.
Варианты UEFI Payload:
-
Legacy UEFI Payload: Требует парсинг-библиотеку для обработки специфичной для реализации информации о платформе. Если bootloader обновляет свое API, payload также должен быть обновлен.
-
Universal UEFI Payload: Следует Universal Scalable Firmware (USF) Specification, используя Executable and Linkable Format (ELF) или Flat Image Tree (FIT) в качестве формата изображения. Вместо самостоятельного парсинга он ожидает получения Hand Off Blocks (HOBs) при входе в payload.
Несмотря на то, что Legacy UEFI Payload работает нормально, сообщество EDK2 стремится переключить индустрию на Universal UEFI Payload. Выбор между этими payload’ами зависит от компонентов вашей прошивки. Например, невозможно запустить Legacy Payload с поддержкой SMM на Slim Bootloader без моего патча. С другой стороны, использование Universal Payload с coreboot требует shim-слоя, который будет переводить coreboot tables в HOBs. Такая функциональность доступна только в форке EDK2 от StarLabs.
Интерфейс
Каждая система, соответствующая спецификации UEFI, предоставляет System Table, которая передается коду, работающему в среде UEFI (драйверам, приложениям, загрузчикам ОС). Эта структура данных позволяет UEFI приложениям получить доступ к system configuration tables таким как 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;
Сервисы включают следующие типы: Boot Services, Runtime Services, Services provided by protocols (сервисы, предоставляемые протоколами).
UEFI абстрагирует доступ к устройствам с помощью UEFI Protocols. Эти протоколы представляют собой структуру данных, содержащую указатели на функции и идентифицируются с помощью Globally Unique IDentifier (GUID), что позволяет другим модулям находить и использовать их. Они могут быть обнаружены через Boot Services.
UEFI драйвер создает эти протоколы, и реальные функции (не указатели!) содержатся в самом драйвере. Этот механизм позволяет различным компонентам внутри среды UEFI взаимодействовать друг с другом и обеспечивает возможность операционной системе общаться с устройствами до загрузки собственных драйверов.
Хотя некоторые протоколы предопределены и описаны в UEFI спецификации, производители прошивок могут также создавать свои собственные протоколы для расширения функциональности платформы.
Boot Services
Предоставляет функции, которые могут использоваться только во время загрузки. Эти сервисы остаются доступными до тех пор, пока не будет вызвана функция EFI_BOOT_SERVICES.ExitBootServices()
(MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c).
Указатели на все Boot Services хранятся в Boot Services Table (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;
Runtime Services
Минимальный набор сервисов, доступных после запуска операционной системы. В отличие от Boot Services, эти сервисы остаются действительными после того, как любой загрузочный модуль (например, OS bootloader) взял под контроль платформу через вызов EFI_BOOT_SERVICES.ExitBootServices()
.
Указатели на все Runtime Services хранятся в Runtime Services Table (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;
На изображении ниже показано время жизни (timeline) для boot и runtime сервисов, чтобы вы могли увидеть, когда каждая из них активна.
Boot Device Select (BDS) phase
Спецификация UEFI определяет механизм политики загрузки, называемый UEFI boot manager. Он будет пытаться загрузить UEFI приложения в определенном порядке до тех пор, пока не передаст управление найденному приложению. Этот порядок и другие настройки можно настроить, изменяя глобальные NVRAM (nonvolatile random-access memory) Variables (энергонезависимые переменные). Рассмотрим наиболее важные из них:
-
Boot####
(####
заменяется уникальным шестнадцатеричным значением) — опция загрузки/загрузочный вариант. -
BootCurrent
— опция загрузки, которая использовалась для запуска текущей системы. -
BootNext
— опция загрузки для следующего загрузочного процесса. Эта опция заменяетBootOrder
только для одной загрузки и удаляется Boot Manager’ом после первого использования. Это позволяет изменить поведение следующей загрузки без измененияBootOrder
. -
BootOrder
— упорядоченный список загрузочных вариантов. Boot Manager пытается загрузить первый активный вариант из этого списка. Если не удается, он пробует следующий вариант, и так далее. -
BootOptionSupport
— типы загрузочных вариантов, поддерживаемые Boot Manager. -
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 и так далее. Если переменная не существует, Boot Manager переходит к следующему элементу. Если переменная существует, она считывает содержимое этой переменной. Каждая boot option переменная содержит EFI_LOAD_OPTION
дескриптор, который представляет собой буфер с упакованными байтами переменной длины (это просто структура данных).
Структура данных описана в MdePkg/Include/Uefi/UefiSpec.h:
typedef struct _EFI_LOAD_OPTION {
/// Атрибуты для этой записи загрузочного варианта.
UINT32 Attributes;
/// Длина в байтах списка FilePathList.
UINT16 FilePathListLength;
/// Человеко-читаемое описание для загрузочного варианта.
/// Пример: 'ARCHLINUX' / 'Windows Boot Manager' / `EFI USB Device`
// CHAR16 Description[];
/// Упакованный массив путей к устройствам UEFI.
/// Пример: 'HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi)'
// EFI_DEVICE_PATH_PROTOCOL FilePathList[];
/// Оставшиеся байты в дескрипторе загрузочного варианта — это бинарные данные, которые передается загруженному образу.
/// Пример: '57a9...0400' в переменной Boot0001
// UINT8 OptionalData[];
} EFI_LOAD_OPTION;
На этом этапе прошивка будет проверять Device Path (EFI_DEVICE_PATH_PROTOCOL). В большинстве случаев наш компьютер загружается с физического устройства хранения данных (жесткий диск/SSD/NVMe и т.д.). Таким образом, Device path к устройству будет содержать следующий узел: HD(Номер раздела, Тип, Подпись, Начальный сектор, Размер в секторах)
.
-
Тип — указывает на используемый формат размещения таблиц разделов с помощью ключевых слов MBR (1) или GPT (2).
-
Подпись — 4ех байтовая MBR подпись, если Тип равен MBR, либо 16ти байтовый UUID, если Тип равен GPT.
Примечание: Если вам интересно, как переводятся другие пути, обратитесь к UEFI Specification v2.10, 10.6.1.6 Text Device Node Reference.
UEFI будет искать на диске раздел, соответствующий узлу. Если он существует, он должен быть помечен определенным Globally Unique IDentifier (GUID), который указывает на EFI System Partition (ESP). Этот раздел отформатирован с использованием файловой системы, основанной на FAT file system, и называется EFI File System; фактически, это обычный FAT12/16/32.
-
Обычная (Native) загрузка: если Device Path содержит явный путь к файлу
File(\Path\To\The\File.efi)
, то UEFI будет искать именно этот файл. Например, опцияBoot0000
содержитFile(\EFI\ARCHLINUX\grubx64.efi)
. -
Резервная (Fallback) загрузка: если Device Path указывает просто на диск, то в таких ситуациях прошивка использует резервный путь загрузки, который зависит от архитектуры —
\EFI\BOOT\BOOT{arch}.EFI
(BOOTx64.EFI
для amd64 илиBOOTia32.EFI
для i386/IA32). Этот механизм позволяет работать загрузочным съемным носителям (например, USB-флеш) в UEFI, они просто используют резервный путь загрузки. Например, опцияBoot0002
будет использовать этот механизм.
Примечание: Все упомянутые выше опции Boot####
относятся к параметрам загрузки, полученным в примере использования утилиты efibootmgr.
В обоих случаях UEFI Boot Manager загрузит UEFI Application (это может быть OS bootloader, UEFI Shell, утилита, Setup Menu и другое) в память. В этот момент управление передается точке входа в UEFI application. В отличие от BIOS, UEFI приложение может вернуть управление прошивке (за исключением ситуации, когда приложение берет на себя управление системой). Если это произойдет или если что-то пойдет не так, Boot Manager перейдет к следующей записи Boot####
и повторит тот же процесс.
Спецификация упоминает, что Boot Manager может заниматься обслуживание базы данных переменных. Это включает удаление переменных загрузочных опций, которые не ссылаются или не могут быть разобраны. Кроме того, он может переписывать любой упорядоченный список, чтобы удалить любые загрузочные опции без соответствующих переменных загрузочных опций.
Вышеприведенный текст описывает UEFI загрузку. Также прошивка UEFI может работать в режиме Compatibility Support Module (CSM), который эмулирует BIOS.
OS Boot Loader
Программное обеспечение, запускаемое прошивкой (обычно Second-Stage Bootloader) и использующее его интерфейс для загрузки ядра ОС. Загрузчик ОС может быть столь же сложным, как и сама ОС, предлагая такие функции, как:
-
Чтение с различных файловых систем (HFS+, ext4, XFS и др.)
-
Взаимодействие через сеть (например, TFTP, HTTP)
-
Загрузка ядер, совместимых с Multiboot
-
Chainloading
-
Загрузка начальных ramdisk (initrd)
-
И многое другое!
Общий дизайн этих программ выходит за рамки данной статьи. Для подробного сравнения популярных загрузчиков ОС вы можете обратиться к ArchLinux wiki и статье в Википедии.
Windows система использует собственный проприетарный загрузчик ОС, известный как Windows Boot Manager (BOOTMGR).
Firmware (прошивка) больше не является маленьким, сложным фрагментом кода. Она превратилась в огромный объем сложного кода, и современные тенденции только способствуют этому. Мы можем запускать Doom, Twitter и многие другие интересные приложения прямо в прошивке.
Понимание общей архитектуры помогает лучше представить, как все компоненты работают вместе. Изучая структуру существующих прошивок, вы сможете увидеть и оценить впечатляющий процесс, который происходит каждый раз, когда компьютер запускается. Такой подход позволяет не только понять роль каждой части, но и увидеть насколько сложными становятся современные системы прошивки.
Источники
-
UEFI Specification Version 2.10
-
UEFI Platform Initialization Specification Version 1.8 (Errata A)
-
EDK II Documentation
-
Slim Bootloader Project Documentation
-
UEFI boot: how does that actually work, then?
-
Understanding modern UEFI-based platform boot
-
Anatomy of the UEFI Boot Sequence on the Intel Galileo
-
Very simple note on disk device «paths» in some common architectures.
-
How Computers Boot Up