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

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

Также у меня была статья на Хабре, где я затрагивал тему загрузочных ISO, но не вдавался в подробности реализации.

Что вы найдёте в этой статье


Не знаю, как для кого, но для меня лучше всего запоминается то, что ты сам попробовал на практике, когда ты сделал немало ошибок, чтобы разобраться с темой. Поэтому мой рассказ о загрузочных ISO-образах будет совмещён с практикой.

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

После прочтения этой статьи вы сможете создать универсальный загрузочный образ ISO, который можно будет записать на оптический диск, внешний жёсткий диск или флеш-накопитель так, что при загрузке с него будут выполняться минимальные программы Hello, World, никак не зависимые от операционной системы. Эти программы можно считать заглушками для реальных загрузчиков операционных систем. Пример из статьи позволит вам разобраться со структурой загрузочных ISO-образов и улучшит ваше понимание процесса загрузки компьютера (bootstrapping).

Немного теории, которую необходимо знать


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

Загрузка операционной системы на компьютере x86


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

Существует два вида программ, располагающихся в ROM — BIOS (Basic Input/Output system) и UEFI (Extensible Firmware Interface). Обычно компьютеры с UEFI позволяют эмулировать BIOS, если выбрать опцию Legacy Mode.

Механизм загрузки BIOS (Legacy)


BIOS не имеет никакого представления о файловых системах, установленных на устройствах, с которых осуществляется загрузка. Он рассматривает устройства как блочные, которые могут возвращать блоки данных (сектора), располагающиеся по определённым LBA (Logical Block Address). Ранее дисковые устройства ещё имели режим адресации CHS (Cylinder, Head, Sector), который был более близок к физической геометрии жёстких дисков, но сейчас он практически не используется.

Если данные удовлетворяют определённому критерию, BIOS загружает их в память, рассматривает их как программу и передаёт ей управление.

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

Когда BIOS передаёт управление, то процессор x86 находится в реальном режиме, а это значит, что в программе можно обратиться только к 1МiB оперативной памяти и, если вы хотите использовать всю оперативную память, то необходимо позаботиться о том, чтобы перевести процессор в защищённый режим. Такие загрузчики, как GRUB 2, как раз это и делают.

Механизм загрузки UEFI


UEFI знает о файловой системе FAT. При загрузке с устройства UEFI пытается найти на устройстве раздел с этой файловой системой и исполняемый файл UEFI в ней, после чего запустить его на выполнение.

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

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

Загрузка с жёсткого диска или флеш-накопителя


Загрузка с жёсткого диска или флеш-накопителя в большинстве случаев подразумевает, что они размечены на разделы, а на одном или нескольких разделах находятся загрузчики и операционные системы, которые необходимо загрузить. Мне известно о двух видах разметки: MBR (Master Boot Record) и GPT (GUID Partition Table).

MBR – более ранний способ разметки, подразумевающий разметку диска на 4 первичных раздела. Существует способ увеличить общее количество разделов за счёт создания так называемых расширенных разделов, но загрузка с таких разделов усложняется.

GPT – современный способ разметки, подразумевающий разметку диска на большое количество разделов и поддержку дисков размером более 2TiB.

На просторах Интернета существует очень распространённое заблуждение, которое заключается в том, что на компьютерах с BIOS используется ТОЛЬКО MBR-разметка, а с UEFI TOЛЬКО GPT-разметка. Это неверно.

BIOS не имеет понятия как о GPT, так и о MBR, он только знает о том, что нужно загрузить и выполнить программу, находящуюся в нулевом секторе, если этот диск является загрузочным и последние два байта в секторе равны 55AAh. Но если в результате будет передано управление загрузчику, который «понимает» GPT, то последний сможет загрузить операционную систему с раздела GPT. Разумеется, сама операционная система должна поддерживать GPT-разметку. Но даже если она не поддерживает GPT, в нулевом секторе можно разместить таблицу разделов MBR, которая будет указывать на подмножество разделов GPT (максимум 4 шт., которые находятся в пределах первых 2ТiB размеченного диска), и они будут видны этой операционной системе.

Чтобы компьютер загрузил ОС средствами UEFI, необходимо наличие системного раздела EFI на диске (EFI System Partition (ESP)), с которого осуществляется загрузка. Неважно, какая разметка используется (MBR или GPT), важно наличие самого раздела, а также наличие приложения UEFI с прописанным именем в системных переменных UEFI или имеющего стандартное имя bootx64.efi и располагающегося в директории EFI\boot в разделе ESP.

Таким образом, различие BIOS и UEFI-загрузки заключается в том, как загрузится и выполнится самая первая программа (приложение) после них. В BIOS загружается и выполняется программа, которая находится в нулевом секторе диска, в UEFI выполняется программа, которая находится на системном UEFI разделе диска.

Файловая система оптических дисков


Для хранения файлов на оптических дисках очень часто используется файловая система ISO 9660. Она имеет несколько уровней (Level 1, Level 2, Level 3) и расширений (Rock Ridge, Joliet). Также часто используется файловая система UDF, но для нашей задачи эти знания не понадобятся, так как фактически мы будем работать с секторами диска. В статье я не буду подробно рассматривать файловые системы для оптических дисков. Загрузчик, который будет загружен BIOS или UEFI для выполнения дальнейшей загрузки, должен «понимать» файловую систему оптических дисков, а я для краткости это не рассматриваю.

Загрузка с оптического диска


Для того, чтобы компьютер смог загружаться с оптического диска, BIOS или UEFI должны поддерживать стандарт El Torito, придуманный специально для этого. И тут, как и при загрузке с жёсткого диска, для BIOS важен сектор, в котором находится программа начальной загрузки, а для UEFI важен системный UEFI-раздел на диске c программой UEFI.

Скажу честно, я до последнего думал, что UEFI запускает файл bootx64.efi, который находится в файловой системе ISO 9660 на оптическом диске, однако это не так, так как UEFI понимает загрузку только с ESP, поэтому ему нужно предоставить образ ESP с файлом bootx64.efi, а в специальной структуре Booting Catalog указать расположение образа.

Гибридный ISO-образ


В настоящее время большинство дистрибутивов Linux распространяются в виде так называемых гибридных ISO-образов.

Суть гибридных ISO-образов в следующем: один и тот же образ можно посекторно записать на оптический диск или на флеш-накопитель/внешний жёсткий диск. Загрузка будет выполнена с любого из устройств, если его выбрать в качестве загрузочного. Это очень удобно для конечного пользователя. Он просто берёт образ и записывает его на оптический диск или флеш-накопитель, не выполняя никаких преобразований.

Как же это происходит? Дело в том, что первые 16 секторов в файловой системе ISO 9660, каждый из которых размером 2048 байт, используются для системных нужд, поэтому там можно разместить MBR и/или GPT. Они игнорируются BIOS/UEFI при загрузке с оптического диска, но при загрузке с флеш-накопителя они используются.

Запись о разделе в MBR или GPT будет указывать на файл с образом ESP, а в случае MBR для BIOS будет содержаться код начальной загрузки, который уже будет каким-то образом читать код из секторов и выполнять его, продолжая тем самым дальнейшую загрузку.

При всём своём удобстве этот подход не стандартизован и, например, Windows или какие-то программы по разметке диска могут считать такую информацию в MBR или GPT неверной.

Структура загрузочного ISO-образа


Любой ISO-образ должен содержать список дескрипторов томов. Каждый дескриптор занимает целый сектор (2048) байта. Дескрипторы томов размещаются начиная с 16-го сектора, если нумерация секторов осуществляется с 0.

Дескриптор тома с загрузочными записями El Torito располагается в 17-м секторе.
Структура загрузочного ISO-образа для современных компьютеров х86 представлена на рисунке.

Для загрузки с оптического диска нас интересует Boot Record Volume Descriptor. С описанием Primary Volume Descriptor и Volume Descriptor Set Terminator вы можете ознакомиться в спецификации файловой системы ISO 9660 (ECMA-119)

