Операционные системы

Теория: От питания до загрузки ОС

После нажатия кнопки питания сразу не запускаются программы сначала включается электрическая часть. Кнопка лишь передаёт сигнал материнской плате Power_On. Контроллер питания даёт команду блоку питания ATX включить основные линии 3.3, 5 и 12 В. Блок питания проверяет стабильность напряжения и, если всё нормально, отправляет обратно сигнал PWR_OK. После этого процессор может начинать работу.

До этого момента процессор не задействован. его внутренние регистры не инициализированы, память не активна, и ни одна инструкция не выполняется. Когда приходит Power Good, кристалл процессора сбрасывает счётчик команд на фиксированный адрес — для x86 это 0xFFFFFFF0. Именно там прошивка BIOS или UEFI хранит первые байты кода. С этого адреса процессор начинает выполнять команды, загружая в себя остальную часть микропрограммы.

BIOS и UEFI здесь выполняют одинаковую фундаментальную роль — они создают из «кучи железа» упорядоченную систему. В ходе POST (Power-On Self Test) прошивка проверяет оперативную память, видеокарту, контроллеры, таймеры и устройства ввода. Если что-то не так, система сообщает об этом звуковыми сигналами. Например, один длинный и два коротких могут означать проблему с видеокартой, а непрерывный писк — с памятью. У более дорогих плат есть POST-код-индикаторы, где на двухзначном дисплее выводятся шестнадцатеричные коды диагностики — их можно сверить с таблицей в руководстве.

Когда тест завершён, прошивка создаёт таблицы конфигурации:

  • ACPI (Advanced Configuration and Power Interface) — управление питанием и устройствами,
  • SMBIOS (System Management BIOS) — описание компонентов системы,
  • списки PCI (Peripheral Component Interconnect) и USB (Universal Serial Bus)-устройств.

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

BIOS ищет загрузочное устройство в порядке, указанном в настройках Boot Order: сначала флешка, потом диск, потом сеть. Как только найден подходящий носитель, BIOS считывает первые 512 байт — Master Boot Record. В этом секторе находится маленькая программа, которая знает, где на диске лежит загрузчик (GRUB, NTLDR, BOOTMGR). BIOS просто копирует MBR в память по адресу 0x7C00 и передаёт ему управление.

UEFI действует иначе. Он не ограничен 16-битным режимом и старой адресацией, поэтому сразу работает с файловой системой. UEFI знает, что искать нужно не «первые байты», а файл с расширением .efi в каталоге EFI System Partition. Этот раздел всегда FAT32 и обычно занимает 100–300 МБ. Пример структуры:

/boot/efi/EFI/ubuntu/grubx64.efi
/boot/efi/EFI/Microsoft/Boot/bootmgfw.efi

UEFI также поддерживает сетевую загрузку (PXE), Secure Boot, интерфейс управления (Setup Utility) и возможность запускать диагностические программы без ОС.

Механизм Secure Boot вшит в UEFI. Он проверяет цифровую подпись исполняемого файла .efi и разрешает запуск только доверенного кода. Ключи хранятся в микропамяти прошивки. Если файл не подписан, система просто откажется его запускать. Поэтому при сборке кастомного ядра Secure Boot часто приходится отключать вручную.

Все сведения о зарегистрированных загрузчиках UEFI хранит в энергонезависимой памяти — NVRAM. Каждый загрузчик имеет номер (Boot0000, Boot0001 и т.д.), а порядок их вызова задаётся переменной BootOrder. Это можно увидеть с помощью команды:

sudo efibootmgr -v

Вывод покажет метки, пути и приоритет. Если система перестала видеть Linux, можно вручную добавить загрузчик:

sudo efibootmgr --create --disk /dev/nvme0n1 --part 1 \
    --label "GRUB" --loader "\EFI\ubuntu\grubx64.efi"

Эти записи остаются в прошивке даже после переустановки ОС.

В старых BIOS такой гибкости нет — всё определяется наличием MBR на диске. Если сектор повреждён или удалён, BIOS просто покажет сообщение «No bootable device».

Иногда UEFI запускает собственные приложения перед ОС: обновления прошивки, утилиты настройки RAID, встроенные тесты памяти. Всё это тоже .efi-файлы, просто с другой целью.

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

Secure Boot и цифровые подписи

Современные компьютеры защищают процесс загрузки не только на уровне операционной системы, но и до неё. Один из ключевых механизмов — Secure Boot. Он встроен в UEFI и отвечает за то, чтобы в систему не попал посторонний код ещё до старта ядра. Когда UEFI находит загрузчик — например, grubx64.efi или bootmgfw.efi — она не запускает его сразу. Сначала проверяет цифровую подпись файла по списку доверенных ключей, хранящихся в прошивке. Если подпись совпадает с одной из известных (например, Microsoft или Canonical для Ubuntu), загрузчик считается подлинным и получает управление. Если нет — UEFI блокирует запуск и показывает сообщение вроде «Invalid signature detected» или просто пропускает устройство в списке загрузки.

Secure Boot защищает от подмены кода на этапе, когда операционная система ещё не работает и антивирусы бессильны. Без этой проверки вредоносная программа могла бы встроиться в загрузчик, подменить ядро и получить полный контроль над системой до появления экрана входа.

Проблема появляется, когда пользователь собирает собственное ядро или экспериментирует с загрузчиком. Такое ядро не имеет цифровой подписи, доверенной прошивке. UEFI просто откажется его запускать, считая неизвестным кодом. Поэтому при установке систем вроде Arch Linux или при сборке ядра вручную Secure Boot часто нужно отключить.

Сделать это можно через меню прошивки. После включения компьютера нужно войти в настройки (обычно клавиши Del, F2 или Esc), найти раздел Boot или Security и пункт Secure Boot. Если система требует, сначала следует перевести режим в Custom или Setup Mode, чтобы разрешить изменение ключей. После этого статус Secure Boot можно поменять на Disabled.

