цепочка загрузки встраиваемого Linux

July 30, 2026 · посетителей

В прошлый раз я писал про DFU как способ прошивки firmware через USB. Тот пост оставил без ответа один вопрос, который заслуживает отдельного разбора: что на самом деле происходит между нажатием кнопки питания и появлением приглашения shell? DFU — лишь одно из ответвлений этого пути, так что стоит один раз пройти весь путь целиком.

Этапы

В виде flowchart на Mermaid цепочка (с местом DFU в ней) выглядит так:

flowchart TD
    A[Power-on / Reset] --> B[Boot ROM<br/>immutable, on-chip]
    B --> C{Valid image on<br/>boot media?}
    C -->|No / forced| D[ROM recovery mode<br/>UART / USB]
    C -->|Yes| E[SPL<br/>first-stage bootloader]
    E --> F[U-Boot<br/>second-stage bootloader]
    F --> G{Enter DFU?}
    G -->|Yes| H[DFU mode<br/>waiting for firmware over USB]
    G -->|No| I[Load kernel + device tree]
    I --> J[Linux kernel]
    J --> K[Mount root filesystem]
    K --> L[init / systemd]

И в отрисованном виде:

Схема цепочки загрузки встраиваемого Linux: включение питания приводит к сбросу в boot ROM, которая проверяет носитель загрузки на наличие валидного образа. Если он не найден (или восстановление вызвано принудительно), система переходит в режим восстановления через UART/USB. В противном случае загружается SPL, который загружает собственно U-Boot. U-Boot может либо войти в режим DFU и ждать прошивку по USB, либо загрузить ядро и device tree, запустить Linux, смонтировать корневую файловую систему и передать управление init/systemd.

Boot ROM

Записана в кремний на этапе производства — после этого в ней ничего нельзя изменить. Её единственная задача — найти хоть что-то загружаемое на одном из небольшого набора носителей загрузки (eMMC, SD, QSPI-флеш, иногда USB) в соответствии с boot-mode пинами или eFuse, и перейти туда. Если ничего подходящего не найдено, большинство SoC на этом этапе переключается в минимальный режим восстановления через UART или USB — самое первое место, где вообще можно "поговорить" с чипом.

SPL

Сокращение от Secondary Program Loader (термин U-Boot; другие производители называют это FSBL или похоже). Он выполняется из небольшого объёма SRAM на кристалле, ещё до инициализации DRAM, поэтому должен быть крошечным. Его основная задача именно в этом: поднять DRAM, а затем загрузить в неё следующий этап — полноценный U-Boot.

U-Boot целиком

Это тот загрузчик, который большинство людей имеет в виду, говоря "загрузчик". У него есть драйверы, shell, переменные окружения, поддержка сети и интерпретатор команд. Именно здесь на самом деле живёт DFU — выполнение dfu 0 mmc 0 (или похожей команды) переводит U-Boot в режим DFU вместо продолжения обычной загрузки, и именно с этим режимом со стороны хоста общается dfu-util. В противном случае он загружает образ ядра и blob device tree в память и передаёт управление ядру.

Ядро и пользовательское пространство

Ядро распаковывает себя, поднимает консоль, опрашивает оборудование, используя переданное ему device tree, и монтирует корневую файловую систему — часто ту же карту eMMC или SD, с которой загружался загрузчик, иногда NFS во время разработки. После монтирования корневой файловой системы ядро передаёт управление процессу с PID 1 — обычно это systemd на образе, собранном с помощью Yocto, — и именно здесь на самом деле начинается "пользовательское пространство".

Почему это важно для DFU

DFU обретает смысл только тогда, когда видно его место в цепочке: это ответвление, которое U-Boot может выбрать вместо загрузки ядра, а не отдельная надстройка сверху. Именно поэтому DFU не может спасти от любого сбоя: если сама boot ROM не может найти валидный SPL, вы вообще никогда не доберётесь до U-Boot и будете зависеть от того, какой режим восстановления поддерживает boot ROM (а это сильно варьируется от производителя к производителю и заслуживает отдельного поста).

Дополнительное чтение

По теме

Комментарии