▍ Boot Record Volume Descriptor


Назначение Boot Record Volume Descriptor — указать, где находится Booting Catalog, который содержит информацию для BIOS или UEFI о том, что именно и каким способом можно загрузить с оптического диска.
Байты Описание
0 Индикатор загрузочной записи, всегда содержит значение 0x00
1… 5 Идентификатор ISO-9660, всегда содержит строку CD001
6 Версия дескриптора, содержит 0x01
7… 38 Идентификатор загрузочной системы, всегда содержит строку EL TORITO SPECIFICATION, оставшиеся байты заполняются 0
39… 70 Не используется. Всегда заполнено 0
71… 74 LBA первого сектора загрузочного каталога
75… 2047 Не используется, всегда заполнено 0

▍ Booting Catalog


Booting Catalog – это массив записей размером 32 байта каждая. Количество записей не ограничено. Всего в спецификации определены 5 типов записей: Validation Entry, Default Entry, Section Header, Section Entry, Section Entry Extension. Последнюю описывать не буду, так как я не встречал её применение.

Validation Entry

Назначение Validation Entry — это подтверждение того, что образ ISO (оптический диск) действительно является загрузочным.
Байты Описание
0 Header Id всегда равен 0x01
1 ID платформы
0x00 = 80x86
0x01 = Power PC
0x02 = Mac
2..3 Зарезервировано, всегда содержит 0
4..27 ID, идентификатор производителя CD-ROM, сейчас обычно содержит 0
28..29 Контрольная сумма
30 Всегда 0x55, участвует в подсчёте контрольной суммы
31 Всегда 0xAA, участвует в подсчёте контрольной суммы
Default Entry

Назначение Default Entry — указать, что будет загружено по умолчанию. Обычно это сектора для загрузки при помощи BIOS.
Байты Описание
0 Boot Indicator (0x88 — загрузочная, 0x00 — не загрузочная)
1 Boot media type
0x00 — без эмуляции
0x01 — эмуляция дискеты 1.2
0x02 — эмуляция дискеты 1.44
0x03 — эмуляция дискеты 2.88
0x04 — эмуляция жёсткого диска
В настоящее время чаще всего используется режим 0x00. Эмуляция дискет и жёстких дисков нужна для загрузки очень старых операционных систем.
2 Сегмент загрузки обычно 0x00, что подразумевает, что сектор с кодом загрузчика будет помещён в сегмент 0x07C0, как и в загрузке с жёсткого диска или дискеты
4 Тип системы для режима без эмуляции – 0x00
5 Не используется
6..7 Количество секторов размером 512 байт (не 2048), которые нужно считать в сегмент загрузки
8..11 LBA-адрес первого сектора, который нужно загрузить в сегмент загрузки
12..31 Не используются, всегда содержат 0
Section Header

Назначение Section Header — сгруппировать возможные виды загрузки, однако обычно на практике существует ещё только один вид загрузки через UEFI.
Байты Описание
0 Header Indicator (0x90 – не последний заголовок, 0x91 – последний заголовок). В большинстве случаев, так как обычно в ISO-образе только одна секция, поле содержит 0x91.
1 Идентификатор платформы.
0x00 — 80x86
0x01 — Power PC
0x02 — Mac
0xEF — EFI (UEFI)
Значение 0xEF отсутствует в оригинальной спецификации, но сейчас оно используется, если мы хотим выполнить загрузку средствами UEFI.
2..3 Количество Section Entry после заголовка.
4..31 Идентификатор для BIOS и загрузчика, чтобы он принял решение, использовать ли информацию из следующих секций для загрузки. В большинстве случаев тут содержатся 0.
Section Entry

Назначение Section Entry — указать, что может быть загружено и откуда. Обычно это сектора образа ESP для загрузки при помощи UEFI.
Байты Описание
0 Booting Indicator (0x88 — загрузочная, 0x00 — не загрузочная)
1 Режим эмуляции (Boot media type)
0x00 — без эмуляции
0x01 — эмуляция дискеты 1.2
0x02 — эмуляция дискеты 1.44
0x03 — эмуляция дискеты 2.88
0x04 — эмуляция жёсткого диска
В настоящее время чаще всего используется режим 0x00. Эмуляция дискет и жёстких дисков нужна для загрузки очень старых операционных систем. В оригинальной спецификации вы можете посмотреть, какие ещё значения может содержать этот байт.
2..3 Сегмент загрузки обычно 0x00, что подразумевает, что сектор с кодом загрузчика будет помещён в сегмент 0x07C0, как и в загрузке с жёсткого диска или дискеты
4 Тип системы для режима без эмуляции – 0x00
5 Не используется, всегда равен 0x00
6..7 Количество секторов размером 512 байт (не 2048), которые нужно считать в сегмент загрузки
8..11 LBA-адрес первого сектора, который нужно загрузить в сегмент загрузки
12 Selection Criteria Type. Критерий выбора. Обычно 0. Подробнее смотрите в спецификации El Torito
13..31 Vendor Unique Selection Criteria. Обычно 0x00. Подробнее в спецификации El Torito

Практическая часть


Создание образа


Изначально я хотел описать в статье, как создать образ с нуля без использования сторонних программ, но потом мне показалось, что это раздует статью, её будет сложно читать, и вы потратите много времени на изучение. Поэтому использовал уже готовые решения, которые используются в Linux: Xorriso для создания образов, а для того, чтобы увидеть наглядно структуры загрузочного ISO, xxd для просмотра содержимого образа в шестандцатиричном формате

Вы всегда можете попробовать создать загрузочный ISO-файл сами, написав небольшие программы на C, Java или другом языке программирования, но в статье я на этом останавливаться не буду.

Минимальные программы-заглушки загрузчиков для BIOS и UEFI


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

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

Для упрощения понимания наши загрузчики не будут ничего делать кроме вывода тривиальных фраз типа «Hello, world!» на экран. Можно сказать, что это заглушки, которые могут быть использованы для написания полноценных загрузчиков в дальнейшем.

Код программы-заглушки загрузчика BIOS


Загрузчик для BIOS – это один или несколько секторов на диске. Инструкции, содержащиеся в них, процессор выполняет в реальном режиме, где доступно только 1MiB оперативной памяти.
Обычно исходный код загрузчика при помощи ассемблера превращается в бинарный файл, содержимое которого потом посекторно записывается на диск.

Для меня проще всего получить такой код, используя ассемблер fasm.

		use16
		org 0x7c00
		
		cli
		jmp 0:start
		times 8-($-$$) nop		; Pad to file offset 8

; iso_boot_info structure is filled by xorriso when we generate ISO file.
iso_boot_info:
bi_pvd:	dd 16				; LBA of primary volume descriptor
bi_file:	dd 0				; LBA of boot file
bi_length:	dd 0xdeadbeef			; Length of boot file
bi_csum:	dd 0xdeadbeef			; Checksum of boot file
bi_reserved:	times 10 dd 0xdeadbeef	; Reserved
iso_boot_info_end:

signature:	dd 0x7078c0fb			; used by ISOLINUX hybrid MBR

start:
		xor ax, ax
		push ax
		pop es
		push ax
		pop ds
		sti

		mov ax, 0x03
		int 0x10

		mov si, hello_message

		mov ah, 0xe
print_loop:
		lodsb
		or al, al
		jz done
		int 0x10
  		jmp print_loop

done:
		jmp $
hello_message:
		db "Hello world BIOS", 0x0a, 0

		times 510 - ($ - $$) db 0
		dw 0xaa55