Некоторые прошивки позволяют не отключать защиту полностью, а добавить свой ключ. Это более безопасный способ, если требуется запускать собственные сборки ядра. Для этого создаётся пара ключей — частный (для подписи) и публичный (для прошивки). Публичный добавляется в список доверенных через пункт Key Management, а ядро подписывается командой sbsign --key MOK.key --cert MOK.crt vmlinuz-....

Проверить, включён ли Secure Boot, можно прямо из Linux:

cat /sys/firmware/efi/vars/SecureBoot-*/data

Если значение равно 1, защита активна; если 0 — отключена.

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

Загрузчик

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

Исторически GRUB строился из двух стадий. Первая стадия (stage1) — это крошечный фрагмент кода, который прошивка может запустить напрямую. В BIOS-системах он размещается в MBR и ближайших секторах диска. Его задача минимальна — найти и загрузить вторую часть.

Вторая стадия (stage2) — полноценная программа GRUB с драйверами файловых систем, поддержкой меню, командной строки и модулей. В современных версиях GRUB 2 термины stage1 и stage2 почти не используют, но архитектура осталась той же. После MBR записывается специальный промежуточный файл core.img — он знает, где находится остальная часть GRUB (каталоги /boot/grub и модули) и загружает их.

В UEFI-режиме схема изменилась: прошивка больше не ищет загрузочный сектор, а сразу запускает исполняемый файл grubx64.efi (или grubaa64.efi для ARM) из EFI System Partition — например, из каталога *\EFI\ubuntu* или *\EFI\fedora*. Этот файл выполняет ту же роль, что и core.img в BIOS: инициализирует окружение, подключает нужные модули и читает конфигурацию из /boot/grub/grub.cfg.

Разница режимов важна именно в точке входа. BIOS читает первые 512 байт и передаёт управление загрузочному коду, поэтому GRUB ставит мини-загрузчик в MBR и core.img в свободные сектора; UEFI вообще не смотрит MBR и запускает обычный .efi-файл с ESP-раздела, например \EFI\ubuntu\grubx64.efi. Дальше логика одинаковая: ядро и initramfs читаются с файловой системы /boot, конфигурация тянется из grub.cfg, модули подключаются по мере надобности.

Конфигурацию GRUB формирует файл /boot/grub/grub.cfg. В некоторых дистрибутивах путь может быть /boot/grub2/grub.cfg — это не другая программа, а иная укладка каталогов. Сам файл не редактируют вручную: правила описывают в /etc/default/grub и каталогах /etc/grub.d/, а затем генерируют конфигурацию. На Debian/Ubuntu для этого служит update-grub, который сам вызовет grub-mkconfig; на других системах запускают grub-mkconfig -o /boot/grub/grub.cfg. Такой подход гарантирует согласованность меню с текущими ядрами и соседними системами.

Строка меню описывает, какое ядро загружать и какие параметры ему передать. Директива linux указывает путь к к исполняемому файлу ядра, обычно /boot/vmlinuz-X.Y.Z, и набор параметров командной строки. Параметр root= сообщает ядру, где искать корневую файловую систему; надёжнее указывать UUID, тогда ядро не перепутает диск при смене порядка устройств. Параметр ro просит монтировать корень в режиме «только чтение» на время ранней инициализации; это снижает риск порчи данных, пока пользователи пространства ещё не поднялись. Параметр quiet уменьшает болтливость ядра в консоли, скрывая большую часть сообщений; параметр splash отдаёт управление программе заставки (например, Plymouth), которая рисует экран загрузки вместо текстового лога. Параметр systemd.unit= позволяет выбрать целевое состояние systemd прямо на старте: значение multi-user.target приведёт систему в консольный многопользовательский режим, graphical.target запустит графическую оболочку, rescue.target включит однопользовательский режим, а emergency.target даст минимальную аварийную среду без автомонтирования. Эти параметры не «магия GRUB», это аргументы командной строки ядра, которые GRUB просто передаёт.

Рядом со строкой linux всегда идёт строка initrd, которая указывает путь к образу initramfs, например /boot/initrd.img-X.Y.Z. Этот образ — временная файловая система в памяти, где лежат скрипты и модули для раннего старта: драйверы дисков, разблокировка LUKS, активация LVM/RAID. Если указать ядро без корректного initramfs, система с высокой вероятностью упадёт с ошибкой «kernel panic — unable to mount root fs». В UEFI-режиме некоторые сборки используют директивы linuxefi и initrdefi, смысл не меняется: ядро и initramfs получают свои пути и параметры, а затем исполняются.

Во время загрузки параметры ядра часто нужно изменить «на лету» - без редактирования конфигурационных файлов. Меню GRUB позволяет это сделать прямо перед запуском системы. Чтобы временно изменить параметры, выберите нужный пункт меню и нажмите e. Откроется окно с содержимым записи - несколько строк, среди которых ключевые начинаются с linux (путь к ядру и его параметры) и initrd (путь к initramfs).

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

  • systemd.unit=rescue.target — загрузка в режим восстановления.
  • systemd.unit=emergency.target — загрузка в аварийную консоль.
  • Удалите quiet, чтобы увидеть полный лог и сообщения ядра.
  • Временно замените root=UUID=… на корректный UUID, если система не находит корневой раздел.

После внесения изменений нажмите Ctrl + X или F10, чтобы запустить систему с этими параметрами. Все изменения действуют только для текущей загрузки и не сохраняются на диск. При следующем запуске GRUB вернётся к исходной конфигурации — это удобно для диагностики, экспериментов и восстановления после сбоев.

GRUB подгружает модули по мере необходимости. Модуль normal.mod включает «нормальный» режим с меню, модуль ls.mod даёт команду ls по дискам, модуль ext2.mod умеет читать ext-подобные файловые системы, btrfs.mod — Btrfs, xfs.mod — XFS. В rescue-режиме набор команд минимален, поэтому часто первым делом подгружают нужный модуль через insmod, чтобы получить привычные возможности. Такой модульный дизайн упрощает ядро загрузчика и позволяет поддерживать много форматов без раздувания базового образа.

