Последнее изменение файла: 2023.12.12
Скопировано с www.bog.pp.ru: 2024.07.27
Bog BOS: Загрузка Linux
В статье описывается процесс загрузки Linux (x86, GRUB, SysV init):
последовательность выполнения, настройка загрузчиков и /etc/inittab, systemctl.
- инициализация контроллера RAM
- декомпрессия BIOS из флеш в RAM
- защита от записи захваченного куска и передача туда управления
- POST (Power On Self Test) - процедура идентификации, тестирования и конфигурации оборудования
- процедура IPL - Initial Program Load (по мотивам BBS, PnP BIOS, PCI Local Bus, PXE Specification)
- BIOS отображает все найденные Option ROM на системную память
- BIOS включает в таблицу IPL (до 16 записей)
встроенные устройства загрузки (BAID - BIOS Aware IPL Device, не имеют своей Option ROM, код хранится на системной плате) и инициализирует их как умеет
- дополнительные устройства имеют в устройстве или на системной плате Option ROM (например, PCI Expansion ROM),
которые должны иметь стандартный формат заголовка (сигнатура 55AAh) с заголовком расширения "$PnP"
(один Option ROM может иметь несколько заголовков расширения, каждый имеет контрольную сумму), который позволяет отнести устройства
к BEV (Bootstrap Entry Vector - смещение программы загрузки, например, контроллер Ethernet)
или BCV (Boot Connection Vector - смещение программы подключения, например, контроллер RAID;
может захватывать прерывания 9h (ввод), 10h (вывод) и 13h (диск));
также содержит идентификатор устройства, имя изготовителя, название продукта
(серийного номера не предусмотрено, поэтому в меню загрузки будет 8 одинаковых названий моделей диска),
тип устройства, подтип устройства, флажки (это устройство ввода, это устройство вывода, включить в IPL, прочее)
- BIOS поочерёдно передаёт управление на вектор инициализации внутри заголовка
(переход, сегментная адресация - 16-bit Real Mode или 16-bit Protected Mode (16:16),
совместимый с адаптированными вызовами в 32-bit Protected Mode (16:32), совместимость с 0:32 Protected Mode (flat) не предполагалась)
каждого Option ROM (сначала видео, ввод и IPL);
инициализация не должна перехватывать прерывания 9h, 10h и 13h;
возвращает флажки: может обслуживать прерывания 9h (ввод), 10h (вывод) и 13h (диск), устройство готово к обслуживанию;
по ходу дела инициализируются требуемые шины и мосты;
программа инициализации BCV после включения устройства ищет подключённые устройства и для каждого добавляет заголовок BCV в памяти
и добавляет свой первый диск в список IPL
- BIOS просматривает все Option ROM (в памяти) и ведёт таблицу BCV контроллеров с приоритетами BCV,
передаёт управление на сегментный адрес программы подключения (перехватывает прерывания 9h, 10h или 13h)
- BIOS просматривает все Option ROM (в памяти) и определяет потенциальные загрузочные устройства из BEV и составляет таблицу IPL:
тип устройства, флажки (индекс последней загрузки в таблице, активное устройство, была ошибка, носитель готов),
сегментный адрес программы загрузки, строка описания ASCIIZ - имя продукта
- приоритет загрузки определяется оператором при настройке BIOS и хранится в NVRAM (по умолчанию, сначала BAID, затем BEV устройства)
- BIOS перебирает в соответствии с приоритетами загрузочные устройства из таблицы IPL и пытается с них загрузиться
(передаёт управление на сегментный адрес программы загрузки);
при неудаче программа загрузки должна выдать INT 18h (когда-то тут был BASIC)
- программе загрузки передаётся номер загрузочного устройства (80h для первого НЖМД)
- программа загрузки действует в зависимости от типа устройства:
- блочное устройство: загрузка загрузочного сектора (512 байт) в память по адресу 0000:7C00h и передача ему управления;
если загрузка с жёсткого диска, то загрузочный сектор лежит в MBR (Master Boot Record)
- CD-ROM: см. описание спецификации El Torito
- сетевой контроллер (BEV): PXE
- первоначальный загрузчик находит и загружает программу загрузки 2 этапа
(stage 2) и передаёт ей управление (GRUB, LILO, SYSLINUX);
используется BIOS API; обычное место загрузчика 2 этапа - /boot/
- загрузчик 2 этапа выбирает, находит и загружает ядро и RAM диск (initrd)
в память;
GRUB читает конфигурацию из /boot/grub/grub.conf;
конфигурация для LILO хранится в MBR;
GRUB и LILO позволяют вывести список возможных загружаемых систем
на экран и выбрать нужную с помощью клавиатуры;
GRUB позволяет изменить параметры загрузки (корневая файловая система,
ядро, RAM диск, параметры ядра) с помощью текстового редактора;
используется BIOS API;
RAM диск содержит образ файловой системы с модулями (драйверами)
устройств, необходимыми для монтирования корневой файловой системы;
в случае со встроенным Linux RAM диск содержит всю систему
- ядро повторно обходит и инициализирует периферийные устройства,
для которых есть встроенные драйвера
- ядро монтирует RAM диск (предварительно разжав) и загружает
с него необходимые модули,
инициализирует соответствующие устройства
- если необходимо, то ядро инициализирует LVM и программный RAID
- ядро размонтирует RAM диск и освобождает занимаемую им память
- ядро монтирует корневую файловую систему в режиме "только чтение";
в процессе дальнейшей работы ядро загружает дополнительные модули
с корневой файловой системы
- запускается процесс /sbin/init (далее описывается загрузка в стиле
System V)
- init разбирает конфигурационный файл /etc/inittab
для определения дальнейших действий;
если при загрузке указан уровень s (или S), то inittab не читается,
а система переходит в однопользовательский режим (shell на
/dev/console с правами root);
строка с действием initdefault определяет
"уровень выполнения" (run level) по умолчанию, т.е. режим работы системы
(однопользовательская, многопользовательская, с доступом в сеть,
с графическим окружением и т.д.);
строка с действием sysinit (/etc/rc.d/rc.sysinit) определяет
скрипт инициализации;
- init выполняет скрипт /etc/rc.d/rc.sysinit (проверка и монтирование
остальных файловых систем, swap и т.д.)
- в "нормальном" /etc/inittab при переходе на любой уровень запускается
скрипт /etc/rc.d/rc с указанием уровня в качестве параметра;
данный скрипт запускает скрипты /etc/rcуровень.d/K*
(в алфавитном порядке) с параметром stop и скрипты
/etc/rcуровень.d/S* с параметром start;
в конце запускается /etc/rc.d/rc.local;
по традиции скрипты являются символьными ссылками
на скрипты в директории /etc/init.d/;
вместо /etc/init.d/ может использоваться /etc/rc.d/init.d/;
вместо /etc/rcуровень.d/ может использоваться /etc/rc.d/rcуровень.d;
реальность несколько сложнее
- инициализация платформы UEFI
- менеджер загрузки UEFI выбирает драйверы и приложения из списка
- загрузка ядра и RAM диска;
RAM диск содержит образ файловой системы с модулями (драйверами)
устройств, необходимыми для монтирования корневой файловой системы;
в случае со встроенным Linux RAM диск содержит всю систему
- ядро повторно обходит и инициализирует периферийные устройства, для которых есть встроенные драйвера
- ядро монтирует RAM диск (предварительно разжав) и загружает с него необходимые модули,
инициализирует соответствующие устройства - dracut
- ядро размонтирует RAM диск и освобождает занимаемую им память
- ядро монтирует корневую файловую систему в режиме "только чтение";
в процессе дальнейшей работы ядро загружает дополнительные модули с корневой файловой системы
- запускается процесс /usr/lib/systemd/systemd
- тут будет длинный рассказ после того как systemd устоится
systemd (LGPL) - управление системой и сервисам.
RHEL/CentOS 7.9 - версия 219.
Запускается как PID 1 вместо initd (sysvinit). Для совместимости поддерживает скрипты инициализации LSB.
Управляет запуском модулей (unit) и отслеживает зависимость между модулями.
В будущем заменит собой все системные сервисы Linux. Уже имеется сервис журнализации (systemd-journal вместо syslog),
управление сеансами пользователей (systemd-logind вместо ConsoleKit), временем и сетевым временем (timedated и timesyncd вместо ntpd/chronyd),
именем хоста (вместо hostbame), именами DNS (systemd-resolved вместо библиотеки resolv), локалью (localed вместо ?),
контейнерами и виртуальными машинами (systemd-nspawn, machinectl, systemd-machined.service),
учётными записями, настройками, сетевыми интерфейсами (networkd, networkctl, /lib/systemd/network/ вместо network-scripts и nmcli),
монтированием (вместо /etc/fstab и mount) и монтированием по требованию (вместо automount), замена chroot
и UEFI загрузчику (systemd-boot), systemd-tmpfiles, systemd-udevd. Кстати, Gnome 3.8 и выше не работает без systemd.
Использует D-Bus, cgroups и Unix-сокеты для общения между процессами.
Контролирует состояние модулей и реагирует на их изменение.
Позволяет активировать сервисы по зависимостям, обращению к портам (замена inetd, xinetd.service?), по расписанию (замена cron).
Типы модулей
- сервисы (.service) - набор процессов, изолируемых средствами cgroups
- цель, режим работы (.target) - группа сервисов (аналог уровня initd)
- точка монтирования (.mount)
- точка монтирования по запросу (.automount)
- раздел подкачки (.swap)
- запуск других модулей по расписанию (.timer)
- работа с сокетами (.socket)
- контейнер cgroups (.slice)
- подключение устройства (.device)
- управление иерархией файловой системы (.path)
- .snapshot
- .scope
Основной файл настройки - /etc/systemd/system.conf (/etc/systemd/system/).
systemctl - утилита управления, systemd-analyze - трассировка загрузки.
systemctl - основная управляющая утилита systemd. Файл настройки - /etc/systemd/system.conf.
Список сервисов: systemctl [--all] [--state={active|failed}] {list-units|list-unit-files} [режим-работы].
Управление работой сервисов: systemctl {is-active|status|start|stop|reload|restart} имя-сервиса.
Управление запуском сервисов при загрузке: systemctl {disable|enable|preset} имя-сервиса.
Управление режимом работы (аналог уровня в inittab): systemctl set-default {graphical.target|multi-user.target|rescue.target}.
Ключ ядра systemd.unit=имя-режима. Сервис debug-shell обеспечивает оболочку во время загрузки (enable).
Перезапуск systemd: systemctl daemon-reload. Необходимо, например, при добавлении сервиса.
Перезагрузка: systemctl reboot [--firmware-setup].
7 Ctrl-Alt-Del в течении 2 секунд - немедленная перезагрузка.
Привычный /etc/rc.local лежит в /etc/rc.d/rc.local, настройки systemd сервиса rc-local расположены в /usr/lib/systemd/system/rc-local.service,
запускается в режиме multi-user.target после network.target, предварительно необходимо дать права на выполнение
chmod u+x /etc/rc.d/rc.local
Пример своего сервиса (/usr/lib/systemd/system/имя-сервиса.service):
[Unit]
Description=Confluence
After=network.target nss-lookup.target
[Service]
Type=forking
WorkingDirectory=/home/confluence/atlassian-confluence-5.9.7
ExecStart=/home/confluence/atlassian-confluence-5.9.7/bin/start-confluence.sh
PIDFile=/home/confluence/atlassian-confluence-5.9.7/work/catalina.pid
ExecStop=/home/confluence/atlassian-confluence-5.9.7/bin/stop-confluence.sh
ExecReload=/home/confluence/atlassian-confluence-5.9.7/bin/stop-confluence.sh | sleep 60 | /home/confluence/atlassian-confluence-5.9.7/bin/start-confluence.sh
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=Confluence
SyslogFacility=daemon
IOSchedulingClass=best-effort
Restart=on-failure
[Install]
WantedBy=multi-user.target
/etc/fstab превращается в модули *.mount на лету (не совсем корректно).
systemd-analyze set-log-level notice
В различных дистрибутивах и различных ситуациях могут использоваться
следующие загрузчики:
LILO и GRUB работают через BIOS,
а большинство BIOS позволяют доступ только
к первым двум IDE-дискам (считая ATAPI CD-ROM) в пределах первых 1023 цилиндров.
Так что каталог (или раздел) /boot, в котором хранятся как файлы самого
загрузчика, так и загружаемые файлы (ядро, initrd) должен удовлетворять
данным ограничениям.
Формат файла /etc/inittab
(комментарии начинаются с символа '#'):
идентификатор:перечень-уровней-выполнения:действие:процесс
где
- идентификатор - уникальная последовательность от 1 до 4 символов
(в старых версиях до 2); для getty и ему подобных идентификатор
д.б. номером линии tty
- перечень-уровней-выполнения - перечисление (без пробела) уровней
выполнения, для которых выполняется указанное действие
(от 0 до 6 и от A до C, s, S); для sysinit, boot и bootwait
игнорируется; при смене уровня всем процессам, не специфицированным
для этого уровня, посылается сигнал SIGTERM, а через 5 секунд (интервал
задаётся при вызове telinit -t) сигнал SIGKILL
(init предполагает, что процесс не сменил группу процессов, в которой
он его запустил);
пустой список означает "для всех"
- действие (по-моему, тут перемешанны условия и действия)
- respawn (процесс по завершении запускается вновь и вновь;
после 10 перезапусков за 2 минуты делается пауза 5 минут)
- wait (процесс запускается один раз при переходе на уровень,
init ждёт его завершения)
- once (процесс запускается один раз при переходе на уровень)
- boot (процесс запускается при загрузке системы)
- bootwait (процесс запускается при загрузке системы,
init ждёт его завершения)
- off (ничего не делать)
- ondemand (процесс запускается при вызове данного уровня
выполнения (от A до C), но смены уровня не происходит)
- initdefault (на какой уровень выполнения переходить после загрузки;
если не указан, то будет спрашивать на консоли)
- sysinit (процесс запускается при загрузке до boot и bootwait)
- powerwait (вызывается при пропадании питания, например, программой
слежения за UPS,
SIGPWR (подробности в /etc/powerstatus: FAIL),
init ждёт его завершения)
- powerfail (вызывается при пропадании питания, например, программой
слежения за UPS,
SIGPWR (подробности в /etc/powerstatus: FAIL),
init не ждёт его завершения)
- powerokwait (вызывается при возобновлении питания,
SIGPWR (подробности в /etc/powerstatus: OK),
init ждёт его завершения)
- powerfailnow (вызывается непосредственно перед исчерпанием
аккумуляторов UPS, SIGPWR (подробности в /etc/powerstatus: LOW))
- ctrlaltdel (вызывается при получении сигнала SIGINT от ядра)
- kbrequest (ядро посылает SIGWINCH при нажатии определённой
комбинации клавиш)
- процесс - имя файла ('+' перед символом отменяет запись utmp и wtmp),
программа или скрипт
При запуске процесса устанавливаются переменные окружения:
PATH, INIT_VERSION, RUNLEVEL, PREVLEVEL, CONSOLE.
Уровни выполнения для Red Hat Linux:
- 0: halt (неинтереактивный уровень)
- 1: single user (одна виртуальная консоль)
- 2: multiuser (6 виртуальных консолей)
- 3: multiuser + NFS (6 виртуальных консолей)
- 4: не используется
- 5: X11 (6 виртуальных консолей и xdm, gdm или kdm
в зависимости от /etc/X11/prefdm)
- 6: reboot (неинтереактивный уровень)
Переход на другой уровень можно сделать с помощью
программы telinit или прямо через /dev/initctl.
telinit с указанием уровня q (Q) заставляет init
перечитать /etc/inittab. Использование SIGPWR и /etc/powerstatus признано
устаревшим.
Загрузчик может передать процессу init параметры
- -s, S, single (загрузка в однопользовательском режиме)
- от 1 до 5 (явное задание уровня выполнения)
- -b, emergency (однопользовательский режим без выполнения sysinit)
- -a, auto (устанавливается переменная AUTOBOOT)
Copyright © 1996-2024 Sergey E. Bogomolov; www.bog.pp.ru