Процесс загрузки компьютера

Казалось бы, нет задачи проще, чем загрузка компьютера: нажал на кнопку питания, и спустя непродолжительное время на экране появится интерфейс операционной системы. На самом же деле именно между этими двумя событиями в недрах машины и происходит все самое интересное. Особенно если используется UEFI и диск с разметкой GPT. Давай заглянем под капот твоего ноута или компа и посмотрим, как загружаются устройства, использующие самые современные технологии.

РЕКОМЕНДУЕМ:
Управление компьютером силой мысли

Что не так с BIOS?

Сам термин BIOS археологи впервые обнаружили в коде CP/M от 1975 года. Исходные тексты CP/M, в файле BDOS.PLM (CP/M 1.1) которых под авторством Гэри Килдалла и появилось упоминание BASIC I/O SYSTEM, Computer History Museum выложил в свободный доступ в 2014-м в честь 40-летия системы. Если тебе интересно ознакомиться с этим историческим артефактом, они доступны на сайте музея.

Базовая система ввода-вывода в некотором смысле выполняет функцию интерфейса между оборудованием и ОС, без нее операционка не загрузится, а железо останется холодным и безжизненным. К тому же в ней есть функции, которые можно вызывать из ОС для доступа к базовым возможностям оборудования, подобно тому, как приложения используют системные вызовы для доступа к функциям ОС. Однако операционные системы все же предпочитают использовать собственные драйверы для работы с оборудованием.

В x86-системах BIOS выполняет тестирование (POST) и инициализацию оборудования. Затем управление передается первичному загрузчику (master boot code), который ищет активный раздел и его загрузочный сектор, чтобы передать управление ему для загрузки операционной системы. В BIOS используется формат разметки MBR, который тем не менее строго определенного стандарта не имеет.

Например, Крис Касперски в своей книге «Восстановление данных. Практическое руководство» писал, что в последние четыре байта, отведенные под код первичного загрузчика, Windows записывала идентификатор диска, и это неизбежно убивало использующий их загрузчик. Таким образом, для корректной работы с Windows первичный загрузчик должен был занимать не более 442 байт вместо честно выделенных ему 446.

BIOS за 45 лет существования показала себя невероятным долгожителем мира IT, пережив дискеты, CP/M и PL/M, MS-DOS и Windows 9x. Но сколько ни обновляй ее под современные реалии, в выделенные для начального загрузчика 446 байт сейчас много ненужного не поместишь. Были у BIOS и другие недостатки, из-за которых назревала необходимость заменить 16-битную архитектуру, по крайней мере для «большого железа» вчетверо большей разрядности. Так посчитали ребята из Intel, и в 1998 году был основан проект Intel Boot Initiative. Исходная версия спецификации, разработанная в первую очередь для машин на Itanium (IA-64), была опубликована под названием EFI (Extensible Firmware Interface) в 1999 году. А в 2005-м на базе этого проекта появился Unified EFI Forum, занимающийся разработкой и поддержкой родившейся таким образом технологии по сей день.

Пришла беда откуда не ждали

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

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

Кроме того, интерфейс этот зовется унифицированным. Спецификация указывает одной из целей разработки UEFI сделать так, чтобы разные операционки могли грузиться на разном железе без внесения изменений в ОС или аппаратную платформу. Иными словами, UEFI играет роль дополнительного слоя абстракции, в стандарте определен даже EFI Byte Code (EBC). Цели, безусловно, благие. Жаль, исполнение подкачало — реализовывать стандарт каждый волен по-своему, и, к примеру, китайские прошивки, как иногда пишут на форумах, способны иной раз удивлять своим поведением.

Внедрение UEFI в пользовательские системы наделало немало шуму. Быть может, ты помнишь, как были рады линуксоиды, когда появились ноуты на Windows 8 и для их сертификации Microsoft требовала Secure Boot. При этом изначально предусматривать ее отключение или установку любых ключей, кроме ключей MS, не считалось необходимым. Нетрудно представить проблемы установки, а скорее даже запуска сторонних ОС в таком случае.