Адресация дисков в консоли GRUB отличается от Linux. Первый диск — это hd0, второй — hd1. Размеченный GPT-диск использует нотацию (hd0,gpt1) для первого раздела, MBR — (hd0,msdos1). Команда ls без аргументов покажет список известных устройств и разделов; команда ls (hd0,gpt1)/ напечатает содержимое корня этого раздела; так легко найти /boot и убедиться, что ядро и initrd на месте. Для надёжного выбора раздела полезна команда search. Она умеет искать по UUID и меткам: search --fs-uuid --set=root <UUID> найдёт раздел с указанным UUID и установит переменную root, чтобы дальнейшие пути читались от него.

Аварийная консоль «grub rescue>» появляется, когда GRUB не может найти свои модули и конфигурацию. В такой ситуации план действий всегда один: определить, где лежит /boot/grub, указать это место и включить «нормальный» режим. Пользователь вводит ls, чтобы увидеть доступные диски, подбирает нужный раздел и проверяет наличие каталога /boot/grub. Затем задаёт переменные окружения: set prefix=(hd0,gpt2)/boot/grub сообщает, где лежат модули и конфигурация, set root=(hd0,gpt2) задаёт корневой раздел для чтения файлов. После этого insmod normal подгружает модуль «normal», а команда normal возвращает привычное меню. Если модули нашлись, но конфигурация сломана, помогает команда configfile (hd0,gpt2)/boot/grub/grub.cfg — она загрузит конфиг напрямую и построит меню на его основе.

В некоторых случаях нет смысла возвращаться в меню, проще загрузить ядро вручную. После выбора правильного раздела вводят linux /boot/vmlinuz-X.Y.Z root=UUID=… ro и рядом initrd /boot/initrd.img-X.Y.Z, а затем boot. Эти команды повторяют то, что делает меню, и работают даже без конфигурации. В UEFI-сборках вместо linux может потребоваться linuxefi, а вместо initrdinitrdefi; если команда не распознаётся, GRUB сообщит об этом сразу, и тогда стоит подгрузить модуль linuxefi через insmod.

Чтобы изменения параметров сохранялись между перезагрузками, GRUB использует файл окружения grubenv. Переменная saved_entry позволяет запомнить выбранный пункт меню и автоматически загружать его в следующий раз. Команда grub-set-default записывает желаемый пункт в grubenv, а grub-reboot задаёт его только на один следующий старт. Такая механика удобна для безголовых серверов, где нужно один раз загрузить альтернативное ядро, а потом вернуться к стабильной записи.

Управляющие файлы находятся в разных местах и выполняют разные роли. /etc/default/grub хранит человеческие настройки: таймаут меню, фоновую картинку, включение графического режима, набор обнаруживаемых ОС. Скрипты в /etc/grub.d/ генерируют блоки для grub.cfg: один добавляет локальные ядра, другой — обнаруженные ОС через os-prober, третий — специальные записи восстановления. После изменений всегда запускают генерацию, иначе grub.cfg останется прежним и загрузчик не увидит правок.

Установка и переустановка GRUB зависят от режима прошивки. В BIOS-режиме установка идёт в MBR целевого диска: grub-install /dev/sda запишет первый этап и core.img. В UEFI-режиме команда должна знать, где находится ESP: grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB создаст каталог \EFI\GRUB на ESP и положит туда grubx64.efi. Параметр --target указывает платформу и архитектуру; x86_64-efi — для 64-битного UEFI, i386-pc — для классического BIOS. Параметр --efi-directory сообщает путь монтирования ESP внутри текущей системы; без него установщик не сможет записать .efi файл и зарегистрировать загрузчик. Параметр --bootloader-id задаёт имя каталога на ESP и подпись записи в NVRAM; он влияет на то, как загрузчик будет называться в меню прошивки.

Диагностика всегда начинается с понимания, кто «не передал эстафету». Если меню не появляется и прошивка пишет «No bootable device», значит, UEFI не нашёл .efi на ESP или BIOS не нашёл валидного MBR. Если виден prompt grub>, конфигурация не нашлась, но модули на месте — можно загрузиться вручную. Если prompt grub rescue>, модулей нет — нужно указать prefix и root и подгрузить normal.mod. Если GRUB стартует, но ядро падает с «unable to mount root fs», значит, неверный root= или отсутствует нужный initramfs; стоит проверить UUID, пересобрать initramfs и убедиться, что в нём есть драйверы контроллера диска.

Работа флагов и параметров должна быть прозрачной для студента. Параметр root=UUID=… сообщает ядру точный раздел корня, чтобы исключить путаницу по именам устройств; параметр ro гарантирует, что корень монтируется в безрисковом режиме до завершения раннего старта; параметр quiet гасит лишний лог, но при отладке его лучше убрать, чтобы видеть сообщения ядра; параметр splash передаёт управление заставке и скрывает шум — он полезен на десктопах, но мешает при диагностике; параметр systemd.unit=<цель> заставляет PID 1 стартовать в указанной цели и тем самым управляет глубиной загрузки без правки конфигов. Эти параметры не исправляют аппаратные ошибки, но позволяют точечно менять поведение загрузки.

Связка «ядро + initramfs» всегда должна идти парой. В меню их версии обязаны совпадать; если ядро обновили, но initramfs не пересобрали, образ окажется несовместимым. На Debian/Ubuntu команда update-initramfs -u -k <версия> пересоберёт образ для нужного ядра; -k all обновит все установленные. Проверить, что именно запускается, можно уже из работающей системы: cat /proc/cmdline отдаст строку параметров, которые передал GRUB, а uname -r покажет версию ядра, на которую реально загрузились.

При многообразии режимов и конфигураций логика GRUB остаётся линейной. Загрузчик стартует в минимальном окружении, находит свои модули, читает grub.cfg, показывает меню, загружает ядро, указывает initramfs, передаёт командную строку и отдаёт управление. Если какой-то из этих шагов не состоялся, это не загадка, а конкретное место в цепочке, которое нужно восстановить — указать правильный раздел, подгрузить нужный модуль, поправить параметры или переустановить загрузчик для выбранного режима прошивки. Именно эта предсказуемость делает GRUB удобным инструментом как для ежедневной работы, так и для учебной практики.

