Каким образом можно обойти UEFI при разработке собственной операционной системы?

В современных материнских платах установлена обновлённая прошивка (BIOS/UEFI), которая при загрузке ожидает не простой бинарный файл загрузчика, а файл BOOTX64.EFI. Как можно обойти этот механизм поиска/загрузки и обеспечить запуск собственной ОС при старте системы? <br/> <br/> Примечание: ОС разрабатывается с использованием русскоязычного синтаксиса. Целевая архитектура — x86, защищённый 32‑битный режим. Код генерируется на Python и собирается напрямую в сырые машинные опкоды x86.
  • 17 июля 2026 г. 21:01
Ответы на вопрос 3
Коротко — «обойти» UEFI полностью на современной плате обычно нельзя (фирменная прошивка управляет порядком загрузки), но есть несколько законных путей обеспечить запуск вашего кода при старте. Ниже — практические варианты и их плюсы/минусы, а также рекомендации для вашей цели (x86, защищённый 32‑бит, код в виде сырых машинных опкодов).

Основные варианты

1) Загружать через UEFI корректно (рекомендовано)
- Поместите загрузчик/обработчик в EFI System Partition (FAT32) по пути /EFI/BOOT/BOOTX64.EFI — это стандартный auto‑path для x86_64 плат.
- BOOTX64.EFI — это PE/COFF‑программа (UEFI приложение) для x86_64. Она запускается в 64‑битном UEFI окружении и может использовать сервисы прошивки для доступа к дискам, памяти и т.д.
- Ваша стратегия: сделать небольшой 64‑битный UEFI‑stub (можно на C/ассемблере, собирать с GNU‑EFI/EDK2) который:
  - загружает ваш 32‑битный бинарник в нужное место памяти,
  - подготавливает таблицы страниц/сегменты,
  - выполняет переход (stub) из 64‑бит в 32‑бит защищённый режим и передаёт управление вашему образу.
Плюсы: работает на всех UEFI платах (при отключённом Secure Boot или при подписи). Минусы: нужно написать/sobрать PE/COFF UEFI‑приложение и реализовать переход в PM из long mode.

2) Использовать готовый загрузчик (например GRUB)
- Установите GRUB как BOOTX64.EFI на ESP; GRUB умеет загружать multiboot‑совместимые ядра или любой сырый образ и выполнять переходы/подготовку.
- Для этого можно либо сделать multiboot2‑заголовок в вашем образе, либо написать небольшой загрузчик под GRUB.
Плюсы: меньшая ручная работа (GRUB уже решает многие проблемы). Минусы: требуется изучение GRUB/multiboot и установка GRUB в ESP.

3) Загружать через BIOS‑совместимый путь (Legacy/CSM, MBR)
- Если на плате есть опция Legacy/CSM – включить её и подготовить USB/жёсткий диск с MBR и загрузочным сектором (512 байт), как в классических BIOS.
- Ваш первый сектор (boot sector) можно сделать традиционным: он выполняется в реальном режиме и переводит процессор в защищённый режим, затем загружает остальное.
Плюсы: прямой путь к 32‑битному защищённому режиму, не нужно писать EFI-программу. Минусы: многие новые платы либо вовсе не поддерживают CSM, либо она отключена по‑умолчанию.

4) Эмуляция/виртуализация для разработки (очень рекомендовано)
- QEMU + SeaBIOS (или QEMU с OVMF для UEFI) позволяет быстро тестировать загрузчики без работы с реальным железом.
- Это позволяет итеративно отлаживать машинные опкоды, переход в защищённый режим и т.п. быстро и безопасно.

5) Создание ISO/El Torito hybrid (для CD/USB)
- Можно подготовить ISO с El Torito образом, который будет загружаться как "floppy" или "hard disk". Это полезно для совместимости с некоторыми прошивками.
- Но современные платы всё равно предпочтут EFI путь для x86_64.

Про Secure Boot и подписи (важно)
- Если на плате включён Secure Boot, UEFI будет запускать только подписанные доверенные PE/COFF‑образа. Легитимных вариантов:
  - подписать BOOTX64.EFI ключом, доверенным UEFI (обычно трудоёмко),
  - либо выключить Secure Boot в настройках прошивки.
- Я не буду приводить инструкции по обходу механизмов безопасности — корректный путь либо подпись, либо официальное отключение Secure Boot.

Практические советы для вашей ситуации (генерация машинных опкодов в Python, ядро — 32‑бит)
- Быстрее всего: использовать GRUB как BOOTX64.EFI и оформить ваш образ под multiboot (или сделать GRUB‑module/chainload). Тогда GRUB выполнит низкоуровневую работу по загрузке и переходу в защищённый режим.
- Если хотите минимизировать внешние зависимости: напишите маленький 64‑бит UEFI‑stub (BOOTX64.EFI), который всего-то загружает бинарник и выполняет переключение в 32‑бит protected mode — в образ можно встроить ваш сырой код. Такой stub можно писать на C и asm, собирать с GNU‑EFI/EDK2.
- Для быстрой отладки сначала тестируйте в QEMU/SeaBIOS (для BIOS) или QEMU+OVMF (для UEFI). Это позволит быстро проверять переходы режимов и корректность опкодов.

Ресурсы и ключевые слова для поиска (чтобы не приводить длинных примеров кода здесь)
- UEFI specification, EDK2 (TianoCore), GNU‑EFI
- GRUB2, Multiboot / Multiboot2 specification
- QEMU + SeaBIOS / OVMF
- El Torito, MBR boot sector, PE/COFF format (BOOTX64.EFI)
- Intel SDM — для деталей переключения в protected mode и управления A20/paging/сегментами

Если хотите — могу:
- описать высокоуровневую структуру 64‑битного UEFI‑stuba, который загружает 32‑бит ядро (без инструкций по обходу Secure Boot),
- или показать пример multiboot заголовка (или объяснить, как подготовить образ для GRUB),
- или подсказать, как настроить тест в QEMU для итеративной отладки.

Что предпочитаете — вариант с GRUB (самый простой), или писать свой UEFI‑stub?
<blockquote>Ос пишется исключительно для души. </blockquote> <br/> Так напишите его себе (BOOTX64.EFI), там же не так и сложно <br/> Посмотрите на <a href="https://github.com/tianocore/edk2" rel="nofollow">https://github.com/tianocore/edk2</a> - там все что Вам надо есть ...
Свой bootx64.efi можно и не писать: закидываешь в заголовок бинарника мультибут2 (магик 0xe85250d6 + address tag с load_addr + отдельный entry address tag с entry_addr, если бинарник не ELF), собираешь hybrid iso через grub-mkrescue с grub-efi-amd64-bin. UEFI всё равно запускает EFI-файл, просто это будет уже GRUB, а не твой код - и он сам дергает ExitBootServices и роняет тебя в чистый 32-битный protected mode без paging прямо на entry_addr. PE32+/efi-стаб можно не писать вообще. <br/> p.s. сегменты после прыжка в непредсказуемом состоянии, сразу перегрузи свою GDT через lgdt и обнови CS дальним jmp.
Похожие вопросы