Чтобы создать загрузчик UEFI, недостаточно записать файл на диск — прошивка ищет исполняемый файл строго определённого формата PE32+ с сигнатурой EFI-приложения на разделе с файловой системой FAT32. Если файл лежит не по пути \EFI\BOOT\BOOTX64.EFI или не содержит корректного заголовка, прошивка просто проигнорирует его, и пользователь увидит стандартное меню выбора ОС без своей записи.
В этой статье разберём полный цикл: как устроена загрузка UEFI, какие инструменты нужны для сборки, как написать минимальный загрузчик на языке C и зарегистрировать его в NVRAM прошивки. Материал рассчитан на тех, кто уже знаком с основами программирования, но впервые сталкивается с разработкой под UEFI.
Как UEFI находит и запускает загрузчик
В отличие от классического BIOS, который читал первый сектор диска (MBR) и передавал ему управление, UEFI работает с файловой системой. Прошивка монтирует специальный раздел — EFI System Partition (ESP), отформатированный в FAT32, и ищет на нём исполняемые файлы с расширением .efi.
Порядок поиска определяется переменными загрузки, хранящимися в энергонезависимой памяти NVRAM. Каждая запись Boot#### содержит путь к файлу загрузчика и метку, которую вы видите в меню загрузки. Если ни одна запись не сработала, прошивка использует резервный путь — \EFI\BOOT\BOOTX64.EFI для 64-битных систем. Именно этим механизмом пользуются установочные флешки: они не требуют записи в NVRAM.
Понимание этой схемы важно для диагностики: если самописный загрузчик не стартует, первым делом проверяют три вещи — наличие ESP-раздела, корректность пути к файлу и наличие записи в NVRAM.
Необходимые инструменты и среда разработки
Существует два основных подхода к разработке под UEFI. Первый — официальный инструментарий EDK II от сообщества TianoCore: это полноценный фреймворк, на котором строятся коммерческие прошивки, но его освоение требует времени. Второй — GNU-EFI, облегчённый набор библиотек и заголовков, позволяющий собирать EFI-приложения привычным компилятором GCC.
- 🛠️ EDK II — максимальные возможности, поддержка всех протоколов UEFI, крутая кривая обучения.
- 🛠️ GNU-EFI — быстрый старт на Linux, подходит для учебных и небольших проектов.
- 🛠️ POSIX-UEFI или uefi-rs — альтернативы для тех, кто предпочитает C++ или Rust.
- 🛠️ QEMU + OVMF — виртуальная машина с прошивкой UEFI для безопасного тестирования без риска для реального железа.
Для первого эксперимента разумнее всего выбрать связку GNU-EFI и QEMU с прошивкой OVMF. Тогда ошибка в коде приведёт лишь к зависанию виртуальной машины, а не к проблемам с загрузкой основного компьютера.
Минимальный загрузчик на C: разбор кода
Точка входа EFI-приложения отличается от привычной функции main. Прошивка передаёт программе два ключевых аргумента: образ загруженного приложения (handle) и указатель на системную таблицу, через которую доступны все сервисы UEFI — вывод текста, работа с файлами, памятью и устройствами.
#include <efi.h>
#include <efilib.h>
EFI_STATUS efi_main(EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable)
{
InitializeLib(ImageHandle, SystemTable);
Print(L"Hello, UEFI!\n");
return EFI_SUCCESS;
}
Функция Print выводит строку в кодировке UCS-2, поэтому литералы строк начинаются с префикса L. Возврат EFI_SUCCESS сообщает прошивке, что приложение завершилось штатно, и управление возвращается в меню загрузки.
Компиляция выполняется в два этапа: сначала GCC собирает объектный файл, затем компоновщик формирует исполняемый файл формата PE32+ с подсистемой EFI-приложения. В GNU-EFI эти шаги обычно оформлены готовым Makefile, но полезно понимать, что происходит под капотом.
gcc -I/usr/include/efi -I/usr/include/efi/x86_64 \
-fpic -ffreestanding -c main.c -o main.o
ld -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds \
/usr/lib/crt0-efi-x86_64.o main.o -o main.so -lefi -lgnuefi
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc \
--target=efi-app-x86_64 main.so BOOTX64.EFI
⚠️ Внимание: точные пути к библиотекам GNU-EFI зависят от дистрибутива и версии пакета. Перед сборкой проверьте расположение файлов crt0-efi-x86_64.o и скрипта компоновщика командой поиска по системе, а не копируйте пути вслепую.
Запись загрузчика на ESP-раздел
Готовый файл нужно разместить на ESP-разделе. В Linux этот раздел обычно уже существует и монтируется в /boot/efi; если системы на диске нет, раздел создают вручную с типом EFI System и форматируют в FAT32. Для теста через резервный путь файл копируют как BOOTX64.EFI в каталог \EFI\BOOT\.
Для собственного имени файла структура каталогов произвольная — например, \EFI\MYLOADER\loader.efi. Но в этом случае без записи в NVRAM прошивка файл не найдёт, о чём расскажем в следующем разделе.
☑️ Подготовка ESP-раздела
Отдельный нюанс — регистр имён. FAT32 нечувствительна к регистру, поэтому bootx64.efi и BOOTX64.EFI для прошивки — один и тот же файл, и проблем из-за этого не возникает.
Регистрация загрузчика в NVRAM
Чтобы запись появилась в меню загрузки, её нужно добавить в NVRAM. В Linux это делается утилитой efibootmgr — она показывает текущие записи, позволяет создавать новые и менять порядок загрузки.
efibootmgr --create --disk /dev/sda --part 1 \
--label "My UEFI Loader" \
--loader '\EFI\MYLOADER\loader.efi'
В Windows аналогичную задачу решает встроенная утилита bcdedit, но её синтаксис ориентирован в первую очередь на записи Windows Boot Manager, и для сторонних EFI-приложений удобнее использовать efibootmgr из загрузочного Linux-окружения. После добавления записи проверьте её появление в меню загрузки прошивки — обычно оно вызывается клавишей вроде F12 или Esc, но конкретная клавиша зависит от производителя платы.
⚠️ Внимание: некорректные операции с NVRAM могут привести к тому, что система перестанет находить основную ОС. Перед экспериментами убедитесь, что у вас есть загрузочная флешка, с которой можно восстановить записи загрузки.
Почему запись не появляется в меню
Частые причины: путь в записи указан с прямыми слэшами вместо обратных; неверно указан номер диска или раздела в efibootmgr; прошивка игнорирует записи, если файл физически отсутствует по указанному пути; некоторые прошивки сбрасывают нестандартные записи при отключённом или включённом Secure Boot. Проверяйте вывод efibootmgr -v и фактическое наличие файла на ESP.
Secure Boot и подпись загрузчика
Если на компьютере включён Secure Boot, прошивка откажется запускать неподписанный загрузчик — на экране появится ошибка проверки подписи. Это нормальное поведение механизма защиты, а не неисправность.
Есть три пути решения. Первый — временно отключить Secure Boot в настройках прошивки на период разработки: это самый простой вариант для тестовой машины. Второй — подписать файл собственным ключом и внести этот ключ в базу доверенных ключей прошивки через режим настройки (Setup Mode). Третий — использовать подписанный загрузчик-прослойку shim, как это делают дистрибутивы Linux, но для собственного проекта этот путь избыточен.
| Подход | Сложность | Когда уместен |
|---|---|---|
| Отключение Secure Boot | Низкая | Тестовая машина, обучение |
| Собственный ключ и подпись | Средняя | Личные проекты, контролируемое железо |
| Использование shim | Высокая | Распространение на чужие устройства |
| Работа без Secure Boot на QEMU/OVMF | Низкая | Отладка кода без риска |
⚠️ Внимание: отключайте Secure Boot только на машине, которую полностью контролируете, и возвращайте настройку после завершения экспериментов. На рабочем компьютере с Windows отключение может повлиять на функции, завязанные на проверку целостности загрузки.
Типичные ошибки и их диагностика
Чаще всего начинающие сталкиваются с ситуацией, когда файл собран, лежит на ESP, но прошивка его «не видит». Разберём типовые причины и способы проверки.
- 🔍 Файл собран не в том формате — проверьте, что
objcopyвызван с цельюefi-app-x86_64, а не с форматом обычного исполняемого файла. - 🔍 Неверный путь на ESP — сверьте фактическое расположение файла с записью в выводе
efibootmgr -v. - 🔍 Secure Boot блокирует запуск — временно отключите его и проверьте, исчезла ли проблема.
- 🔍 Прошивка игнорирует NVRAM-записи — попробуйте резервный путь
\EFI\BOOT\BOOTX64.EFI. - 🔍 Загрузчик стартует и сразу зависает — добавьте вывод отладочных строк через
Printна каждом этапе, чтобы локализовать точку сбоя.
Методичный подход здесь важнее интуиции: меняйте по одному фактору за раз и фиксируйте результат. Так вы быстро отделите проблемы сборки от проблем размещения файла и проблем с политиками прошивки.
Часто задаваемые вопросы
Можно ли написать загрузчик UEFI на Windows без Linux?
Да. EDK II официально поддерживает сборку в Windows с компилятором Visual Studio. Потребуется развернуть дерево исходников EDK II и настроить окружение по официальной документации проекта — процедура зависит от версии, поэтому сверяйтесь с актуальным руководством TianoCore.
Чем загрузчик отличается от обычного EFI-приложения?
Формально — ничем: это тот же файл формата PE32+ с точкой входа efi_main. Разница в назначении: загрузчик дополнительно загружает в память ядро операционной системы, передаёт ему параметры и завершает работу загрузочных сервисов вызовом ExitBootServices.
Обязательно ли размещать файл по пути BOOTX64.EFI?
Нет. Этот путь — лишь резервный вариант, который прошивка проверяет, когда нет подходящих записей в NVRAM. Свой файл можно разместить в любом каталоге ESP и зарегистрировать через efibootmgr.
Запустится ли загрузчик на компьютере со старым BIOS?
Нет. EFI-приложения требуют прошивки с поддержкой UEFI. На системах только с Legacy BIOS файл .efi не будет распознан — там используется совершенно иной механизм загрузки через загрузочный сектор.
Опасно ли экспериментировать с загрузчиком на основном компьютере?
Сам по себе файл на ESP безопасен: удалив его или некорректную запись, вы вернёте систему в исходное состояние. Риск представляют ошибочные действия с разделами диска и некорректные изменения NVRAM. Поэтому начинать разумнее с виртуальной машины QEMU + OVMF, а на реальном железе всегда держать под рукой загрузочную флешку.