Не очень лестно об UEFI отзывался и Линус Торвальдс. В списке рассылки ядра Linux он говорит, что «EFI — это еще один факт повреждения мозга Intel (первым был ACPI)», и сожалеет, что UEFI захватывает x86-машины, тогда как появился он для IA-64. То ли дело BIOS, из которого никто не пытался соорудить карету и который делал лишь то, для чего был предназначен: just load the OS and get the hell out of there. По поводу Secure Boot Линус тоже как-то высказался не самым лестным образом.

Но все же давай посмотрим, какие у UEFI имеются достоинства.

Во-первых, с приходом UEFI размер диска больше не ограничен значением в 2 ТиБ и составляет 8 ЗиБ — такие носители, наверное, появятся еще не скоро. Во-вторых, его отличие от традиционных BIOS в том, что он загружает файлы со специального раздела EFI system partition (ESP), вместо того чтобы искать код начального загрузчика внутри таблицы разделов. То есть UEFI выступает более высокоуровневым загрузчиком, так как изначально способен работать с файлами на разделах (но из коробки, как правило, поддерживает только FAT, а для других файловых систем необходимо устанавливать драйверы UEFI). Достаточно отформатировать флешку в FAT и положить на нее в каталог /EFI/BOOT/ файл с образом, который UEFI подхватит для дальнейшей загрузки, и почти не надо думать загрузочная флешка готова!

Вместе с UEFI был разработан и новый стандарт разметки дисков GPT (GUID Partition Table). В спецификации UEFI называются следующие преимущества нового формата перед старым добрым MBR:

  • адреса логических блоков (LBA) стали 64-битными вместо 32-битных в MBR (чем и преодолели ограничение на размер диска в 2 ТиБ);
  • поддерживается намного больше разделов, чем четыре основных в MBR;
  • для обеспечения избыточности вводится запасная таблица разделов;
  • используется механизм контрольных сумм CRC32 для обеспечения целостности служебных таблиц;
  • используется GUID и читабельное имя раздела для его идентификации.

Давай теперь посмотрим, как это добро устроено и работает.

Немного об архитектуре системы UEFI

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

Загрузчики ОС, например GRUB2, для UEFI считаются приложением. Есть возможность даже загружать операционные системы напрямую из UEFI, минуя отдельный загрузчик, будь то GRUB, загрузчик Windows или любой другой. Для загрузки приложений и драйверов в UEFI используется Boot manager. Эти самые драйверы и приложения имеют расширение .efi и являются UEFI-образами, формат которых базируется на PE32/PE32+ или COFF.

Стандарт UEFI, помимо интерфейсов, имеет собственные протоколы взаимодействия своих модулей: Simple File Protocol для чтения файлов с устройств, протоколы взаимодействия драйверов и приложений со средой UEFI, среди которых Secure Boot, и много чего еще.

В рамках UEFI есть такая занятная вещь, как UEFI Shell. Этот шелл не всегда присутствует в прошивке компьютера, но можно создать загрузочную флешку и запускать шелл с нее. Или скопировать UEFI Shell на EFI-раздел диска, и после небольших страданий стараний он появится в опциях загрузки. UEFI Shell может пригодиться, например, для редактирования загрузчика UEFI, запуска UEFI-приложений или в каких-нибудь исследовательских целях.

Эта оболочка с интерфейсом командной строки позволяет без загрузки ОС выполнять простые файловые операции вроде просмотра содержимого директорий, копирования и удаления, запускать драйверы и приложения UEFI, работать с сетью и править меню загрузки. Существует дополнительный набор программ от Intel, UEFI Disk Utilities, с которым можно даже размечать диски. В оболочке поддерживается выполнение скриптов, перенаправление вывода и конвейер, файловые шаблоны, история команд и прочие вещи, напоминающие о bash (зато дополнение по табу не работает). Из-за подобных возможностей, превосходящих задачи простого первичного загрузчика, UEFI и называют иногда псевдоОС.

UEFI Shell в виртуалке. Русские имена файлов не показывает, зато он разноцветный
UEFI Shell в виртуалке. Русские имена файлов не показывает, зато он разноцветный

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

О разметке дисков GPT

Первый логический блок на носителе — LBA0 — содержит так называемый защитный (protective) MBR на случай, если старые программы, слыхом не слыхавшие о GPT, сочтут диск нерабочим и решат его исправить. Также благодаря защитному MBR вместо действительной разметки старое ПО будет видеть один большой раздел, именуемый GPT protective partition.

