Каждый раз, когда пользователь нажимает кнопку питания своего компьютера, до того, как система полностью будет загружена, происходят несколько ключевых этапов:
Сначала запускается BIOS - Basic Input/Output System (Базовая система ввода/вывода). BIOS не является полноценной операционной системой: это прошивка материнской платы, которая выполняет начальную инициализацию оборудования и передает управление загрузчику. В начале запуска компьютера BIOS проводит процедуру POST (Power-On Self-Test) - проверяет работоспособность оборудования (процессора, ОЗУ и так далее)
BIOS узнает о загрузочном коде напрямую из таблицы MBR (Master Boot Record, Главная загрузочная запись), которая расположена в начале любого диска, с которого можно загрузится (или через PXE - Preboot eXecution Environment)
Master Boot Record занимает первый 512 байт (первый сектор на диске) и содержит:
0x55AAСейчас же вместо BIOS повсеместно используется UEFI - Unified Extensible Firmware Interface (Единый расширяемый интерфейс прошивки). UEFI - это более современная прошивка, которая поддерживает графический интерфейс, управление мышью и обычно работает с таблицей разделов GPT (GUID Partition Table)
Программный код BIOS и UEFI расположены непосредственно на микросхеме на материнской плате компьютера
Далее рассмотрим загрузку Linux в BIOS. BIOS загружает выбранный исполняемый код, который находится в MBR, в ОЗУ, и процессор исполняет его. Для загрузки Linux используют особой компонент - загрузчик. Сейчас самый используемый - это GNU GRUB (GRand Unified Bootloader) версии 2
Код из Master Boot Record содержит 1 фазу загрузчика GRUB boot.img - он занимает 440 байт, что недостаточно для полноценной загрузки
boot.img далее запускает фазу 1.5 загрузчика - core.img. Он находится между MBR и первым разделом диска, в нем расположен код базового набора драйверов для файловых систем (ext4, xfs и так далее), для работы с массивом RAID или LVM (Logical Volume Manager, менеджер логических томов). Как правило, размер core.img составляет от 30 до 40 Кб (как правило 62 сектора на диске, максимальный размер - 458 240 байт)
После этого core.img уже может читать файлы из раздела загрузчика (после загрузки он монтируется как /boot/grub и как правило, находится на другом разделе, чем /). core.img загружает код загрузчика из /boot/grub, который прочитывает файл grub.cfg, где находится выбор ОС (в случае Linux это выбор ядра или его версии) - так начинается фаза 2. GRUB запускает графическое меню, где можно выбрать ядро и его параметры:

Для компьютеров с UEFI все намного проще. UEFI является намного более умным, чем BIOS, и его память на материнской плате содержит драйвера для работы с дисками (в частности для файловых систем FAT16 и FAT32), устройствами USB и сетью
Также UEFI хранит загрузочные записи - они хранят идентификатор GUID раздела и путь до кода загрузчика в специальном разделе ESP (EFI System Partition)
Далее при запуске UEFI ищет на диске этот скрытый раздел ESP, который отформатирован в FAT16 или FAT32. На этом разделе хранятся загрузчики разных ОС и другие инструменты (например, для проверки памяти или для отладки ядра)
При загрузке Linux этот раздел монтируется в /boot/EFI. Структура этого каталога выглядит примерно так:
/boot/EFI
├── ARCH
│ └── grubx64.efi
├── BOOT
│ ├── BOOTIA32.EFI
│ ├── BOOTX64.EFI
│ ├── fbia32.efi
│ └── fbx64.efi
├── Microsoft
│ ├── Boot
│ │ ├── bootmgfw.efi
│ │ ├── bootmgr.efi
│ │ ├── boot.stl
│ │ ├── memtest.efi
│ │ ├── SecureBootRecovery.efi
│ │ └── ...
│ └── Recovery
│ └── ...
└── systemd
└── systemd-bootx64.efi
Главный загрузчик для Windows, Windows Boot Manager, находится в файле Microsoft/bootmgfw.efi. Для Linux (в данном случае дистрибутива Arch Linux) загрузчик расположен в ARCH/grubx64.efi. В BOOT лежит загрузчик по умолчанию: операционная система сначала создает свой загрузчик в BOOT, затем копирует его в отдельную директорию и создает запись в памяти UEFI
Сам файл grubx64.efi представляет собой код из core.img - набор базовый модулей, необходимый для чтения раздела в ext4, конфигурационного файла grub.cfg и загрузки дополнительных модулей
Помимо этого UEFI еще может загружаться через сеть. Для этого он, предварительно получив IP-адрес по протоколу DHCP, скачивает по протоколу TFTP файл bootx64.efi и запускает его
После выбора записи загрузчик GRUB помещает в память образ ядра Linux vmlinuz и образ начальной файловой системы initramfs, а затем передает управление ядру
Сам файл vmlinuz - это сжатый образ ядра. Исторически название расшифровывают как vm (virtual memory, виртуальная память) + linu (linux) + z (zipped - сжатый образ). В оперативной памяти ядро распаковывается, переходит в защищенный режим работы процессора, настраивает таблицы страниц, обработчики прерываний, планировщик и начинает обнаружение устройств
На этом этапе ядро еще не может сразу смонтировать настоящую корневую файловую систему /, потому что для этого часто нужны дополнительные модули и драйверы
Именно поэтому вместе с ядром загружается initramfs (от Initial RAM Filesystem) - небольшой архив, который распаковывается в оперативную память и превращается во временную корневую файловую систему
Внутри initramfs обычно находятся:
Раньше до версии ядра 2.6 вместо initramfs использовался initrd (Initial RAM Disk), который монтировался как блочное устройства
Обычно дальше идут такие процессы:
initramfs в память/init. /init загружает нужные модули ядра и подготавливает устройстваinitramfs, который находится в ОЗУ, в файловую систему раздела на дискеЕсли корневой раздел недоступен, система часто попадает в аварийную оболочку из initramfs, где администратор может вручную диагностировать проблему
Когда настоящее корневое дерево каталогов уже доступно, ядро запускает первый пользовательский процесс с идентификатором PID = 1. Исторически это была программа init, а в современных дистрибутивах чаще всего таким процессом становится systemd
Процесс PID = 1 - это особый процесс, так как:
Если ядро не может запустить процесс с PID = 1, загрузка прекращается с паникой ядра
Классическая система инициализации init, которая появилась в UNIX System III и получила развитие в UNIX System V (сейчас такой init называют SysV init), использовала набор sh-скриптов из каталогов вида /etc/rc*.d/. Они запускались последовательно в соответствии с выбранным уровнем выполнения (так называемым runlevel), который описаны в /etc/inittab.Формат строк в /etc/inittab такой:
<идентификатор>:<уровни исполнения>:<действие>:<командная строка запуска>
В System V уровни выполнения в init были такими:
0 - остановка системы1 - однопользовательский режим2 - многопользовательский режим без доступа в Интернет3 - многопользовательский режим4 - не используется или переопределяется пользователем5 - многопользовательский графический режим6 - перезагрузкаВ распространенных дистрибутивах, таких как Debian, уровни означали другое:
0 - остановка системы1 - режим восстановления2, 3, 4 - частичный режим, где не все службы запущены5 - полноценный режим6 - перезагрузкаУровень 1 обычно предназначен для загрузки ОС и ее восстановления
В файле /etc/inittab поле <действие> определяет режим запуска процесса, например: wait - запустить и ждать завершения, respawn - перезапускать после завершения, sysinit - выполнить на раннем этапе загрузки
В большинстве современных дистрибутивов вместо SysV init используется systemd. Он запускает службы параллельно, использует декларативные файлы вида /etc/systemd/system/myapp.type и умеет отслеживать зависимости между компонентами системы
Службы в systemd имеют тип:
.service - служба.target - логическая цель загрузки.mount - точка монтирования.socket - сокет для активации службыТип службы определяет показывает, какой объект системы он описывает. Так, /etc/systemd/system/myapp.service - это служба. Внутри текстовый файл содержит ее описание:
[Unit]
Description=My Application
After=network.target # запустить после запуска демона networkd
[Service]
Type=simple
User=myappuser # запустить от имени myappuser
ExecStart=/usr/bin/myapp # исполняемый файл
Restart=on-failure # перезапустить при падении
StandardOutput=journal # записывать логи в журнал systemd
При загрузке systemd читает конфигурацию, монтирует файловые системы, поднимает сеть, запускает системные службы и доводит систему до нужного целевого состояния, например до multi-user.target (многопользовательский режим) или graphical.target (режим с графической оболочкой)
Подытоживая, загрузку ОС Linux можно описать так:
vmlinuz и initramfsinitramfs помогает ядру найти и смонтировать настоящий корневой разделPID = 1 (init или systemd) запускает службы и переводит систему в рабочее состояние
Последовательность загрузок разных частей операционной системы расширяет функционал до тех пор, пока система может взаимодействовать с оборудованием, и решает проблему “курицы и яйца”