Загрузка ядра (FIT-образ) без rootfs

Вопрос или проблема

Встраиваемое устройство на Linux, с которым я работаю, имеет следующий параметр ядра:

root=/dev/ram0

Кроме того, образ ядра объединяется вместе с initrd и деревом устройств, чтобы создать упрощенное дерево образов, или образ FIT.

Когда устройство полностью загружено, у него нет постоянного хранилища. То есть все, что записывается в файловую систему, является полностью временным. Учитывая переданный ядру параметр root=, это не вызывает удивления.

Мой вопрос: Как это работает?

  • Я знаю, что Uboot копирует ядро в ОЗУ и выполняет его с помощью команды bootm, но откуда берутся файлы файловой системы? Содержатся ли они в initrd? Я понимаю, что initrd – это временная конструкция. Если это так, это будет смещение в блобе образа FIT. Так как просто передача root=/dev/ram0 достаточна для того, чтобы ядро знало, где находится его файловая система?

  • Ядро выполняет интроспекцию и читает заголовок образа FIT, чтобы определить расположение составных компонентов?

  • Как изменения файловой системы поддерживаются внутри образа FIT, учитывая, что он будет упакован вместе как с ядром, так и с блобом дерева устройств?

Я знаю, что Uboot копирует ядро в ОЗУ и выполняет его с командой bootm, но откуда берутся файлы файловой системы?

Перед тем как загрузить fitImage, его нужно загрузить в ОЗУ. После этого вы можете запустить его с помощью bootm. Внутри образа fit можно определить Load Address и Entry Point для ядра, например.

Содержатся ли они в initrd? Я понимаю, что initrd – это временная конструкция. Если это так, это будет смещение в блобе образа FIT. Так как просто передача root=/dev/ram0 достаточна для того, чтобы ядро знало, где находится его файловая система?

Это зависит от вашей системы, что подразумевается под файловой системой. Есть несколько систем, работающих исключительно с RAMDISK и просто сохраняющих конфигурацию в любом виде NVRAM или Flash.

Другие системы используют RAMDisk, чтобы проверить, где найти корневую файловую систему. Например, для сканирования USB-шины, SATA или SD-карт. Когда корневая файловая система смонтирована, процесс загрузки продолжается с этого раздела. Из-за того, что init должен выполняться с PID 1, некоторые приемы необходимы.

Ядро выполняет интроспекцию и читает заголовок образа FIT, чтобы определить расположение составных компонентов?

Нет, образ fit разбирается u-boot. Как u-boot передает адреса, где находятся DTB и RAMDISK, зависит от используемой платформы, насколько мне известно.

Как изменения файловой системы поддерживаются внутри образа FIT, учитывая, что он будет упакован вместе как с ядром, так и с блобом дерева устройств?

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

Посмотрев на исходный код ядра:

  • mtdsplit_fit.c

        /* Поиск раздела rootfs после образа FIT */
        ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size,
                                   &rootfs_offset, NULL);
        if (ret) {
                pr_info("rootfs не найден после образа FIT в \"%s\"\n",
                        mtd->name);
                return ret;
        }
    
  • mtdsplit.c:

    int mtd_find_rootfs_from(struct mtd_info *mtd,
                             size_t from,
                             size_t limit,
                             size_t *ret_offset,
                             enum mtdsplit_part_type *type)
    {
            size_t offset;
            int err;
    
            for (offset = from; offset < limit;
                 offset = mtd_next_eb(mtd, offset)) {
                    err = mtd_check_rootfs_magic(mtd, offset, type);
                    if (err)
                            continue;
    
                    *ret_offset = offset;
                    return 0;
            }
    
            return -ENODEV;
    }
    EXPORT_SYMBOL_GPL(mtd_find_rootfs_from);
    
    int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
                               enum mtdsplit_part_type *type)
    {
            u32 magic;
            size_t retlen;
            int ret;
    
            ret = mtd_read(mtd, offset, sizeof(magic), &retlen,
                           (unsigned char *) &magic);
            if (ret)
                    return ret;
    
            if (retlen != sizeof(magic))
                    return -EIO;
    
            if (le32_to_cpu(magic) == SQUASHFS_MAGIC) {
                    if (type)
                            *type = MTDSPLIT_PART_TYPE_SQUASHFS;
                    return 0;
            } else if (magic == 0x19852003) {
                    if (type)
                            *type = MTDSPLIT_PART_TYPE_JFFS2;
                    return 0;
            } else if (be32_to_cpu(magic) == UBI_EC_MAGIC) {
                    if (type)
                            *type = MTDSPLIT_PART_TYPE_UBI;
                    return 0;
            }
    
            return -EINVAL;
    }
    EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic);
    