Следом идет первичная таблица GPT. В ней хранится заголовок GPT (GPT header) с общей информацией: сигнатурой и версией GPT, GUID диска, контрольными суммами служебных таблиц и прочими полезными вещами. Рядом с заголовком находится массив записей о разделах (Partition entry array), в котором описывается каждый раздел на носителе: GUID типа раздела, GUID раздела, LBA начала и конца, атрибуты и имя. После таблицы разделов следует FirstUsableLBA, то есть блок, который может быть использован непосредственно для раздела.

В первичной таблице есть LBA запасной (Backup) GPT, идентичной первой, только значения ее полей MyLBA и AlternativeLBA меняются местами. Запасная таблица находится в последнем блоке диска, перед ней расположена еще одна таблица с записями о разделах, так что поле PartitionEntryLBA также имеет другое значение.

Для хранения дополнительных программ UEFI может присутствовать относительно небольшой (в районе 100–200 Мбайт) системный раздел ESP. Обычно он располагается первым и имеет тип FAT32. В случае загрузочных флешек вся флешка форматируется в FAT, поэтому там нет необходимости создавать отдельный ESP. Значения системных переменных и конфигурация, например порядок загрузки, хранится в NVRAM.

Примерное относительное расположение всех этих элементов ты можешь посмотреть на схеме, более подробные определения таблиц доступны в спецификации.

Схематичное представление основных структур GPT
Схематичное представление основных структур GPT

Как видишь, здесь мало общего с разметкой MBR, нет практически никакой совместимости (есть, правда, Hybrid MBR, но мы о нем сейчас не будем говорить). Зато теперь можно насоздавать кучу здоровых разделов, причем без костылей в виде основных и расширенных томов.

Загрузочная последовательность

Загрузка в среде с UEFI тоже усложнилась, но не настолько, чтобы мы не сумели понять основные принципы. Например, так же как и в BIOS, выполняется начальная инициализация оборудования. Теперь за нее отвечает Platform Initialization (PI), спецификацию которой можно найти в первом томе документа Platform Initialization (PI) Specification. Примерно вот так выглядит загрузочная последовательность UEFI.

Процесс загрузки платформы с UEFI
Процесс загрузки платформы с UEFI

Рассмотрим шаги загрузки по порядку:

Инициализация оборудования (Pre-EFI Initialization)

На данном этапе всю работу выполняет, как уже сказано, часть стандарта под названием PI. PI должна определить причину старта (перезагрузка, выход из сна, простое включение) и инициализировать процессор, чипсет и системную плату. Сюда входит также организация среды выполнения драйверов, и может присутствовать модуль совместимости CSM (Compatibility Support Module) для загрузки с MBR, которая по умолчанию не поддерживается. После инициализации железа управление передается менеджеру загрузки. Он определяет, что загружать далее.

PI использует собственные бинари формата Terse Executable. Этот тип исполняемых файлов в целом очень похож на PE (может быть и COFF), но сигнатура MZ была заменена на VZ. Поговаривают, что совпадение с инициалами Винсента Циммера, труженика Intel и руководителя рабочей группы PI, абсолютно случайно.

Загрузка модулей EFI и загрузчика ОС

Менеджер загрузки определяет, какие драйверы и приложения UEFI должны обязательно быть загружены на конкретной системе, и при необходимости взаимодействует с пользователем. В качестве одного из таких приложений загружается и загрузчик UEFI (UEFI OS loader), но на этом этапе можно загрузить и оболочку UEFI. Вообще, загрузчик ОС может быть как собственным загрузчиком UEFI, так и любым другим, главное, чтобы он был нужного UEFI формата с расширением .efi. Для среды UEFI это в любом случае просто приложение, которое для работы с оборудованием должно использовать только сервисы и протоколы UEFI.

Завершение загрузочных сервисов

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

Концептуально загрузка с UEFI вроде не так сильно отличается от BIOS — здесь тоже есть нечто похожее на POST и на начальный загрузчик. Но появилась еще такая фича, как Fast Boot. Она связана с тем, что зачастую действия для инициализации железа операционная система все равно выполняет заново (скажем, заполняет таблицу прерываний). Чтобы не делать двойную работу, в UEFI данный этап может пропускаться, тем самым загрузка системы ускоряется.