Что происходит после GRUB

Когда загрузчик передаёт управление ядру Linux, операционная система еще не вступила в работу. В памяти загружено только само ядро и образ initramfs — временная файловая система, которая играет роль «моста» между загрузкой и полноценной работой. Без неё ядро было бы слепым: оно не знало бы, где искать корневой раздел, как расшифровать диск, как собрать RAID или активировать LVM.

Initramfs: временная система в памяти

Initramfs расшифровывается как initial RAM filesystem. Это архив, который загрузчик (например, GRUB) кладёт в оперативную память вместе с ядром. Когда процессор начинает выполнять код ядра, то первым делом ядро поднимает начальный rootfs и распаковывает в него архив initramfs (cpio), после чего этот временный rootfs выступает как / до переключения на реальный корень ФС этот архив в оперативной памяти, создавая крошечную файловую систему /.

Внутри initramfs находятся минимальные утилиты, скрипты и драйверы, которые нужны, чтобы подготовить настоящий корень (/) к монтированию. Обычно там лежит:

  • busybox — универсальный бинарник, который объединяет десятки стандартных команд (ls, cp, sh, mount, modprobe и т.д.);
  • скрипт /init — главная точка входа, именно его запускает ядро как первый процесс;
  • драйверы дисков, сетевых адаптеров, контроллеров NVMe, RAID-массивов, LVM;
  • конфиги вроде /etc/crypttab, /etc/mdadm.conf, /etc/lvm/lvm.conf;
  • вспомогательные утилиты (fsck, udevadm, dracut, lvm, mdadm).

Когда ядро запускает /init, этот скрипт выполняет несколько шагов:

  1. Загружает нужные модули (modprobe nvme, modprobe ext4).
  2. Если диск зашифрован, вызывает утилиту расшифровки (cryptsetup luksOpen).
  3. Активирует группы томов LVM (vgchange -ay).
  4. Собирает RAID-массивы (mdadm --assemble --scan).
  5. Проверяет корень (fsck) и монтирует его в /new_root.

Переопределяет корень файловой системы: exec switch_root /new_root /sbin/init

  1. Эта команда передаёт управление от временной файловой системы к настоящему корню. После этого initramfs выгружается из памяти, и система продолжает загрузку уже с реального диска.

Если на этом этапе что-то пойдёт не так — например, не найден корень файловой системы, не подгружен нужный модуль, ошибка в UUID или LUKS-пароле — ядро открывает консоль (initramfs). Это интерактивная оболочка busybox, в которой можно вручную проверить устройства и исправить проблему:

ls /dev             # посмотреть доступные устройства
blkid               # проверить UUID и типы разделов
modprobe nvme_core  # загрузить драйвер NVMe
mount /dev/nvme0n1p3 /new_root
switch_root /new_root /sbin/init

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

Чтобы увидеть, что входит в initramfs, можно распаковать его прямо в Linux:

mkdir /tmp/initramfs
cd /tmp/initramfs
zcat /boot/initrd.img-$(uname -r) | cpio -idmv

Команда cpio распакует архив, и вы увидите структуру: bin/, sbin/, etc/, lib/, init.

Когда ядро или оборудование обновляется, initramfs нужно пересобрать, чтобы туда попали свежие модули:

  • Debian/Ubuntu: sudo update-initramfs -u -k all
  • RHEL/CentOS: sudo dracut -f
  • Arch: sudo mkinitcpio -P

Ядро Linux: запуск и инициализация

Ядро получает управление от загрузчика и начинает работать с компонентами вашего ПК напрямую. Первое, что оно делает, — переводит процессор из реального режима (16-бит, в котором работает BIOS) в защищённый режим (32- или 64-бит), чтобы использовать всю оперативную память и многозадачность.

Дальше ядро настраивает управление памятью через MMU (Memory Management Unit)блок управления памятью внутри процессора. MMU создаёт таблицы страниц — специальные структуры, которые сопоставляют виртуальные адреса программ с реальными физическими адресами в оперативной памяти. Благодаря этому каждая программа получает собственное виртуальное пространство и не может случайно повредить чужие данные. Это основа изоляции процессов в Linux.

Когда память настроена, ядро включает подсистему прерываний — механизм, который позволяет устройствам «обращаться» к процессору при событиях (например, нажатие клавиши или получение пакета из сети). Каждому типу сигнала соответствует номер — IRQ (Interrupt Request), запрос прерывания. Например, клавиатура обычно использует IRQ1, контроллер системных таймеров — IRQ0, сетевой адаптер — свой IRQ.

Для обработки этих сигналов ядро включает драйверы таймеров и устройств прерываний, чтобы реагировать на события вовремя: обновлять системное время, обслуживать диски, клавиатуру, мышь и сетевые пакеты. Именно на этом этапе Linux начинает реагировать на внешние события и становится интерактивным — процессор уже не просто выполняет код подряд, а умеет реагировать на происходящее в реальном времени.

Когда базовые структуры готовы, ядро начинает инициализировать драйверы:

  • контроллеры памяти и PCIe;
  • устройства хранения (SATA, NVMe, USB);
  • сетевые адаптеры;
  • устройства ввода (клавиатура, мышь). Чтобы получить доступ к настоящей файловой системе, ядру нужны драйверы устройств хранения — дисков, контроллеров, RAID, LVM и т. д. Если эти драйверы не встроены прямо в ядро, они подгружаются из образа initramfs (initial RAM filesystem). Initramfs — это временная файловая система, распакованная в оперативной памяти. В ней лежит минимальный набор инструментов и скрипт /init (или /init/dracut), который выполняет работу от имени пользовательского пространства (user space).

На этом этапе именно /init внутри initramfs монтирует корневой раздел (/), указанный параметром root= в строке GRUB. Когда корень готов, выполняется команда switch_root (или старый аналог pivot_root) — она «передаёт» систему с временного окружения initramfs на реальную файловую систему. Только если initramfs отсутствует (например, на встраиваемых системах), ядро монтирует корень самостоятельно — напрямую, без промежуточных скриптов.

