Фазы загрузки Linux
- title
- Фазы загрузки Linux
- type
- concept
- summary
- Шестифазная модель загрузки Linux на x86_64: каждая фаза, от трамплина до kernel_init, открывает возможности, нужные следующей
- tags
- linux, kernel, boot
- parent
- linux-kernel-startup
- created
- 2026-05-14
- updated
- 2026-05-14
- lang
- ru
- translation_of
- linux-boot-phases
- source_updated
- 2026-05-14
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Загрузка Linux на x86_64 - это строго упорядоченная последовательность сборки, а не скрипт. У каждой фазы свои границы дозволенного ("что мы сейчас можем делать"), и порядок важен: каждый шаг открывает возможности, необходимые следующему. В схеме Эспино в linux-kernel-startup процесс разбит на шесть фаз.
Фазы
| Фаза | Точка входа | Что становится возможно |
|---|---|---|
| 1. Ассемблер | startup_64 |
CPU в Long Mode, таблицы страниц выправлены, всё готово к исполнению C |
| 2. Ранний C | x86_64_start_kernel |
Очищена .bss, настроены обработчики исключений, сохранены параметры загрузки, применён микрокод |
3. setup_arch |
setup_arch() |
Определены возможности CPU, разобрана карта памяти, отображена вся RAM, доступен early printk |
4. start_kernel |
start_kernel() |
Работает kmalloc, подняты планировщик/RCU/таймеры, включены прерывания, настоящая консоль, ядро пропатчило себя под этот CPU |
5. rest_init |
rest_init() |
Созданы PID 1 (kernel_init) и PID 2 (kthreadd); поток загрузки становится idle |
6. kernel_init |
kernel_init_freeable() |
Пробуждены остальные CPU, загружены драйверы, смонтирован корень, освобождена память __init, работает userspace |
Почему важен порядок
Большая часть структуры держится на двух правилах упорядочивания:
Прерывания отключены, пока нет всего, что их обрабатывает. Фаза 4 почти целиком проходит с отключёнными прерываниями. Ядро не может принять прерывание, пока не настроен контроллер IRQ, не могут срабатывать таймеры, не поднят RCU, у timekeeper'а нет источника времени, а подсистема printk не может сообщить об ошибке. Вызов local_irq_enable() происходит глубоко внутри start_kernel(), а не в самом его начале.
Каждый аллокатор передаёт дела следующему. На этапе загрузки ядро живёт на memblock (это скорее трекер, чем полноценный аллокатор), пока mm_core_init() не поднимет стек buddy -> SLUB -> vmalloc. Точкой передачи владения служит memblock_free_all(); начиная с этого момента все выделения памяти идут через аллокатор страниц и slab-кэш.
Передача управления: поток загрузки становится idle
Самая важная граница проходит между фазой 4 и фазой 5. На протяжении всей фазы 4 всю работу выполняет единственный поток (init_task). sched_init() тихо переименовывает его в задачу idle для загрузочного CPU - но поток продолжает выполнять код инициализации. Сама передача управления происходит в rest_init(): schedule_preempt_disabled() отдаёт CPU, и когда управление возвращается, исходный поток навсегда уходит в do_idle(). С этого момента работу по загрузке ведёт PID 1 (kernel_init). Единое выполнение разделяется на три потока: PID 0 (idle), PID 1 (init -> userspace), PID 2 (kthreadd).
Правило "двери запирают последними"
Несколько механизмов защиты включаются в фазе 6 после выполнения большей части кода, поскольку эта защита помешала бы его работе:
mark_readonly()переводитrodataв режим только для чтения на уровне таблиц страниц - раньше этого сделать нельзя, так как ядро патчило собственный код (alternatives, jump labels).pti_finalize()финализирует Page Table Isolation - по той же причине.free_initmem()освобождает память функций с атрибутом__init- это должно происходить строго после того, как завершится последняя функция__init.
Что полезно перенять из этой модели
Разбиение на шесть фаз специфично для Linux, но два общих паттерна применимы к любому процессу загрузки:
- Границы возможностей на каждой фазе. У каждой фазы свой набор доступных функций ("что мы сейчас можем вызывать?"). Документирование этих границ - самое полезное, что может дать карта загрузки.
- Передача аллокаторов как дискретное событие. Простой bootstrap-аллокатор уступает место настоящему в конкретный момент. Фазы до этого момента могут работать только с сырыми блоками памяти; фазы после него - с объектами.
Ссылки
- linux-kernel-startup - статья, из которой взята эта модель
- kernel-self-patching - перезапись кода во время выполнения в фазе 4
- linux-preemption-models - что происходит с планированием после завершения загрузки