Еще одна особенность UEFI называется Secure Boot (забавно, что в поисковиках первым среди предложений по этому запросу появляется «как отключить»). Это протокол, предназначенный для подписи драйверов и проверки исполняемых файлов. В первую очередь он предотвращает загрузку недоверенных образов UEFI, проверяя подписи этих образов перед запуском.

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

Тем не менее, чтобы при включенной Secure Boot загружать что бы то ни было на устройствах с установленными ключами Microsoft, эти бинарники должны быть соответствующим образом подписаны. Подписывать GRUB чревато задержками релизов, да и Microsoft не особо горит желанием выдавать ключ из-за используемой им GPLv3.

Это стало причиной появления так называемых предзагрузчиков: Shim и PreLoader (Loader.c), которые сами подписаны, но запускать могут уже не подписанные MS образы. Что они и делают, передавая управление GRUB’у или другому загрузчику. Нынче Shim используется такими дистрибутивами, как Fedora, Debian, Ubuntu, SUSE. Более подробно с анализом защищенности прошивки в ходе загрузки ты можешь ознакомиться в нашей статье про пентест UEFI.

Если кажется, что все потрачено…

От ошибок никто не застрахован, и потрачено все может быть по разным причинам. Юзер «что-то нажал», возникли баги в дисковых утилитах, а еще есть особенности работы GPT с RAID. Да и UEFI, бесспорно, сложнее BIOS, а чем объемнее код, тем легче ошибкам в него закрасться. Вот в разных реализациях и обнаруживаются баги, позволяющие обойти защитные механизмы UEFI потехи ради или для установки вредоноса в такую область, что не спасет ни переустановка оси, ни смена диска. А мало ли, на что способны такие вредоносы…

Кстати, некоторые антивирусы уже умеют сканировать UEFI на наличие буткитов.

К слову, не могу не упомянуть забавный случай, когда пресловутый rm -rf --no-preserve-root / вместе с содержимым дисков стер содержимое переменных в NVRAM, которое в Linux монтируется в /sys/firmware/efi/efivars, что привело к окирпичиванию ноута. Такая вот особенность реализации стандарта попалась экспериментатору и наглядно показала, что доступ на запись к переменным UEFI из ОС был сомнительной затеей. В общем, хорошенько подумай, если вдруг захочешь поиграть с огнем.

Так можно ли что-то сделать, если на твоем устройстве работает диск уже в новом формате, а с ним случилась беда? В теории какие-то проблемы можно решить с помощью UEFI Shell. Некоторые ошибки дисков, возникающие при загрузке, UEFI исправляет самостоятельно; другие же, как, например, во врезке, требуют «оперативного вмешательства».

Проверка целостности таблиц и исправление ошибок при загрузке

Стандартом неспроста предусмотрены две таблицы GPT — первичная и запасная. Кроме того что проверяется сигнатура GPT и то, указывает ли MyLBA на проверяемую таблицу, сверяются значения CRC32. Если при загрузке контрольная сумма одной из таблиц GPT не совпадает с действительностью, то она восстанавливается из второй таблицы. Если же случилось так, что не совпали контрольные суммы для обеих таблиц, то устройство определяется как не имеющее GPT-разметки. Тут могут пригодиться инструменты поинтереснее.

Восстановление GPT-разделов

Если пострадало больше одной служебной таблицы, потребуются, очевидно, другие решения, чем сверка контрольных сумм. Благо они существуют уже не только для носителей с разметкой MBR. При случайном (или нет) повреждении GPT-разделов есть возможность их восстановить.

В Linux, несмотря на то, как сообщество встретило UEFI, появились программы для работы с GPT, в том числе способные восстанавливать удаленные файлы и разделы. Первая, на которую стоит обратить внимание, — testdisk. Впрочем, у нее есть версии и под DOS, и под винду, и под «Мак». Она может оказаться полезной для восстановления не только служебных таблиц, но и удаленных данных. Скажем, у нас повреждена запасная таблица разделов, а первичная вообще куда-то подевалась (ну всякое ведь бывает, там if с of перепутал в dd), и в итоге в /dev/ отображается пострадавшее устройство, но не разделы на нем. Кому верить, как читать данные?