Код у нас получается достаточно простой, но существуют моменты, на которые необходимо обратить внимание.

  1. Так как процессор будет выполнять код в реальном режиме, нам нужно использовать директиву use16.
  2. Наш код будет загружаться в BIOS по адресу 0x7c00. Чтобы ассемблер закрепил корректные адреса за метками, используется директива org.
  3. Чтобы аппаратные прерывания не помешали начальной инициализации регистров, используется команда процессора cli.
  4. Очень важно проинициализировать регистры. Во многих статьях по созданию загрузочных секторов забывают этот факт. В результате вроде всё гладко работает в qemu или VirtualBox, однако в VMWare или на реальном железе код отказывается работать. Я потратил достаточно много времени, пока это не понял.
  5. Так как часть полученного кода будет модифицироваться Xorriso, который записывает нужные данные, то нам необходимо выполнить команду jmp, а дальше в коде зарезервировать место под эти данные.
  6. Я не создавал свою MBR для ISO-образа, а использовал ту, которую предоставляет загрузчик ISOLINUX, поэтому необходимо прописать значение signature, ожидаемое загрузчиком из MBR, иначе наша заглушка загрузчика для BIOS не будет выполнена.
  7. Значение 55AA и заполнение нулями в конце программы необязательно, но я хотел получить полноценный загрузочный сектор, который можно было бы записать в нулевой сектор жёсткого диска или флеш-накопителя, и он тоже бы выполнялся.

Код программы-заглушки загрузчика UEFI


Загрузчик для UEFI – это уже исполняемый файл, который помимо программного кода и данных содержит дополнительную информацию о том, как размещать их в оперативной памяти. Файлы .efi по формату практически совпадают с исполняемыми файлами Windows. Разумеется, в них нет вызовов функций операционной системы. Обычно исходный код пишется на языке C или С++. Мы для простоты будем использовать C.

При сборке в операционной системе Linux нам понадобится кросс-компилятор.

Необходимости комментировать что-то в программе нет ввиду её простоты, однако я добавлю, что для компиляции программы у вас должен быть установлен пакет gnu-efi, а вечный цикл (while (1)) я сделал для наглядности, чтобы сообщение не исчезало при завершении работы программы, и EFI_SUCCESS она никогда не вернёт.

#include <efi.h>
#include <efilib.h>

EFI_STATUS EfiMain (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE  *SystemTable ) {

    SystemTable->ConOut->OutputString(SystemTable->ConOut, L"UEFI Hello World!\n");
    while(1);
    return EFI_SUCCESS;
}

Алгоритм создания загрузочного диска вручную


Я собирал образ загрузочного диска на Ubuntu 22.10.

Для начала необходимо поставить следующие пакеты, если они не установлены.
Пакет Назначение
make Утилита make
gcc-mingw-w64 Компилятор C
fasm Ассемблер
gnu-efi Библиотека для создания UEFI-приложений
binutils Утилиты для работы с объектными файлами
mtools Утилиты для работы с образом раздела FAT
dosfstools Утилиты для форматирования
xorriso Утилита для создания ISO-образов
isolinux Загрузчик, который позволяет загружаться с оптических дисков. Нам от него нужен только MBR для гибридного ISO
xxd Утилита для просмотра бинарных файлов. В частности, она нам понадобится для просмотра структуры созданного ISO-образа
qemu-system-x86 Эмулятор, который позволяет эмулировать компьютеры с BIOS и UEFI
ovmf Образ прошивки UEFI для эмулятора
1. Создаём необходимые директории.

$ cd ~
$ mkdir -p boot-hello-world
$ cd boot-hello-world
$ mkdir -p build
$ mkdir -p out

2. Создаём файлы bioshello.asm и efihello.c с исходным кодом наших программ-заглушек загрузчиков.

3. Компилируем заглушку для загрузчика BIOS.

$ fasm bioshello.asm build/bootsec.bin

4. Компилируем заглушку для загрузчика UEFI.

$ x86_64-w64-mingw32-gcc -shared -I/usr/include/efi -nostdlib -mno-red-zone -fno-stack-protector -Wall -e EfiMain efihello.c -o build/bootx64.efi.dll
$ objcopy --target=efi-app-x86_64 build/bootx64.efi.dll build/bootx64.efi

5. Создаём образ ESP, создаём в нём директории, копируем в него файл bootx64.efi.

$ dd if=/dev/zero of=build/uefi.img bs=512 count=2880
$ mkfs.msdos -F 12 -n 'EFIBOOTISO' build/uefi.img
$ mmd -i build/uefi.img ::EFI
$ mmd -i build/uefi.img ::EFI/BOOT
$ mcopy -i build/uefi.img build/bootx64.efi ::EFI/BOOT/bootx64.efi

6. Создаём структуру из файлов и директорий, которые будут размещены в образе ISO.

$ mkdir -p build/iso-image/boot
$ mkdir -p build/iso-image/EFI/boot
$ cp build/bootx64.efi build/iso-image/EFI/boot/
$ cp build/bootsec.bin build/iso-image/boot/
$ cp build/uefi.img build/iso-image/boot/

7. Создаём гибридный загрузочный образ ISO.

$ xorriso  -as mkisofs -V "HYBRID" -o out/bootdisk.iso -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -c boot/boot.cat -b boot/bootsec.bin -no-emul-boot -boot-info-table \
-boot-load-size 4 -eltorito-alt-boot -e boot/uefi.img -no-emul-boot -isohybrid-gpt-basdat build/iso-image --sort-weight 0 /boot --sort-weight 1 /

8. Экспериментируем и проверяем работу образа в различных эмуляторах, например qemu, виртуальных машинах (VMWare, Virtual Box), записываем образ на оптический диск и флеш-накопитель (при помощи программ Win32DiskImager, balenaEtcher).

Например, чтобы запустить в qemu-эмуляторе загрузочный ISO с использованием BIOS, если бы он был записан на оптический диск:

$ qemu-system-x86_64 -boot d -cdrom out/bootdisk -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio

Чтобы запустить в qemu-эмуляторе загрузочный ISO с использованием UEFI, если бы он был записан на флеш-накопитель:

$ qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -boot d -hda $(BOOT_ISO) -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio

Чтобы выйти из эмулятора, нужно нажать клавиши Ctrt + A, а потом X.

Я думаю, о том, как запустить эмуляцию запуска загрузочного диска с использованием BIOS с флеш-накопителя и с использованием UEFI с оптического диска вы догадаетесь сами.

Ещё один способ создания загрузочного флеш-накопителя в Windows


Внимательный читатель мог заметить, что зачем-то в ISO-образ помимо образа ESP помещается и файл bootx64.efi. Напрашивается вопрос, зачем это делается, если UEFI нужен именно образ ESP в ISO-образе? Ответ заключается в том, что, разместив файл в образе ISO, можно создать загрузочный флеш-накопитель путём простого копирования всех файлов из ISO-образа.

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

  1. Запускаем программу diskpart.
  2. Выводим на экран список доступных дисков командой list disk.
  3. Выбираем среди них флеш-накопитель, который мы будем размечать и форматировать командой select disk.
  4. Выполняем очистку выбранного диска командой clean.
  5. Создаём первичный раздел командой create partition primary.
  6. Форматируем раздел командой format fs=fat32 quick.
  7. Выходим из diskpart командой exit.
  8. Копируем файлы из ISO-образа на флеш-накопитель простым копированием файлов


В нашем случае нам достаточно скопировать только директорию EFI, так как остальные файлы использоваться не будут, но для простоты скопируйте все файлы из ISO-образа.

Изучение структуры созданного загрузочного ISO-образа


Созданный образ у нас находится в директории out и имеет имя bootdisk.iso.

1. Выведем номер сектора, где располагается Booting Catalog:

$ xxd -l 4 -s $(expr 17 \* 2048 + 71) out/bootdisk.iso 

Здесь 4 — это количество байт, которые выводим, 17 — номер сектора с Boot Record Volume Descriptor, 2048 — размер сектора, 71 — смещение внутри сектора, где располагается LBA Booting Catalog.


Номер сектора занимает 4 байта, поэтому нужно знать, какой порядок байтов используется Big Endian или Little Endian. Я не нашёл в спецификации El Torito, какой порядок используется, но, судя по всему, это Little Endian, поэтому байты нужно читать справа налево, получая 0x00000021.

