Вопрос или проблема
Встраиваемое устройство на 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
служит для указания места файловой системы, которая формируется в оперативной памяти. А для изменения и поддержки файловой системы, работа с различными модулями и программными инструментами позволит гибко управлять данными в рамках временного загрузчика.