После этого выполняется ключевой переход: ядро завершает свою инициализацию и запускает первый процесс в системе — PID 1:

execve("/sbin/init")

Если в параметрах ядра указано init=/bin/bash, будет запущен именно этот исполняемый файл — это удобно для аварийного восстановления. Но по умолчанию ядро вызывает /sbin/init, которым в современных дистрибутивах является systemd.

С этого момента управление полностью передаётся из пространства ядра (kernel space) в пространство пользователя (user space). Дальше начинается работа менеджера инициализации — systemd — который построит из ядра полноценную операционную систему: запустит службы, смонтирует оставшиеся разделы, поднимет сеть и подготовит систему к входу пользователя.

Systemd и цели (targets)

Systemd — это первый процесс в пользовательском пространстве (PID 1). Он получает полностью инициализированное ядро и теперь должен запустить остальную систему. Systemd читает юниты (файлы с расширениями .service, .mount, .target) из /etc/systemd/system/ и /usr/lib/systemd/system/. Каждый юнит описывает службу, точку монтирования или группу зависимостей.

Systemd проходит через последовательные цели (targets), каждая из которых означает определённый уровень готовности:

  • basic.target — минимальный набор системных служб: файловые системы, логи, таймеры.
  • multi-user.target — многопользовательский режим: включены демоны, сеть, SSH, cron.
  • graphical.target — поверх предыдущего добавляется графическая среда и дисплейный менеджер. Посмотреть, какая цель активна:
systemctl get-default

Если что-то пошло не так, можно перейти в режим восстановления:

  • rescue.target — аналог старого single-user mode, минимальный набор служб и root-консоль.
  • emergency.target — вообще без служб, только оболочка root и смонтированный корень (часто только для чтения). Переключение на лету:
sudo systemctl isolate rescue.target
sudo systemctl isolate graphical.target

При старте systemd запускает службы параллельно, что делает загрузку быстрой. Проверить, что именно запущено:

systemctl list-units --type=service

А чтобы посмотреть порядок целей —

systemctl list-units --type=target

Когда systemd достигает нужной цели, он передаёт управление программам входа: getty для консоли или дисплейному менеджеру (GDM, SDDM, LightDM) для графики.

Итог

Загрузчик кладёт ядро и initramfs в память → ядро инициализирует процессор, память и драйверы → initramfs подготавливает настоящий корень → выполняется switch_root → запускается systemd (PID 1) → systemd приводит систему к цели (multi-user или graphical) → система готова к работе.

Если на каком-то этапе цепочка обрывается, это и есть точка сбоя загрузки: повреждённый initramfs, неверный root, ошибка в драйвере или зависший юнит systemd.

Пользовательская сессия

Пользовательская сессия начинается в тот момент, когда система уже дошла до целевого состояния systemd и готова принимать пользовательские запросы. На сервере это обычно multi-user.target, где видны текстовые консоли; на рабочей станции чаще graphical.target, где появляется окно графического входа. Дальше работают два параллельных мира входа: консольный через getty и login и графический через дисплейный менеджер вроде GDM, SDDM или LightDM.

Консольный вход обеспечивает служба getty, которую systemd запускает как шаблонные юниты вроде getty@tty1.service. Каждый такой юнит привязывается к конкретной виртуальной консоли, поэтому переключение по Ctrl+Alt+F1…F6 переносит пользователя между разными tty.

Состояние можно проверить командой:

systemctl status getty@tty1.service

Если нужно увидеть только логи текущего запуска и только для этой службы, подойдёт:

journalctl -b -u getty@tty1.service

где -b оставляет записи текущей загрузки, а -u — только выбранного юнита. Задача getty — вывести приглашение login:, принять имя пользователя и запустить программу проверки пароля login.

Systemd использует разные шаблоны: getty@tty1.service — для виртуальных консолей, а serial-getty@ttyS0.service — для последовательных портов.

Проверка учётных данных происходит с помощью через PAM, поэтому поведение входа управляется набором модулей. Файл /etc/pam.d/login определяет, какие правила применяются. Модуль pam_unix сверяет пароль с /etc/shadow, pam_env подставляет переменные окружения, pam_limits задаёт лимиты ресурсов, а pam_nologin при наличии файла /etc/nologin запретит вход всем, кроме root, и покажет его содержимое как причину. Если аутентификация прошла, login запускает оболочку, указанную в /etc/passwd, например /bin/bash или /bin/zsh. На этом шаге формируется окружение пользователя: читаются .profile, .bash_profile и .bashrc для bash; сюда попадает PATH, алиасы и инициализация инструментов.

Иногда для киоска требуется входить без пароля сразу в консоль. Киосковый режим - это способ работы компьютера, при котором доступно только одно приложение или ограниченный интерфейс. Пользователь не может открыть рабочий стол, запускать другие программы или менять настройки. Такой режим используют в терминалах оплаты, билетных автоматах, инфопанелях и тестовых стендах.

В Linux авто-вход на консоль настраивается через agetty. Команда

agetty --autologin student --login-program /bin/login --noclear tty1 115200 linux

Выполнит автоматический вход пользователем student на tty1.

  • --autologin — имя пользователя, которое будет залогинено автоматически,
  • --login-program — конкретный бинарник программы входа,
  • --noclear — не очищать экран до показа приглашения, что полезно для отладки.

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

Графический вход берёт на себя дисплейный менеджер. На GNOME это GDM, на KDE — SDDM, на лёгких окружениях — LightDM. Эти программы стартуют как обычные сервисы systemd, например gdm.service, и открывают графическое окно аутентификации. Внутри они тоже используют PAM, но дополнительные модули могут подключать сетевую авторизацию или смарт-карты. Проверить состояние и логи можно командами systemctl status gdm и journalctl -b -u gdm, где флаги те же: -b оставит события текущего сеанса, а -u сфокусирует вывод на конкретной службе.