2. Выведем первые четыре записи Booting Catalog:

$ xxd -l $(expr 32 \* 4) -s $(expr $(echo $((0x21))) \* 2048) out/bootdisk.iso

Здесь 32 — это размер записи в Booting Catalog, 4 — количество записей, $(expr $(echo $((0x21))) — десятичное представление 0x21, 2048 — размер сектора.


3. Выведем LBA-адрес сектора, который будет загружен при загрузке средствами BIOS:

$ xxd -l 4 -s $(expr $(echo $((0x21))) \* 2048 + 32 + 8) out/bootdisk.iso

Здесь 4 — количество байт, которые выводим, 32 — размер записи в Booting Catalog (мы берём данные из Default Entry, поэтому пропускаем 32 байта), 8 — смещение внутри Default Entry, где располагается LBA загрузчика для BIOS, 2048 — размер сектора.


4. Выведем первые 512 байт этого сектора (это наша программа, которую мы написали на ассемблере и откомпилировали).

$ xxd -l 512 -s $(expr $(echo $((0x22))) \* 2048) out/bootdisk.iso



5. Выведем LBA сектора, где располагается образ раздела ESP, необходимый для загрузки средствами UEFI.


$ xxd -l 4 -s $(expr $(echo $((0x21))) \* 2048 + 32 \* 3 + 8) out/bootdisk.iso

6. Выведем первые 512 байт образа ESP.

$ xxd -l 512 -s $(expr $(echo $((0x23))) \* 2048) out/bootdisk.iso


LBA адресов теоретически могут быть у вас быть другие. Я привёл те, которые были у меня.

Вы можете получить LBA адресов, по которым располагается откомпилированная программа на ассемблере, используя структуры MBR и GPT, находящиеся в первых секторах, изучив документацию по MBR и GPT. Здесь я приводить не буду, оставляю на самостоятельное изучение. Скажу только, что они будут отличаться, так как используются в этом случае сектора по 512 байт, а не по 2048.

Создание среды для сборки


Для создания воспроизводимого окружения для сборки очень удобно использовать Docker. Он позволяет создавать изолированные окружения с необходимыми зависимостями. Мы тоже будем использовать его, ниже я привожу Dockerfile.

FROM ubuntu:22.10
RUN apt update && apt install --yes make gcc-mingw-w64 fasm gnu-efi binutils
RUN apt install --yes mtools dosfstools xorriso isolinux xxd
RUN apt install --yes qemu-system-x86 ovmf 
WORKDIR /app/

Вы можете собрать образ Docker со всеми необходимыми для сборки зависимостями, используя команду.

$ docker build -t boot-hello-world:latest . 

Для запуска контейнера в интерактивном режиме в PowerShell в директории, где у вас содержатся файлы bioshello.asm и efihello.c нужно ввести команду.

$docker run --name isobuilder -v ${pwd}:/app --rm -it boot-hello-world bash

Автоматизация сборки ISO-образа


Для автоматизации сборки из исходников существует множество различных утилит, но для простоты мы будем использовать make.

Основное отличие утилиты make от обычных shell-скриптов заключается в том, что она:

  • отслеживает зависимости в исходных файлах;
  • пересобирает только при наличии изменений.

Ниже привожу файл Makefile, который автоматизирует сборку и позволяет запускать этот образ в эмуляторе qemu в различных режимах.

CC = x86_64-w64-mingw32-gcc 
CFLAGS = -shared -I/usr/include/efi -nostdlib -mno-red-zone -fno-stack-protector -Wall -e EfiMain

BUILDDIR = build
OUT = out
ISO_DIR = $(BUILDDIR)/iso-image
EFI_BOOT_DIR = $(ISO_DIR)/EFI/boot

EFI_APP = bootx64.efi
BIOS_APP = bootsec.bin
ESP_IMAGE = uefi.img
BOOT_ISO = $(OUT)/bootdisk.iso

HYBRID_MBR = /usr/lib/ISOLINUX/isohdpfx.bin
TARGETS = $(BOOT_ISO)

all: $(TARGETS)  	

$(BUILDDIR):
	mkdir -p $(BUILDDIR)
	mkdir -p $(OUT)

$(BUILDDIR)/$(BIOS_APP): bioshello.asm | $(BUILDDIR)
	@echo "[BUILDING BIOS APP]"
	fasm $< $@

$(BUILDDIR)/$(EFI_APP): efihello.c | $(BUILDDIR)
	@echo "[BUILDING EFI APP]"
	$(CC) $(CFLAGS) $< -o $@.dll
	objcopy --target=efi-app-x86_64 $@.dll $@

$(BUILDDIR)/$(ESP_IMAGE): $(BUILDDIR)/$(EFI_APP) | $(BUILDDIR)
	@echo "[BUILDING ESP IMAGE]"
	dd if=/dev/zero of=${BUILDDIR}/${ESP_IMAGE} bs=512 count=2880
	mkfs.msdos -F 12 -n 'EFIBOOTISO' ${BUILDDIR}/${ESP_IMAGE}
	mmd -i ${BUILDDIR}/${ESP_IMAGE} ::EFI
	mmd -i ${BUILDDIR}/${ESP_IMAGE} ::EFI/BOOT
	mcopy -i ${BUILDDIR}/${ESP_IMAGE} ${BUILDDIR}/${EFI_APP} ::EFI/BOOT/bootx64.efi

$(ISO_DIR): $(BUILDDIR)/$(BIOS_APP) $(BUILDDIR)/$(ESP_IMAGE)
	@echo "[CREATING ISO DIRECTORY WITH FILES]"
	mkdir -p ${ISO_DIR}/boot
	mkdir -p ${EFI_BOOT_DIR}
	cp ${BUILDDIR}/${EFI_APP} ${EFI_BOOT_DIR}/
	cp ${BUILDDIR}/${BIOS_APP} ${ISO_DIR}/boot/
	cp ${BUILDDIR}/${ESP_IMAGE} ${ISO_DIR}/boot/   

$(BOOT_ISO): $(ISO_DIR)
	@echo "[BUILDING HYBRYD ISO FILE]"
	xorriso  -as mkisofs -V "HybridBootISOSample" -o $@ -isohybrid-mbr $(HYBRID_MBR) -c boot/boot.cat -b boot/$(BIOS_APP) -no-emul-boot -boot-info-table \
	-boot-load-size 4 -eltorito-alt-boot -e boot/$(ESP_IMAGE) -no-emul-boot -isohybrid-gpt-basdat $(ISO_DIR) --sort-weight 0 /boot --sort-weight 1 /
	@echo "The Hybrid ISO file [$@] was created. You can burn it to CD/DVD or to the flash disk and test"

clean:
	@echo "[PERFORMING CLEAN]"
	rm -rf $(BUILDDIR)
	rm -rf $(OUT)

qemu-bios-cdrom: $(BOOT_ISO)
	@echo "[STARTING QEMU WITH BIOS FIRMWARE FROM CDROM]"
	qemu-system-x86_64 -boot d -cdrom $(BOOT_ISO) -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio

qemu-efi-cdrom: $(BOOT_ISO)
	@echo "[STARTING QEMU WITH UEFI FIRMWARE FROM CDROM]"
	qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -boot d -cdrom $(BOOT_ISO) -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio

qemu-bios-flash-disk: $(BOOT_ISO) 
	@echo "[STARTING QEMU WITH BIOS FIRMWARE FROM FLASH DISK]"
	qemu-system-x86_64 -boot d -hda $(BOOT_ISO) -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio
 
qemu-efi-flash-disk: $(BOOT_ISO)
	@echo "[STARTING QEMU WITH UEFI FIRMWARE FROM FLASH DISK]"
	qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -boot d -hda $(BOOT_ISO) -nographic -net none -monitor telnet::45454,server,nowait -serial mon:stdio 

Данный Makefile позволяет собрать ISO-образ (make clean all), а также запустить его в эмуляторе с BIOS, UEFI, с флеш-накопителя и cdrom, что понятно из названий.

Полезные ссылки


  1. Спецификация ISO 9660 (ECMA 119).
  2. Cпецификация El Torito.
  3. Спецификация UEFI.
  4. Docker Desktop.
  5. SD Card Memory Formatter — программа для форматирования (форматирует USB-накопители тоже). Иногда помогает, когда программы записи образов отказываются записывать образ.
  6. balenaEtcher — программа для записи образов на флеш-накопитель.
  7. Win32 Disk Imager — программа для записи образов на флеш-накопитель. Иногда записывает, когда и balenaEtcher отказывается.
  8. wiki.osdev.org — сайт с информацией по разработке ОС, где среди прочего есть информация по загрузке ОС.
  9. wiki.archlinux.org — сайт с исчерпывающей информацией по операционным системам, но лучше искать информацию на нём с помощью Google.

Заключение


В статье создан минимальный гибридный ISO-образ, который позволяет понять основы загрузки на компьютерах (BIOS и UEFI c жёсткого диска, флеш-накопителя, оптического диска). Многие вопросы не были рассмотрены с целью упрощения, так как статья имеет познавательный, а не энциклопедический характер и не рассчитана на тех, кто имеет значительный опыт по этой теме.

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

Я не рассматривал загрузочные образы операционной системы Windows и реализацию загрузки с оптических дисков в Windows, но, получив знания из статьи, вам будет гораздо проще понять, так как там тоже используется El Torito.

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

Играй в нашу новую игру прямо в Telegram!

Комментарии (67)


  1. oxx
    04.01.2023 12:46
    +4

    Скажите често, это кого-то интересует в 2022 году? А то я прямо целый проект убил на эту тему, потому что спроса больше нет.


    1. ParaParadox
      04.01.2023 13:04
      +18

      Если для Вас эта информация бесполезна, значит и другим не нужна? Странная у Вас логика.


      1. oxx
        04.01.2023 13:22
        +12

        Видимо вы неправильно поняли мой комментарий. Мне искренне интересно, есть ли все еще спрос на эту тему. Я посвятил ей более 25 лет, но просто спроса более не наблюдаю, только в контексте прочтения старых образов. В какой области это сейчас востребовано?


        1. rPman
          04.01.2023 14:50
          +15

          Какой спрос вы ожидаете?
          Данная статья очень полезная, раскрыто практически все что нужно плюс даже предлагается реализовать свой загрузчик. Т.е. целевые аудитории этой статьи пересечение двух далеких — девопс, те кому нужно настраивать и устанавливать системы, восстанавливать с помощью загрузчика в нестандартных ситуациях и т.п. (например, как сделать загрузочный диск для рекавери если usb/cdrom не работают но есть второй диск?) и вторая — разработчики и тестириовщики ос (загрузчик), красивый пример — к вам пришел заказчик и сказал хочу загрузчик со… «странным» функционалом, grub/syslinux не подходят (точнее потребуется их модификация) как один из способов защиты данных от несанкционированного доступа в условиях железа с ограниченным функционалом.

          p.s. очень жаль что покрыта только x86 архитектура, все чаще приходится работать с arm (android, rpim,,) и почти наверняка скоро в ходу будут полноценные железки со своими стандартами


        1. ParaParadox
          04.01.2023 15:47
          +8

          Спрос на какую либо тему это, ИМХО, не главный показатель. Взять, к примеру, ролики в топе YouTube с миллионами просмотров при нулевой, лично для меня, ценности. А количество подписчиков на канал с видеоуроками одного хорошего человека, которые мне очень помогли в понимании WPF+MVVM, менее 2000. Спрос на тему в рамках YouTube минимальный, но в определённых кругах очень даже имеется.


          1. rPman
            04.01.2023 17:02
            +3

            и вообще оценивать полезность через популярность это как спрашивать, сколько будет «2+2» через опросы.


        1. Tomasina
          04.01.2023 21:28

          Мне интересно. Ибо в парке есть как современные ПК, так и очень древние, типа Пентиум 4 с шиной IDE HDD. И часто нужна универсальная флешка, с которой можно загрузиться на любом компе. А вот найти такой образ весьма непросто.


          1. DaemonGloom
            05.01.2023 10:05
            +3

            В такой ситуации лучше завести две флешки. Причём под старье ещё и стоит попытаться найти флешку с U3 — они умели притворяться usb CDROM, что позволяет грузиться на большем числе старых компьютеров. А вторую флешку — обычную, под современные компы.


          1. storoj
            05.01.2023 16:06

            А как насчёт легендарных Zalman VE-200?


            1. Tomasina
              05.01.2023 16:34

              Кушает много (не все порты так умеют), и в ТХ упоминание USB 3.0 (может и некритично).


              1. storoj
                05.01.2023 16:52

                Вроде бы у VE-200 (самого первого) был всё же USB 2.0


          1. R0bur
            07.01.2023 11:08

            Установить на флешку GRUB2 в режиме BIOS/UEFI, после чего из него запускать дистрибутивы - недостаточно?


        1. edo1h
          05.01.2023 03:08
          +3

          В какой области это сейчас востребовано?

          То есть в какой? В области установки ОС и/или загрузки livecd.
          Что тут изменилось в последнее время? Дистрибутивы всё так же распространяются в виде iso.


    1. Wesha
      05.01.2023 01:51
      +6

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

      А в 2023, например, меня интересует. Я многое и сам знал — но далеко не всё.


  1. Dr_Faksov
    04.01.2023 13:45
    -7

    Ситуация, когда BIOS инициализирует(или нет) UEFI видел многократно. Наоборот не видел никогда. Я бы сказал, что BIOS грузится всегда, после чего передаёт( или нет) управление UEFI.


    1. vadimr
      04.01.2023 13:49
      +6

      Например, на Маках нет BIOS.


      1. Didimus
        04.01.2023 13:53
        -7

        Статья про х86. Нет биоса на тех, где другие архитектуры?


        1. vadimr
          04.01.2023 13:54
          +7

          На Маках x86 тоже нет биоса.

          Кроме того, я не заметил, чтобы статья была про x86.


      1. Dr_Faksov
        04.01.2023 14:33

        На нет и суда нет. Зачем об этом говорить? Речь идёт про случаи где есть обе системы.


        1. vadimr
          04.01.2023 14:35
          +2

          Вы написали двумя комментариями выше:

          Я бы сказал, что BIOS грузится всегда, после чего передаёт( или нет) управление UEFI.

          Это утверждение неверно. Но говорить о том, что оно неверно, Вы почему-то не хотите.


          1. Dr_Faksov
            04.01.2023 15:19
            +2

            Во-первых, я не утверждаю что оно истинно. Я не зря написал "Я бы сказал"

            Во-вторых, ваша аргументация сводится к утверждению, в моём понимании, -"В архитектурах не поддерживающих систему BIOS, BIOS не загружается, поэтому нельзя утверждать что BIOS загружается всегда". К данной статье оно неприменимо, так как в ней дёт речь об архитектурах, поддерживающих ОБЕ системы.

            А вообще, я бы расширил и дополнил вышеприведённый аргумент до вида "В архитектурах не поддерживающих системы BIOS и UEFI, BIOS и UEFI не загружается, поэтому нельзя утверждать что обе они необходимы именно для работы с дисками"


    1. CodeRush
      05.01.2023 01:32
      +25

      В действительности, все не так, как на самом деле.

      BIOS - это собирательное название прошивок x86 систем в том виде, в котором их начала выпускать IBM, т.е. таких, которые стартовали и работали в 16-битном режиме исполнения, имели текстовый или псевдографический интерфейс BIOS Setup, и предоставляли операционной системе интерфейс BIOS Interrupt Call, основанный на программных прерываниях. По мере развития железа и перехода на 32, а затем и 64-битные процессоры 16-битная прошивка стала серьезной обузой, как и устаревший и несовместимый с новыми устройствами интерфейс BIOS IC, и от них начали понемногу избавляться в пользу комбинации из трехфазового Platform Interface (32-битной Pre-EFI Initialization, где происходит тренировка памяти, чтобы перестать исполнять код с SPI flash, 32\64-битной Driver Execution Environment, где происходит вся остальная инициализация железа, и 32\64-битной Boot Device Selection, которая рисует графический Setup, запускает Option ROMы, находит на известных ей ФС загрузчик ОС и передает на него управление). При этом BDS (совместно с DXE) и реализует тот самый Unified Extensible Firmware Interface, который загрузчик ОС затем использует вместо устаревшего BIOS Interrupt Call. Тем не менее, последний все еще поддерживается на многих системах при помощи механизма Compatibility Support Module, который позволяет UEFI-совместимой прошивке публиковать не только свой нативный (32\64-битный) UEFI, но и оставленный для обратной совместимости 16-битный BIOS IC, и сделано это при помощи довольно хитрых трамплинов в старый режим и обратно. Запускается CSM частично в D
      XE, частично в BDS, а работает только в BDS (потому что загрузчики ОС работают только там).

      Таким образом, из "BIOS запускает UEFI", и "UEFI запускает BIOS" - это бессмысленные выражения. На старых компьютерах 16-битный BIOS имел 16-битный интерфейс IC, и никакого UEFI там не было еще. На новых компьютерах 32-битный PEI запускает 32\64-битный DXE, который запускает 32\64-битный BDS, который имеет либо только 32\64-битный UEFI, либо еще и 16-битный CSM, который эмулирует старый 16-битный IC в достаточной степени, чтобы старые загрузчики запускались.

      BIOS IC и UEFI - не единственные интерфейсы между прошивкой и ОС на x86, как и BIOS и PI не единственные способы добраться до них. Вместо BIOS и PI можно использовать coreboot, вместо DXE/BDS/IC/UEFI - напрямую запускать ядро Linux или любой другой ОС. Интерфейс UEFI тоже не обязательно публикуется DXE и BDS, его могут публиковать и другие загрузчики, например, uBoot или TianoCore payload для coreboot.

      Короче: BIOS - это собирательное название 16-битного всего, что работало на старых х86-машинах до ОС. UEFI - это интерфейс между прошивкой и ОС, и ничего больше. Прошивка же сама по себе называется "UEFI-совместимой", если на публикует вышеупомянутый интерфейс.


    1. qw1
      05.01.2023 12:44
      +1

      Ситуация, когда BIOS инициализирует(или нет) UEFI видел многократно. Наоборот не видел никогда
      Как это определить, не прибегая к дизассемблированию ROM-образа?

      Довольно давно на материнских платах Setup работает в графическом режиме и понимает всякую периферию, типа USB-мышек и BT-клавиатур.

      На месте писателя BIOS, я бы всё это делал в 32/64-битном режиме. Потому что писать сейчас 16-битный код для UI или драйверов устройств — невообразимая пытка.


  1. vadimr
    04.01.2023 13:51

    ISO-образ в данном контексте – это же образ раздела, а не всего диска, правильно? Если мы захотим скопировать ISO-образ загрузочного DVD посекторно на флешку, то должны его копировать на раздел, а не на устройство?


    1. oxx
      04.01.2023 14:01

      Посекторное копирование из ISO возможно только на CD/DVD (размер физического сектора 2048 против 512). На флешку просто извлекаются данные (включая загрузочный файл).


      1. vadimr
        04.01.2023 14:03

        Ну никто ж не мешает сектор размером 2048 разместить в четырёх секторах размером 512. Я именно посекторно всегда копировал (может быть, правильнее назвать это побайтным для исключения споров), но каждый раз зависаю перед выбором приёмного устройства – диск или раздел.


        1. oxx
          04.01.2023 14:33

          Файловая система разная, способ загрузки разный, короче тут конвертация а не копирование на флешку.


          1. artyomsoft Автор
            04.01.2023 14:41
            +3

            Гибридный ISO образ позволяет копировать себя посекторно на флеш-накопитель, так как он содержит таблицу разделов и раздел, с которого будет осуществляться загрузка


            1. oxx
              04.01.2023 17:31

              <Зануда mode on>
              Боюсь путаница с терминологией только усугубилась.

              ISO - образ CD/DVD/BD диска с файловой системой ISO-9660 + расширения (RockRidge, Joliet, ElTorito) или UDF (опять же с кусочком совместимости с ISO-9660).

              За загрузчика отвечает расширение ElTorito, которое просто указывает на файл, который еще должен быть виден через ISO-9660

              Понятие "раздел" имеет смысл только для UDF, где есть таблица разделов на уровне структуры UDF. Классический ISO-9660 не имеет разделов, а запись на диски оперирует понятием "сессия", но это совсем другое.

              Гибридный диск (если мы говорим о Hybrid-CD), то это ныне забытый формат CD (и только CD), где аудио-дорожки соседствуют с даннными, но его невозможно сохранить в ISO по определению (можно только BIN, MDF, и т.д.).

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

              Обычные утилитки вроде https://www.microsoft.com/en-us/download/windows-usb-dvd-download-tool просто-напросто пишут свой boot sector, который умеет искать загрузчик самого Windows в корневом каталоге конкретной файловой системы.


              1. artyomsoft Автор
                04.01.2023 18:25

                За загрузчика отвечает расширение ElTorito, которое просто указывает на файл, который еще должен быть виден через ISO-9660

                Спецификация El Torito не оперирует понятиями файл, она оперирует понятием сектор. В Booting Catalog хранятся LBA для первого сектора, где находится bootloader (для загрузки через BIOS) и LBA первого сектора, где находится образ раздела ESP (для загрузки через UEFI)

                Понятие "раздел" имеет смысл только для UDF, где есть таблица разделов на уровне структуры UDF. Классический ISO-9660 не имеет разделов, а запись на диски оперирует понятием "сессия", но это совсем другое.

                В UDF (Universal Disk Format) нет таблицы разделов - это файловая система. В моем понимании таблица разделов содержит информацию о том, какие сектора принадлежат конкретному разделу, а на разделе размещается файловая система. Файловая система, может занимать весь диск (блочное устройство), например, на дискете.

                Гибридный диск (если мы говорим о Hybrid-CD), то это ныне забытый формат CD (и только CD), где аудио-дорожки соседствуют с даннными, но его невозможно сохранить в ISO по определению (можно только BIN, MDF, и т.д.).

                Нет. Мы говорим об образе, который содержит MBR, загрузочный сектор и/или GPT, которые при записи всего образа на флеш-накопитель позволят загрузиться с него.

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

                Вот тут я не понял, что Вы имеете ввиду

                Обычные утилитки вроде https://www.microsoft.com/en-us/download/windows-usb-dvd-download-tool просто-напросто пишут свой boot sector, который умеет искать загрузчик самого Windows в корневом каталоге конкретной файловой системы.

                Да. Я это рассматриваю в главе "Ещё один способ создания загрузочного флеш-накопителя в Windows", где это делается обычными командами Windows, но это не имеет никакого отношения к гибридному ISO.


                1. oxx
                  04.01.2023 19:01

                  Спецификация El Torito не оперирует понятиями файл, она оперирует понятием сектор. В Booting Catalog хранятся LBA для первого сектора, где находится bootloader (для загрузки через BIOS) и LBA первого сектора, где находится образ раздела ESP (для загрузки через UEFI)

                  LBA указателю в ElToriro безразлично BIOS его читает или UEFI, главное чтобы LBA был валидным с точки зрения ISO-9660. А содержимое загрузчика стандартом, к счастью, не регламетируется, хотя стандарт и был изначально рассчитан на BIOS.

                  В UDF (Universal Disk Format) нет таблицы разделов - это файловая система. В моем понимании таблица разделов содержит информацию о том, какие сектора принадлежат конкретному разделу, а на разделе размещается файловая система. Файловая система, может занимать весь диск (блочное устройство), например, на дискете.

                  Совершенно верно. В UDF 2.5 и выше есть понятие разедлов, но они все до единого технические, ибо тот же стандарт предписывает иметь только один раздел для самих данных.

                  Нет. Мы говорим об образе, который содержит MBR, загрузочный сектор и/или GPT, которые при записи всего образа на флеш-накопитель позволят загрузиться с него.

                  Еще раз, образ CD-диска (неважно ISO или UDF) не имеет разделов, не содержит GPT или MBR по структуре, я не понимаю, с чего вы это решили.

                  Вот тут я не понял, что Вы имеете ввиду

                  Бинарный образ, на который ссылается ElTorito volume может содержать какой угодно код, и, теоретически, может сам справиться с определение среды, носителя и файловой системы.

                  Да. Я это рассматриваю в главе "Ещё один способ создания загрузочного флеш-накопителя в Windows", где это делается обычными командами Windows, но это не имеет никакого отношения к гибридному ISO.

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


                  1. artyomsoft Автор
                    04.01.2023 19:42
                    +3

                    Еще раз, образ CD-диска (неважно ISO или UDF) не имеет разделов, не содержит GPT или MBR по структуре, я не понимаю, с чего вы это решили.

                    Гибридный ISO содержит MBR и GPT https://wiki.syslinux.org/wiki/index.php?title=Isohybrid.

                    $ xxd -l 512 out/bootdisk.iso

                    $ xxd -l 512 -s 512 out/bootdisk.iso

                    $ xxd -l 512 -s 1024 out/bootdisk.iso

                    Наверное моя вина, что не привел в статье, исправлю, добавлю вывод первого сектора в iso файле. Можете такую же комаднду выволнить и посмотреть, что находится в iso популярных Linux дистрибутивов (Ubuntu, Debian и др.) В образах Windows такого нет. Там, как и должно быть первые 16 секторов по 2048 байт содержат 0.

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

                    Я нигде не у потреблял словосочетание "гибридный диск". https://wiki.syslinux.org/wiki/index.php?title=Isohybrid.


    1. artyomsoft Автор
      04.01.2023 14:09
      +3

      Если Вы имеете ввиду гибридный ISO образ, то он содержит MBR и/или GPT, соответственно, если Вы хотите записать весь на загрузочный флеш-накопитель, то Bам нужно посекторно записывать на диск, а не раздел


      1. oxx
        04.01.2023 14:33

        Вы не путаете ISO и UDF?


        1. vadimr
          04.01.2023 14:37

          В вопросе я имел в виду ISO просто как формат файла, а не конкретно файловую систему ISO-9660.


        1. artyomsoft Автор
          04.01.2023 14:46
          +2

          Нет, не путаю


          1. oxx
            04.01.2023 17:32
            -2

            Можно ссылку на документацию? MBR/GPT вообще к ISO отношения не имеют.


            1. artyomsoft Автор
              04.01.2023 18:32

              Для начала можно это почитать https://wiki.syslinux.org/wiki/index.php?title=Isohybrid


              1. oxx
                04.01.2023 18:47

                Форматируется USB под GPT, потом туда извлекаются файлы из ISO - я это и говорил. GPT данных в ISO нет, но есть совместимые в структуре UDF. Более того, UDF можно напрямую монтировать вместе со всеми разделами, даже не меняя ничего.


              1. oxx
                04.01.2023 19:16
                -1

                Давайте так, я суммирую ваше утверждение, а вы мне скажете, правильно я понял, или нет:

                • Стандарт ISO подразумевает начало данных с MSF 2:0:0 или LBA 150. Все предыдущие сектора для дисков данных априори считаются заполненными нулями

                • Ваша идея заключается в том, чтобы в неиспользуемое пространство дописать таблицу разделов, оформить ISO-9660 как отдельный ее раздел и добавить раздел для загрузчика

                Т.е. фактически это попытка сделать универсальный формат, наподобие экспериментов с universal executive, где за счет легаси classic MZ-section прописывают заголовки для ELF, и это тоже не 100% корректно. И, опять же, термин Hybrid CD image уже занят на mixed-mode (data+audio), поэтому его использование не совсем корректно.

                Технически же я вижу 2 проблемы:

                • Программы для записи ISO на CD/DVD чаще всего игнорируют первые 150 секторов, если они даны в формате ISO, а не BIN. Есть риск потери данных при записи на оптический носитель (если таковая операция, конечно, вообще предусметривается)

                • Секторы, на которых расположен загрузчик, должны быть видны из ISO-9660. Опять же, при записи на носитель такие области данных будут просто проигнорированы, если находятся за пределами LBA прописыных в ISO Volume. Проще всего представить такой загрузчик как файл на уровне файловой системы (как в ElTorito). Если, конечно, раздел не сликом большой и помещается в 2 GB.

                  Собственно, это все, что вызвало у меня вопросы.


                1. DaemonGloom
                  04.01.2023 19:53
                  +3

                  Примерно так. Только технические проблемы не имеют значения, поскольку это именно hybrid iso. Когда его уже записали — то он или флешка, или диск. И возможность получить hybrid iso обратно из записанного образа уже особо никого не волнует. Используется как раз для разнообразных загрузочных дисков, которые можно в итоге просто залить хоть на CD/DVD, хоть на флешку через dd и загрузиться с неё.


                1. artyomsoft Автор
                  04.01.2023 20:09
                  +2

                  Стандарт ISO подразумевает начало данных с MSF 2:0:0 или LBA 150. Все предыдущие сектора для дисков данных априори считаются заполненными нулями

                  Нет. Размер блока (сектора) 2048 байт. В стандартном (негибридном ISO) ненули начинаются с LBA 16. Там располагается Primary Volume Descriptor, по LBA 17 располагается Boot Record Volume.

                  Ваша идея заключается в том, чтобы в неиспользуемое пространство дописать таблицу разделов, оформить ISO-9660 как отдельный ее раздел и добавить раздел для загрузчика

                  Нет. ISO-9660 и MBR GPT существуют параллельно. В таблице разделов (как и MBR так и GPT) указывается LBA данных, где располагается раздел ESP (для UEFI загрузки), а по LBA 0 - располагается загрузочный сектор (для BIOS загрузки). Размер блока (сектора) 512 байт. Для ISO-9660 - размер блока 2048 байт. В зависимости от того, куда будет производиться запись образа на флешку или на оптический диск, структра будет рассматриваться по-разному.

                  Программы для записи ISO на CD/DVD чаще всего игнорируют первые 150 секторов, если они даны в формате ISO, а не BIN. Есть риск потери данных при записи на оптический носитель (если таковая операция, конечно, вообще предусметривается)

                  Про первые 150 секторов не знал, да и я все-таки думаю, что первые 16 секторов по 2048 байт. Но это никак не помешает, так как 0 и следующие за ним сектора, которые содержат MBR/GPT/Boot сектор нужны только для загрузки с флешки.

                  Секторы, на которых расположен загрузчик, должны быть видны из ISO-9660. Опять же, при записи на носитель такие области данных будут просто проигнорированы, если находятся за пределами LBA прописыных в ISO Volume. Проще всего представить такой загрузчик как файл на уровне файловой системы (как в ElTorito). Если, конечно, раздел не сликом большой и помещается в 2 GB.

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

                  Я понимаю, что это сложно осмыслить, сам осмысливал достаточно долго, поэтому советую перечитать статью и ссылку, что я Вам давал.


  1. Didimus
    04.01.2023 13:54
    -3

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


    1. vadimr
      04.01.2023 14:00
      +7

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

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


    1. dartraiden
      04.01.2023 21:52
      +1

      С моей точки зрения очень удобно, что я могу просто скопировать все файлы с установочного диска Windows на флешку и всё — она автоматически становится загрузочной без секса с Rufus, Ventoy и так далее.


      1. fshp
        05.01.2023 01:23
        +2

        Нет не можете. UEFI умеет загружаться с FAT32, который не умеет хранить файлы больше 2 гигабайт. А в инсталляторе винды как раз есть такие файлы.

        А вот копирование на NTFS действительно работает. Но только лишь потому что в заголовке NTFS раздела есть загрузчик, который ищет на разделе ntldr. Но это работает только для Legacy и никакого отношения к UEFI не имеет.

        Вообще архив в инсталляторе винды можно перепаковать в несколько томов размером до 2 гигабайт. Но это не "просто скопировать файлы".


        1. CodeRush
          05.01.2023 01:58
          +2

          Только 4 Гб, и тот факт, что MS не могут исправить проблему со слишком большими файлами (особенно с учетом того, что формат WIM поддерживает нативно нарезку на файлы любого размера) и тем, что установщику ОС не нравится наличие EFI-раздела на носителе, с которого происходит установка - результат безалаберного отношения к тому небольшому количеству пользователей, которые устанавливают ОС с нуля, а не получают ее предустановленой при покупке железа.

          UEFI тут не при чем, и винить его разработчиков не в чем.


          1. fshp
            05.01.2023 02:10

            Действительно 4, почему-то 2 в памяти было.

            Не виню разработчиков UEFI. Лишь хотел обратить внимание, что рабочий копипаст файлов основан совсем на другом способе загрузки.


        1. dartraiden
          05.01.2023 13:53
          +2

          Нет не можете. UEFI умеет загружаться с FAT32, который не умеет хранить файлы больше 2 гигабайт. А в инсталляторе винды как раз есть такие файлы.
          В прошивках десктопных мамок зачастую есть драйвер для чтения/записи NTFS, поэтому очень даже могу. Это не абстрактные рассуждения, на текущей мамке я именно так и делаю.

          Если драйвера нет, его можно внедрить самостоятельно.


          1. fshp
            05.01.2023 17:33

            Внедрение драйвера ничем не отличается от загрузки через grub например. Вам все равно нужен fat32 раздел, что бы этот драйвер сначала загрузить с него.

            Встроенный драйвер ntfs все равно является привязкой к вендору. Т.е. не получится создать флешку простым копипастом, что бы она работала везде. А ведь изначально я возразил о том, что UEFI позволяет упростить установку винды. А вот и нет. Не каждая материнка без танцев загрузит инсталлятор с NTFS через UEFI, но каждая загрузит с NTFS в легаси режиме.


            1. rPman
              05.01.2023 17:42
              +1

              легаси режим тоже не идеален

              у меня были материнки (и не одна) старые я имею в виду, в которых mbr загрузка с флешки работала только если ее размер не превышает кажется 8Гб (долгое время у меня была 4Гб флешка которую ну все понимали, а вот остальные — лотерея)

              Если говорить про гарантии — самый универсальный способ — это cdrom (не usb), вот уж где точно все работало, если есть загрузочный dvd будь спокоен на любой материнке, какая бы старая она не была, если есть ide/sata cd/dvd — все загрузится.
              upd. нет была одна материнка, у которой sata cdrom не обнаруживал биос но обнаруживал windows, что то мне говорит это решалось обновлением биоса


            1. dartraiden
              05.01.2023 18:13

              Внедрение драйвера ничем не отличается от загрузки через grub например. Вам все равно нужен fat32 раздел, что бы этот драйвер сначала загрузить с него.

              Драйвер внедряется прямо в прошивку.


        1. Busla
          05.01.2023 14:05
          +2

          Многие вендоры материнок пихают в прошивку UEFI-драйвер NTFS, поэтому UEFI-загрузка с NTFS-флэшек вполне массовое явление.


          1. dartraiden
            05.01.2023 18:15

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


    1. CodeRush
      05.01.2023 01:47
      +6

      Потому что очень устали тренировать десятки гигабайт памяти 16-битным кодом с 64кб на страницу и пояснять такому же 16-битному коду на ассемблере, написанному в 1992 году, что у нас теперь диски по 2 терабайта, и переферия вся подключена по USB.

      Ко временам чипсета P55 там в 16-битном БИОСе этом творилась такая дикая вакханалия чада и угара, что переход на UEFI Platform Interface (т.е. на PEI/DXE/BDS) в следующем поколении решил огромное количество проблем. При этом некоторые вендоры даже не стали этот самый UEFI публиковать, все равно на тот момент загрузчиков совместимых почти не было, и прошивка продолжала делать вид, что она BIOS, с переменным успехом. Некоторые вендоры потом таки опубликовали новый интерфейс обновлением прошивки, но есть еще модели, в которых это приходится делать разблокировкой скрытых опций. К 2012 году на UEFI PI в качестве базы и UEFI в качестве интерфейса с загрузчиками и ОС ПК-индустрия перешла окончательно, последние сервера HP с БИОСами как раз в конце 2011 и вышли, ЕМНИП.

      В общем, зачем - чтобы жить проще стало и не нужно было писать на ассемблере драйверы для USB, PCIe и Thunderbolt, и потому, что вендоры процессоров продавили с одной стороны, в вендоры ОС - с другой. Intel к тому времени над UEFI работал уже 13 лет, и уже лет 5 как поставлял Memory Reference Code в виде 32-битного бинаря, который с 16-битным БИОСом тоже надо было женить при помощи мата и уговоров, поэтому рано или поздно с дохлой лошади наконец слезли, и теперь вот понемногу слезают с CSM, который уже отключен по умолчанию почти на всех платах начиная с 2020 года, а на некоторых его уже нет совсем.


      1. Didimus
        05.01.2023 09:07

        Собравши много компьютеров и починив кучу ноутбуков знакомым, сколько раз ловил проблемы именно из-за уефи. То они вендорлок туда зашили, то оно дисковод не поддерживает... На старых платах все работало как часы (кроме саундкарт, это да)


  1. Chelidonium
    04.01.2023 14:18
    +3

    неизбежно вспоминаются публикации давней давности


  1. gumanzoy
    04.01.2023 21:34
    +1

    Пытался осилить man xorriso но не смог. Для создания гибридных загрузочных iso с grub2 подсказали простой способ.

    grub-mkrescue -o boot.iso папка_с_файлами

    В папке должен быть конфигboot/grub/grub.cfg

    В системе должны быть установлены пакеты grub-common grub-pc-bin grub-efi-amd64-bin


  1. CoolCmd
    04.01.2023 23:19
    +4

    cli
    xor ax, ax
    push ax
    pop es
    push ax
    pop ds
    sti

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

    зачем запрещать прерывания? вы же не ss:sp инициализируете.


    1. artyomsoft Автор
      04.01.2023 23:27
      +1

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


      1. CoolCmd
        05.01.2023 01:32
        +5

        если бы обработчик прерывания не сохранял регистры, то комп бы завис после первого прерывания.


    1. qw1
      05.01.2023 13:09

      зачем запрещать прерывания? вы же не ss:sp инициализируете.
      Так то инструкции pop ss / mov sp, ax выполняются процессором без прерывания. Разве что вы хотите сохранить совместимость с некоторыми непропатченными моделями процессоров 8086, где установка регистра ss не блокировала прерывания на следующей инструкции.


  1. remendado
    05.01.2023 12:54
    -2

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


    1. Wesha
      05.01.2023 13:06
      +7

      99,99 процентов аудитории записывают, когда это надо, загрузочные имиджи на флэшки при помощи rufus

      Здесь всё-таки хабр, здесь аудитория не такая! Реальные пацаны записывают загрузочные имиджи на флэшки при помощи dd if=my_image.iso of=/dev/da1 bs=1M


    1. edo1h
      05.01.2023 15:38
      +2

      99.99% и программы не пишут, что же теперь, о программировании на хабре не писать?


    1. dartraiden
      05.01.2023 18:19

      99,99 процентов
      rufus

      Смешная шутка. Учитывая то, что изрядная часть целевой аудитории руфуса не может осилить его (записал образ — он не грузится — помогите!).


  1. Iskatel_S
    05.01.2023 19:05

    Для UEFI образ El Torito не нужен.