Портируем GNU/Linux на ARM-плату (на примере Kali и iMX.6)
tl; dr: собираю образ Kali Linux для ARM-компьютера, в программе debootstrap
, linux
и u-boot
.
Если вы покупали какой-нибудь не очень популярный одноплатник, то могли столкнуться с отсутствием для него образа любимого дистрибутива. Приблизительно то же самое случилось с планируемым Flipper One. Kali Linux под IMX6 просто нету (я готовлю), поэтому собирать приходится самостоятельно.
Процесс загрузки достаточно простой:
- Инициализируется железо.
- Из некоторой области на запоминающем устройства (SD-карта/eMMC/etc) считывается и выполняется загрузчик.
- Загрузчик ищет ядро операционной системы и загружает его в некоторую область памяти и выполняет.
- Ядро загружает всю остальную ОС.
Для моей задачи хватает такого уровня детализации, подробности можете прочесть в другой статье. Упомянутые выше «некоторые» области отличаются от платы к плате, что и создаёт некоторые сложности с установкой. Загрузку серверных ARM-платформ пытаются стандартизовать с помощью UEFI, но покуда это доступно не для всех, придётся собирать всё по отдельности.
Сборка корневой файловой системы
Для начала нужно подготовить разделы. Das U-Boot поддерживает разные ФС, я выбрал FAT32 для /boot
и ext3 для корня, это стандартная разметка образов для Kali под ARM. Я воспользуюсь GNU Parted, но вы можете сделать то же самое более привычным fdisk
. Также понадобятся dosfstools
и e2fsprogs
для создания ФС: apt install parted dosfstools e2fsprogs
.
Размечаем SD-карту:
- Отмечаем SD-карту как использующую MBR-разметку:
parted -s /dev/mmcblk0 mklabel msdos
- Создаём раздел под
/boot
на 128 мегабайт:parted -s /dev/mmcblk0 mkpart primary fat32 1MiB 128MiB
. Первый пропущенный мегабайт необходимо оставить под саму разметку и под загрузчик. - Создаём корневую ФС на всю оставшуюся ёмкость:
parted -s /dev/mmcblk0 mkpart primary ext4 128MiB 100%
- Если вдруг у вас не создались или не изменились файлы разделов, надо выполнить `partprobe`, тогда таблица разделов будет перечитана.
- Создаём файловую систему загрузочного раздела с меткой
BOOT
:mkfs.vfat -n BOOT -F 32 -v /dev/mmcblk0p1
- Создаём корневую ФС с меткой
ROOTFS
:mkfs.ext3 -L ROOTFS /dev/mmcblk0p2
Отлично, теперь можно её заполнять. Для этого дополнительно потребуется debootstrap
, утилита для создания корневых ФС Debian-подобных операционных систем: apt install debootstrap
.
Собираем ФС:
- Монтируем раздел в
/mnt/
(используйте более удобную для себя точку монтирования):mount /dev/mmcblk0p2 /mnt
- Собственно заполняем файловую систему:
debootstrap --foreign --include=qemu-user-static --arch armhf kali-rolling /mnt/ http://http.kali.org/kali
. Параметр--include
указывает дополнительно установить некоторые пакеты, я указал статически собранный эмулятор QEMU. Он позволяет выполнятьchroot
в ARM-окружение. Смысл остальных опций можно посмотреть вman debootstrap
. Не забудьте, что не любая ARM-плата поддерживает архитектуруarmhf
. - Из-за разницы архитектур
debootstrap
выполняется в два этапа, второй выполняется так:chroot /mnt/ /debootstrap/debootstrap --second-stage
- Теперь нужно зачрутиться:
chroot /mnt /bin/bash
- Заполняем
/etc/hosts
и/etc/hostname
целевой ФС. Заполните по аналогии с содержимым на вашем локальном компьютере, не забудьте только заменить имя хоста. - Можно донастроить всё остальное. В частности я доустанавливаю
locales
(ключи репозитория), перенастраиваю локали и часовой пояс (dpkg-reconfigure locales tzdata
). Не забудьте задать пароль командойpasswd
. - Задаём пароль для
root
командойpasswd
. - Приготовления образа для меня завершаются заполнением
/etc/fstab
внутри/mnt/
.
Загружать буду в соответствии с созданными ранее метками, поэтому содержимое будет таким:
LABEL=ROOTFS / auto errors=remount-ro 0 1
LABEL=BOOT /boot auto defaults 0 0
Наконец, можно примонтировать загрузочный раздел, он нам понадобится для ядра: `mount /dev/mmcblk0p1 /mnt/boot/`
Сборка Linux
Для сборки ядра (и загрузчика потом) на Debian Testing надо установить стандартный набор из GCC, GNU Make и заголовочных файлов GNU C Library для целевой архитектуры (у меня armhf
), а также заголовки OpenSSL, консольный калькулятор bc
, bison
и flex
: apt install crossbuild-essential-armhf bison flex libssl-dev bc
. Так как загрузчик по умолчанию ищет файл zImage
на файловой системе загрузочного раздела, пора разбивать флешку.
- Клонировать ядро слишком долго, поэтому просто скачаю:
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.9.1.tar.xz
. Распакуем и перейдём в директорию с исходниками:tar -xf linux-5.9.1.tar.xz && cd linux-5.9.1
- Конфигурируем перед компиляцией:
make ARCH=arm KBUILD_DEFCONFIG=imx_v6_v7_defconfig defconfig
. Конфиг находится в директорииarch/arm/configs/
. Если такового нет, вы можете попробовать найти и скачать готовый и передать название файла в этой директории в параметрKBUILD_DEFCONFIG
. В крайнем случае сразу переходите к следующему пункту. - Опционально можно докрутить настройки:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
- И кроскомпилируем образ:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
- Теперь можно скопировать файлик с ядром:
cp arch/arm/boot/zImage /mnt/boot/
- И файлы с DeviceTree (описание имеющегося на плате железа):
cp arch/arm/boot/dts/*.dtb /mnt/boot/
- И доустановить собранные в виде отдельных файлов модули:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=/mnt/ modules_install
Ядро готово. Можно всё отмонтировать: umount /mnt/boot/ /mnt/
Das U-Boot
Так как загрузчик интерактивный, для проверки его работы достаточно самой платы, запоминающего устройства и опционально устройства USB-to-UART. То есть, можно ядро и ОС отложить на потом.
Абсолютное большинство производителей предлагают использовать Das U-Boot для первичной загрузки. Полноценная поддержка обычно обеспечивается в собственном форке, но и в апстрим контрибьютить не забывают. В моём случае плата поддерживается в мейнлайне, поэтому форк я проигнорировал.
Cобираем сам загрузчик:
- Клонируем стабильную ветку репозитория:
git clone https://gitlab.denx.de/u-boot/u-boot.git -b v2020.10
- Переходим в саму директорию:
cd u-boot
- Готовим конфигурацию сборки:
make mx6ull_14x14_evk_defconfig
. Это работает только если конфигурация есть в самом Das U-Boot, в ином случае вам потребуется найти конфиг производителя и положить его в корень репозитория в файл.config
, или собрать иным рекомендованным производителем образом. - Собираем сам образ загрузчика кросс-компилятором
armhf
:make CROSS_COMPILE=arm-linux-gnueabihf- u-boot.imx
В результате мы получаем файл u-boot.imx
, это готовый образ, который можно записывать на флешку. Записываем на SD-карту, пропустив первые 1024 байта. Почему я выбрал таргет u-boot.imx
? Почему пропустил именно 1024 байта? Так предлагают сделать в документации. Для других плат процесс сборки образа и записи может немного отличаться.
Готово, можно загрузиться. Загрузчик должен сообщить собственную версию, некоторую информацию о плате и попытаться найти образ ядра на разделе. В случае неудачи будет пытаться загрузиться по сети. В целом вывод довольно подробный, можно найти ошибку в случае проблемы.
Вместо заключения
А вы знали, что лоб у дельфина не костистый? Это буквально третий глаз, жировая линза для эхолокации!