После успешного ввода пароля дисплейный менеджер создаёт графическую сессию. В современных системах это чаще Wayland, реже Xorg. Узнать тип сессии можно командой echo $XDG_SESSION_TYPE уже внутри рабочей среды; значения wayland и x11 подскажут, какой стек используется. Для Wayland GNOME запускает композитор Mutter внутри gnome-shell, KDE запускает KWin. Для Xorg дисплейный менеджер стартует сервер X и передаёт управление оболочке рабочего стола. В обоих случаях формируется окружение пользователя: переменные XDG, локаль, темы, службы автозапуска. Список автозапускаемых приложений лежит в ~/.config/autostart, а общесистемные дефолты — в /etc/xdg/autostart.

Systemd управляет не только системными службами, но и пользовательскими. Когда пользователь входит в систему, systemd создаёт юнит user@UID.service, внутри которого запускается отдельный экземпляр systemd --user. Это своего рода «PID 1 для пользователя»: он управляет пользовательскими юнитами, таймерами, фоновыми задачами, синхронизацией и портальными сервисами.

Список таких юнитов можно посмотреть командой:

systemctl --user list-units

Флаг --user направляет команду в пользовательский менеджер, поэтому root-права не нужны.

Чтобы пользовательские сервисы продолжали работать даже без активной сессии, включают режим linger:

loginctl enable-linger имя

Он позволяет systemd --user оставаться запущенным в фоне после выхода из графики или закрытия SSH-сессии. Это полезно для таймеров, ssh-агентов и фоновых демонов, которым не нужна активная консоль.

Идентичность и состояние пользовательских сеансов можно посмотреть через loginctl.
Команда

loginctl list-sessions

покажет все активные сеансы и их идентификаторы.

Чтобы вывести только нужные свойства конкретного сеанса, используют:

loginctl show-session <id> -p Type -p Remote -p Display -p State

Флаг -p ограничивает вывод указанными полями — это удобно для скриптов и автоматизации.

Если графический сеанс завис, но перезагружать систему не хочется, его можно выгрузить командой:

loginctl terminate-session <id>

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

Утилиты who и w читают базы utmp и wtmp и показывают, кто вошёл и откуда. Команда w полезна тем, что показывает ещё и процессы, запущенные в сессиях, а также источник подключения, поэтому с её помощью быстро видно, висит ли где-то старый ssh или открыт ли терминал на tty2. SSH-сессия технически не относится к дисплейному менеджеру, но подчиняется тем же правилам PAM и видна loginctl, поэтому её тоже можно завершить через loginctl terminate-session.

Путь запуска оболочки в графике регулируется десктоп-файлами и сценариями окружения. GNOME стартует через gnome-session, KDE — через startplasma-wayland или startplasma-x11, XFCE — через startxfce4. Переменная XDG_CURRENT_DESKTOP даёт текущее окружение, а echo $DISPLAY и echo $WAYLAND_DISPLAY подсказывают, к какому дисплею подключён клиент. Когда что-то не поднимается, полезно отключить «тихий» режим заставок и посмотреть журнал. Команда journalctl -b -u gdm -u sddm -u lightdm вытащит только записи дисплейных менеджеров; здесь -u можно повторять несколько раз, чтобы собрать нужные службы в одном выводе.

Взаимодействие консолей и графики остаётся важным при диагностике. Переключение на чистую консоль комбинацией Ctrl+Alt+F3 даёт root-доступ без графики, а возврат в графическую сессию обычно Ctrl+Alt+F1 или Ctrl+Alt+F2, в зависимости от дистрибутива. Программа chvt 1 переключает виртуальные консоли программно, что помогает в скриптах восстановления. Если графика не стартует, временный переход в текстовый целевой уровень выполняется командой sudo systemctl isolate multi-user.target, после чего можно проверить драйверы и конфиг, а затем вернуть графику командой sudo systemctl isolate graphical.target.

Завершение пользовательской сессии всегда контролируется systemd. Когда пользователь выходит из оболочки или закрывает графический сеанс, systemd --user прекращает связанные юниты, закрывает файловые дескрипторы и освобождает cgroup сессии. Это видно в loginctl session-status <id> сразу после выхода: запись поменяет состояние на закрытое. Если процессы «залипают» и держат монтирования, systemd завершит их сигналом SIGTERM, подождёт, а затем отправит SIGKILL, чтобы гарантировать чистый выход и корректное размонтирование пользовательских временных каталогов.

Связка getty-login-shell и DM-сессия решает одну задачу разными путями: создать доверенную среду, привязать процессы к пользователю и отдать управление оболочке — текстовой или графической. Консоль даёт прямой доступ и простую диагностику, графический вход добавляет удобство и интеграцию с окружением рабочего стола. В обоих случаях systemd остаётся диспетчером сессии и следит, чтобы процессы не выходили за рамки своих cgroup и корректно завершались вместе с пользователем.

Перезагрузка

Перезагрузка в Linux устроена почти так же, как выключение, только в конце ядро не отдаёт сигнал питания ACPI «Power Off», а вызывает аппаратный сброс. Снаружи кажется, что система просто «перезапускается», но на самом деле проходит та же цепочка действий — только вместо остановки идёт повторный запуск цикла загрузки.

Когда пользователь вводит sudo reboot или sudo systemctl reboot, команда передаёт systemd сигнал на переход к цели reboot.target. Это цель верхнего уровня, которая описывает последовательность всех шагов до момента перезапуска. Systemd начинает обратный порядок инициализации — закрывает пользовательские сессии, останавливает сервисы и демоны, размонтирует файловые системы, очищает кэш и передаёт управление ядру.

Первым шагом systemd завершает все активные процессы, отправляя им SIGTERM. Это мягкое уведомление, позволяющее программам корректно закрыться. Почтовые серверы записывают очереди, базы данных сохраняют транзакции, SSH-демон завершает соединения. Если за установленное время (обычно 90 секунд) процессы не отвечают, systemd посылает SIGKILL — жёсткий сигнал, который нельзя перехватить. Он уничтожает процесс без возможности сохранения состояния.

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

Когда синхронизация завершена, systemd размонтирует файловые системы. Процесс идёт в обратном порядке их монтирования. Сначала отключаются дополнительные разделы (/home, /var, /boot), затем временные (/run, /tmp), и в конце корень (/). Если какие-то процессы всё ещё удерживают файлы открытыми, systemd завершает их и повторяет попытку размонтирования.

На последнем этапе в работу вступает systemd-shutdown. Этот компонент выполняет команду ядра на перезапуск через системный вызов reboot(LINUX_REBOOT_CMD_RESTART). Ядро начинает стандартную процедуру сброса:

  • выключает контроллеры DMA, таймеры и сетевые интерфейсы;
  • очищает таблицы страниц и завершает управление памятью;
  • отправляет устройствам шины PCI команды на сброс;
  • и, наконец, передаёт команду reset через ACPI или архитектурный контроллер (например, через регистр порта 0x64 на x86).

В этот момент питание не пропадает — материнская плата просто получает сигнал перезапуска. BIOS или UEFI снова начинают POST-проверку, загружают загрузчик (GRUB) и всё повторяется с самого начала: ядро, initramfs, systemd, цели, пользовательская сессия.

Если нужно инициировать перезагрузку с задержкой, можно использовать:

sudo shutdown -r +5 "Перезагрузка через 5 минут"

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

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

sudo systemctl reboot --force --force

Двойной --force пропускает большинство проверок и сразу вызывает системный вызов reboot(). Это быстрый, но небезопасный способ, который стоит применять только в аварийных ситуациях.

Проверить последовательность зависимостей можно командой:

systemctl list-dependencies reboot.target

В списке будут shutdown.target, umount.target, systemd-reboot.service и другие системные юниты, которые участвуют в процессе.

Всё, что происходит при перезагрузке, фиксируется в журнале:

journalctl -b -1 | grep systemd-shutdown

Флаг -b -1 выводит записи предыдущего запуска — именно в нём хранятся сообщения о корректной или аварийной остановке.

С точки зрения ядра, перезагрузка — это не отдельный процесс, а особый вариант завершения. Systemd проходит тот же путь, что и при выключении: от user space к kernel space, от kernel к железу. Разница лишь в последней команде. Там, где poweroff отдаёт сигнал ACPI «выключить питание», reboot говорит: «сбросить систему и начать заново».

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

Диагностика

Когда система не загружается, нужно идти по цепочке загрузки сверху вниз — от самого «железа» до ядра и systemd. На каждом уровне есть свои признаки, инструменты и способы восстановления. Ошибка чаще всего происходит в момент передачи управления от одного этапа к следующему, поэтому диагностику удобно строить именно по этой логике.

1. Питание и POST

Если при включении не загораются индикаторы и не запускаются вентиляторы, неисправность аппаратная: блок питания, кнопка, кабели или контакт Power_On. На системных платах с POST-индикаторами можно увидеть коды проверки: 00, A2, 99 и т.д. Эти коды показывают, на каком этапе система остановилась. Если же экран пуст, но слышны сигналы — это POST-ошибка. Например, один длинный и два коротких — видеокарта, непрерывный писк — память.

Когда компьютер хотя бы показывает логотип материнской платы, прошивка BIOS/UEFI запустилась. Если на экране сообщение вроде “No bootable device”, значит POST прошёл, но загрузочное устройство не найдено. Здесь нужно войти в настройки прошивки (обычно клавиши Del, F2 или Esc) и проверить раздел Boot Order. В списке должен стоять правильный диск или флешка. Если UEFI-система не видит GRUB, можно проверить список записей командой:

sudo efibootmgr -v

от имени другой работающей системы или Live USB. Отсутствие записи «GRUB» или «ubuntu» — частая причина того, что система не стартует.

2. GRUB

Если загрузчик запускается, но вы видите только консоль grub> или сообщение grub rescue>, значит повреждён файл конфигурации /boot/grub/grub.cfg или раздел /boot. В этом режиме можно вручную загрузить систему. Сначала просмотрите, какие разделы доступны:

ls

Результат покажет список дисков (hd0,msdos1), (hd0,gpt2) и т.д.). Найдите тот, где лежит каталог /boot. Проверить можно так:

ls (hd0,gpt2)/

Если там есть vmlinuz-... и initrd.img-..., то это нужный раздел. Установите его как корень:

set root=(hd0,gpt2)
set prefix=(hd0,gpt2)/boot/grub
insmod normal
normal

Если normal загружается, появится привычное меню.

Для восстановления загрузчика из Live USB нужно смонтировать разделы:

sudo mount /dev/nvme0n1p3 /mnt
sudo mount /dev/nvme0n1p1 /mnt/boot/efi

и переустановить GRUB:

sudo grub-install --boot-directory=/mnt/boot --efi-directory=/mnt/boot/efi --bootloader-id=GRUB
sudo update-grub

После перезагрузки меню вернётся.

3. Параметры ядра

Иногда GRUB работает, но загрузка останавливается на сообщении вроде kernel panic – not syncing: VFS: Unable to mount root fs. Это значит, что ядро не смогло смонтировать корневую файловую систему. В меню GRUB можно нажать e, чтобы временно изменить параметры загрузки. Найдите строку, начинающуюся с linux, и проверьте значение root=. UUID должен совпадать с реальным UUID корня. Проверить его можно из Live USB:

blkid

Если нужно войти в безопасный режим, уберите опции quiet splash и добавьте:

systemd.unit=rescue.target

Так ядро запустит только базовые службы и предоставит консоль root для восстановления.

4. Initramfs

Если на экране появляется приглашение (initramfs) — ядро загрузилось, но не нашло корневой раздел. Это оболочка busybox внутри initramfs. Здесь можно проверить устройства:

ls /dev
blkid
modprobe nvme
mount /dev/nvme0n1p3 /new_root
switch_root /new_root /sbin/init

Если после switch_root загрузка пошла дальше, значит ошибка была в модуле или UUID. После восстановления системы стоит пересобрать initramfs, чтобы добавить нужные драйверы:

sudo update-initramfs -u -k all

5. Systemd и журналы

Если загрузка зависает уже после появления логотипа или строки Starting ..., значит ядро передало управление systemd, но тот не может активировать нужный сервис. Перейти в однопользовательский режим можно так:

systemd.unit=rescue.target

или в экстренный:

systemd.unit=emergency.target

После входа можно посмотреть логи:

journalctl -xb

Флаг -x добавит пояснения, -b ограничит вывод текущим запуском. Сообщения с пометкой FAILED покажут, какая служба не стартовала. Например, Failed to mount /home укажет на проблему в /etc/fstab.

6. Восстановление с Live USB

Если ни ядро, ни initramfs не поднимаются, загружаются с флешки в режиме «Try Ubuntu» или «Rescue System». Оттуда можно смонтировать разделы:

sudo mount /dev/nvme0n1p3 /mnt
sudo mount /dev/nvme0n1p1 /mnt/boot/efi
sudo chroot /mnt

Теперь вы фактически внутри своей системы. Здесь можно:

  • обновить загрузчик (grub-install, update-grub);
  • пересобрать initramfs (update-initramfs -u);
  • проверить файловую систему (fsck -f /dev/nvme0n1p3);
  • отредактировать /etc/fstab или /etc/default/grub.

После выхода из chroot (exit) и перезагрузки система обычно восстанавливается.

7. Общая логика

Цепочка диагностики всегда одна и та же: питание и POST → загрузчик (GRUB) → ядро и initramfs → systemd → пользовательская сессия. Ошибка в одном звене всегда проявляется тем, что следующее не получает управление.

  • если экран чёрный — не прошли POST или Boot Order;
  • если grub rescue> — повреждён загрузчик;
  • если (initramfs) — ядро не нашло корень;
  • если висит на Starting ... — проблема в systemd или fstab.

Выключение

Когда пользователь нажимает кнопку «Выключить» компьютер или выполняет команду shutdown, система не гаснет мгновенно. Это только сигнал для systemd — первого процесса (PID 1), который контролирует весь жизненный цикл системы. Он отвечает за то, чтобы завершение прошло безопасно: процессы успели закрыть файлы, буферы записались на диск, а устройства корректно отключились.

Процесс всегда начинается одинаково. Команда sudo shutdown -h now сообщает systemd, что нужно перейти к цели poweroff.target, где -h означает «halt» — остановку. Для перезагрузки используется shutdown -r now, что приводит к reboot.target. Все эти команды — лишь разные интерфейсы к одному механизму. poweroff, halt, reboot и даже init 0 или init 6 в современных системах делают одно и то же: отправляют управляющий сигнал PID 1 через D-Bus или системный вызов.

Получив команду, systemd строит обратную цепочку зависимостей. Если при запуске система шла от basic.target к graphical.target, то при завершении она идёт в обратную сторону. Сначала отключаются пользовательские сеансы, затем сервисы более низкого уровня. Systemd рассылает всем активным процессам сигнал SIGTERM — мягкое уведомление «пора завершиться». Хорошо написанные программы ловят его и закрываются корректно: базы данных синхронизируют кэш с журналом, веб-сервера закрывают соединения, SSH-демон записывает финальные логи.

Systemd ждёт короткое время (по умолчанию 90 секунд, параметр TimeoutStopSec= в юните). Если за это время процесс не завершился, он получает SIGKILL — принудительное уничтожение. Разница принципиальна: SIGTERM можно обработать, SIGKILL — нет. Его отправка гарантирует, что ни один зависший процесс не помешает размонтировать файловые системы.

После этого systemd инициирует системный вызов sync(). Он заставляет ядро сбросить всё, что находится в кэшах и буферах, на диск. Это предотвращает потерю данных — ведь во время работы часть изменений хранится только в оперативной памяти. Когда запись завершается, ядро возвращает управление, и systemd начинает размонтировать файловые системы в обратном порядке.

Сначала отключаются дополнительные точки — /home, /var, /boot/efi, затем временные (/run, /tmp), а в конце корень (/). Если какое-то приложение всё ещё держит открытый файл, systemd завершает его насильно и повторяет размонтирование. На этом этапе журнал (journalctl) уже записан и закрыт.

Когда все файловые системы размонтированы, корень переводится в режим только для чтения. Systemd запускает сервис systemd-shutdown, который передаёт управление ядру. Ядро выключает сетевые интерфейсы, останавливает DMA-каналы, сбрасывает контроллеры PCI и отдаёт команде питания ACPI сигнал «Power Off». Если вызывается reboot, ядро вместо этого выполняет аппаратный сброс (reset) и запускает процесс заново, начиная с BIOS или UEFI.

Всё это можно наблюдать в журнале:

journalctl -b -1 | grep systemd-shutdown

Флаг -b -1 показывает записи предыдущего запуска — именно там фиксируются события завершения.

Чтобы посмотреть, какие именно службы выключаются, полезна команда:

systemctl list-dependencies poweroff.target

Она покажет всю цепочку зависимостей: shutdown.target, final.target, umount.target, systemd-poweroff.service. Каждая из них отвечает за свой слой: остановку процессов, размонтирование, отключение устройств и передачу сигнала ядру.

На практике это выглядит так. Когда вы вводите sudo systemctl poweroff, systemd сначала закрывает пользовательские сессии, затем отправляет SIGTERM всем системным демонам: sshd, NetworkManager, cron, dbus-daemon. Через пару секунд идёт SIGKILL тем, кто не ответил. Затем sync(), размонтирование, переход ядра в состояние ACPI S5 — и питание отключается.

Если процесс затянулся, можно посмотреть, кто мешает:

systemd-analyze blame

или

journalctl -b -1 -p warning

Параметр -p warning оставит только предупреждения, часто среди них видно зависший юнит.

Все действия systemd при завершении зеркальны его поведению при запуске. Он использует ту же систему зависимостей, только в обратном порядке. Поэтому выключение Linux — это обратная загрузка: от user space к ядру, от ядра к питанию.

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

Рекомендуемые программы

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845