Для восстановления разделов в testdisk необходимо выбрать устройство и тип разделов. Программа пытается определить его самостоятельно, но в нашем случае, когда не совпадают CRC обеих таблиц, она считает, что это не GPT; впрочем, переубедить ее несложно. Далее выполняем анализ диска в поисках потраченных разделов и записываем информацию о найденном разделе на диск. По ходу дела testdisk не скупится на пояснения, что позволяет в простых случаях пользоваться утилитой, совершенно не заглядывая в документацию!

Обнаруженный testdisk’ом раздел. Начинается с блока 34, так как это минимум, выделяемый под структуры GPT
Обнаруженный testdisk’ом раздел. Начинается с блока 34, так как это минимум, выделяемый под структуры GPT

Вторая прога, которая в нашем случае может помочь, называется gdisk по аналогии с fdisk, который не понимает GPT. Для восстановления разделов она может использоваться в связке с parted: первая создает заново заголовки таблицы GPT, а вторая находит утраченные разделы.

Заботливый и информативный gparted, при помощи которого мы остались с пустой таблицей разделов
Заботливый и информативный gparted, при помощи которого мы остались с пустой таблицей разделов

В таком случае в gdisk (или аналогичной утилите) можно создать новые заголовки GPT взамен испорченных. Файлы и структуры файловых систем, к счастью, остаются при таких манипуляциях на месте, и необходимо лишь восстановить таблицу разделов. Для этого желательно помнить примерные границы разделов, так как их нужно сообщить программе parted в команде rescue. После перезагрузки пробуем примонтировать диск — и нам повезло, магия сработала! Вот бы почаще так.

Поиск и восстановление разделов в parted
Поиск и восстановление разделов в parted
Монтируем восстановленный раздел после перезагрузки. Все на месте!
Монтируем восстановленный раздел после перезагрузки. Все на месте!

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

Утилита DMDE с графическим интерфейсом
Утилита DMDE с графическим интерфейсом

Есть, к слову, полноценная версия этой программы и для macOS. DMDE объединяет в себе функции дискового редактора и менеджера разделов. Утилита умеет реконструировать структуру файлов и папок даже в случае сложных повреждений, но самое главное — она может работать с разделами GUID (GPT), причем варианты восстановления предлагаются в автоматическом режиме.

Если на машине под управлением Windows с UEFI/GPT полетел загрузчик, восстановить его можно стандартным инструментарием операционной системы. Достаточно загрузить машину с дистрибутивного образа Windows, открыть командную строку сочетанием клавиш Shift + F10, а затем с использованием нескольких команд создать заново утраченный раздел EFI и поместить туда загрузчик. Подробные инструкции можно отыскать в этих ваших интернетах.

Для счастливых владельцев компов производства Apple была разработана специальная программа Remo Recover, скачать которую можно с сайта разработчика. Там же представлены подробные инструкции по ее использованию, хотя они, в принципе, не особенно нужны: программа (как и многие другие приложения под Mac) обладает простым и интуитивно понятным графическим интерфейсом.

Утилита Remo Recover для macOS
Утилита Remo Recover для macOS

Подведем итоги

Основное назначение UEFI, как и БИОСа, заключается в загрузке ОС, но архитектура UEFI включает в себя намного больше модулей, чем необходимо для этого. А чем система сложнее, тем ее легче поломать, что доказывают найденные в разных реализациях ошибки и уязвимости. И казалось бы, если разницы нет, зачем платить больше?..

Однако почему-то в AMI, Insyde, Phoenix пишут именно UEFI BIOS, а используют этот стандарт такие производители, как Apple, Dell, HP, IBM, Lenovo; причем в Apple он в ходу еще c 2006 года. Microsoft тоже подключилась к этому проекту и внесла свой небезызвестный вклад в виде Secure Boot. В Linux сквозь боль и ненависть медленно, но верно разрабатывались программы для поддержки UEFI, в частности Secure Boot и GPT, позволяющие в настоящее время на довольно низком уровне со всем этим работать и даже решать некоторые проблемы. Так что, по крайней мере, жить можно.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий