← Linux: загрузка
12 мин · просто · Урок 3 из 7

Загрузчик и GRUB

Что делает загрузчик и где живёт GRUB.

Что делает загрузчик

Загрузчик (bootloader) — это программа, которая находит ядро (kernel) на диске, загружает его в память и передаёт ему управление. После включения питания firmware не умеет читать файловую систему и запускать сложное ядро. Оно передаёт эстафету загрузчику, а тот уже разбирается с диском.

Цепочка запуска всегда одна: firmware -> загрузчик -> ядро -> initramfs. Каждое звено делает свой кусок работы и уступает место следующему. initramfs — это временный корень, который ядро распаковывает в память (в rootfs на tmpfs при собранном CONFIG_TMPFS), чтобы подмонтировать настоящий корневой раздел.

Кроме самого ядра загрузчик передаёт ему параметры. Это строка kernel command line: где искать корень, в каком режиме монтировать, что показывать на экране.

# типичная строка параметров ядра
root=/dev/sda2 ro quiet
# root= — какой раздел монтировать как корневой
# ro     — примонтировать сначала только на чтение
# quiet  — не сыпать логами ядра на экран при загрузке

Посмотреть параметры, с которыми загрузилась текущая система, можно после старта:

$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.1.0 root=/dev/sda2 ro quiet

GRUB

GRUB (GRand Unified Bootloader) — это загрузчик, который стоит на большинстве Linux-систем. При старте он показывает меню: какое ядро или какую систему запускать. Меню и все настройки GRUB читает из конфига.

$ ls /boot/grub/
grub.cfg  fonts  i386-pc  locale
# grub.cfg — сгенерированный конфиг, который GRUB читает при старте

Файл grub.cfg не пишут руками. Его собирает утилита из шаблонов в /etc/grub.d/ и настроек в /etc/default/grub. После правки настроек конфиг пересобирают:

$ update-grub                 # Debian/Ubuntu
$ grub2-mkconfig -o /boot/grub2/grub.cfg   # Fedora/RHEL

GRUB подгружает себя с диска небольшими шагами. Первый крошечный кусок кода умеет ровно одно: прочитать с диска следующий, побольше. Тот уже понимает файловые системы, находит grub.cfg, рисует меню и в итоге загружает выбранное ядро. Единой трёхстадийной схемы здесь нет, деталей у разных установок хватает.

GRUB умеет chainloading: передать управление другому загрузчику вместо того, чтобы грузить ядро самому. Так запускают, например, Windows: GRUB не понимает его загрузку, поэтому просто отдаёт управление загрузчику Windows.

# фрагмент меню GRUB с chainloading на другой раздел
menuentry "Windows" {
    chainloader (hd0,1)+1
}

Где физически лежит первичный код

На старых системах с BIOS первый кусок загрузчика помещается в MBR (Master Boot Record), первый сектор диска размером 512 байт. Первые 446 байт там отведены под код первичного загрузчика, остальное занимает таблица разделов и сигнатура.

$ sudo dd if=/dev/sda bs=512 count=1 | wc -c
512
# весь MBR — ровно 512 байт, код в них не помещается целиком

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

На UEFI картина другая. Здесь загрузчик лежит файлом на отдельном разделе EFI и firmware запускает его напрямую. Больше того, ядро Linux можно собрать с EFI stub, и тогда firmware грузит само ядро как исполняемый файл, вообще без отдельного загрузчика.

Две частые ошибки

Первая: «GRUB — это часть ядра». Нет. GRUB отрабатывает и полностью уходит из памяти до того, как ядро начнёт работать. Это отдельная программа со своей задачей: найти и запустить ядро.

Вторая: «загрузчик — это один файл». Тоже нет. GRUB — набор компонентов: первичный код в загрузочной области, модули в /boot, конфиг grub.cfg. Они подгружаются по очереди, а не лежат единым бинарником.

После того как ядро получило управление и подняло initramfs, запускается первый пользовательский процесс, обычно systemd.

Что важно запомнить

Загрузчик находит ядро на диске, грузит его в память и передаёт управление с параметрами (kernel command line).

Цепочка: firmware -> загрузчик -> ядро -> initramfs.

GRUB читает grub.cfg, показывает меню, подгружает себя с диска шагами и умеет chainloading на другой загрузчик.

Параметры ядра вроде root=, ro, quiet видно в /proc/cmdline.

MBR — 512 байт, из них 446 под код первичного загрузчика. На UEFI ядро грузится напрямую через EFI stub без отдельного загрузчика.

GRUB — не часть ядра и не один файл, а набор компонентов.

В следующем уроке — initramfs: зачем ядру временный корень в памяти и как он монтирует настоящий.

Прошли материал до конца? Отметьте урок пройденным.