Ответ или решение

Как работает загрузка ядра (FIT-образ) без rootfs

Когда вы работаете с встроенным устройством на базе Linux, в котором используется бинарный образ ядра, обернутый в FIT (Flattened Image Tree), возникает ряд вопросов о процессе загрузки и функционировании системы без постоянного хранилища. Давайте разберемся, как осуществляется загрузка и какие механизмы обеспечивают работу файловой системы в таком контексте.

Структура загрузки

Во-первых, важно понимать, что при загрузке устройства U-Boot выполняет ряд ключевых шагов. Он копирует ядро в оперативную память (RAM) и выполняет команду bootm, указывая адрес загрузки и точки входа. Как правило, в FIT-образ включены не только файл ядра, но и and initrd (инициализационный RAM-диск) и дерево устройств (Device Tree Blob, DTB).

Роль initrd

Теперь обратим внимание на ваш вопрос о файловой системе. Однако, перед загрузкой необходимо переместить FIT-образ в оперативную память. После этой операции U-Boot осуществляет вызов bootm, в результате чего ядро получает указания о размещении различных компонентов, включая initrd. Initrd действительно представляет собой временное хранилище, которое позволяет загрузить необходимые модули и настроить окружение до того, как будет сконфигурирован окончательный корень файловой системы. В данном случае, параметр root=/dev/ram0 указывает ядру, что файловая система будет находиться в RAM-диске, загруженном в initrd.

Способы работы с файловой системой

Хотя вы правильно заметили, что initrd — это временное решение, эта структура на самом деле содержит необходимые файлы для последующей инициализации системы. Если у вашего устройства нет постоянного накопителя, то все изменения сохраняются в энергонезависимой памяти, такой как NVRAM или Flash. В случае, когда файл initrd успешно загружен, ядро знает, как обратиться к месту, где хранится файл системы — оно извлекает информацию из initrd и начинает процесс инициализации.

Интроспекция и размещение компонентов

Что касается вашего вопроса о том, читает ли ядро заголовок FIT-образа, чтобы определить размещение составляющих компонентов, следует отметить, что U-Boot обрабатывает FIT-образ. Он извлекает информацию о расположении различных сегментов, таких как DTB и RAM-диск. Поэтому ядру не требуется производить дополнительные действия или интроспекцию — все адреса передаются ему от U-Boot.

Поддержка изменений файловой системы в FIT-образе

Наконец, существует и вопрос о том, как изменения в файловой системе возможны при использовании FIT-образа. По сути, когда требуется частое изменение файловой системы, удобно использовать модули, позволяющие делать инкрементальные обновления, или программные решения с поддержкой FUSE, которые облегчают взаимодействие с временной файловой системой. Однако, как уже было упомянуто, конечное решение сильно зависит от используемой аппаратной платформы и типа хранилища (SD-карты, NAND, NOR и т.д.).

Заключение

Таким образом, загрузка ядра из FIT-образа без постоянного хранилища остается сложной, но осуществимой задачей благодаря механизму U-Boot и правильной структуре initrd. Параметр root=/dev/ram0 служит для указания места файловой системы, которая формируется в оперативной памяти. А для изменения и поддержки файловой системы, работа с различными модулями и программными инструментами позволит гибко управлять данными в рамках временного загрузчика.

Оцените материал
Добавить комментарий

Капча загружается...