Как создать загрузчик UEFI своими руками

Чтобы создать загрузчик 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 и скрипта компоновщика командой поиска по системе, а не копируйте пути вслепую.
📊 Какой инструментарий для разработки под UEFI вам ближе?
EDK II (TianoCore)
GNU-EFI
Rust (uefi-rs)
Только изучаю тему

Запись загрузчика на ESP-раздел

Готовый файл нужно разместить на ESP-разделе. В Linux этот раздел обычно уже существует и монтируется в /boot/efi; если системы на диске нет, раздел создают вручную с типом EFI System и форматируют в FAT32. Для теста через резервный путь файл копируют как BOOTX64.EFI в каталог \EFI\BOOT\.

Для собственного имени файла структура каталогов произвольная — например, \EFI\MYLOADER\loader.efi. Но в этом случае без записи в NVRAM прошивка файл не найдёт, о чём расскажем в следующем разделе.

☑️ Подготовка ESP-раздела

Выполнено: 0 / 5

Отдельный нюанс — регистр имён. 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, а на реальном железе всегда держать под рукой загрузочную флешку.