Запуск openScaler на nanoPi-M4

openScaler как и его прородитель openEuler предлагают кодовую базу единую для всех видов вычислительных устройств:

  • серверов
  • рабочих станций
  • краевых
  • встраеваемых

Данная статья описывает шаги, необходимые для запуска openScaler на EDGE-устройстве с процессором RK3399.

Спецификация

nanoPi-M4 обладает следующими характеристиками:

  • SoC: Rockchip RK3399
    • CPU: big.LITTLE,Dual-Core Cortex-A72(up to 2.0GHz) + Quad-Core Cortex-A53(up to 1.5GHz)
    • GPU: Mali-T864 GPU,supports OpenGL ES1.1/2.0/3.0/3.1, OpenCL, DX11, and AFBC
    • VPU: 4K VP9 and 4K 10bits H265/H264 60fps decoding, Dual VOP, etc
  • RAM: Dual-Channel 4GB LPDDR3-1866, or Dual-Channel 2GB DDR3-1866
  • Flash: no Onboard eMMC, but has a eMMC socket
  • Ethernet: Native Gigabit Ethernet
  • Wi-Fi/BT: 802.11a/b/g/n/ac, Bluetooth 4.1, Wi-Fi and Bluetooth combo module, 2×2 MIMO, dual antenna interface
  • Video Input: one or two 4-Lane MIPI-CSI, dual ISP, up to 13MPix/s,supports simultaneous input of dual camera data
  • Video output
    • HDMI: HDMI 2.0a, supports 4K@60Hz,HDCP 1.4/2.2
    • one 4-Lane MIPI-DSI
  • Audio Out: 3.5mm Dual channel headphone jack, or HDMI
  • Audio In: one microphone input interface
  • USB 3.0: four USB 3.0 Type-A ports
  • USB Type-C: Supports USB2.0 OTG and Power input
  • microSD Slot x 1
  • 40Pin GPIO Extension ports:
    • 3 X 3V/1.8V I2C, up to 1 x 3V UART, 1 X 3V SPI, 1 x SPDIF_TX, up to 8 x 3V GPIOs
    • 1 x 1.8V 8 channels I2S
  • 24Pin Extension ports:
    • 2 independent native USB 2.0 Host
    • PCIe x2
    • PWM x1, PowerKey
  • Debug: one Debug UART, 4 Pin 2.54mm header, 3V level, 1500000bps
  • PCB: 8 Layer, 85 mm x 56 mm

 

Сборка компонентов прошивки

Подготовка образа с прошивкой для nanoPi-M4 является путешествием в три шага: сборка из mainline проектов kernel и u-boot, установка rpm пакетов из стандартного репозитория дистрибутива.

В нашем сообществе принято решение поставлять как можно больше необходимых компонент для создания своей прошивки из rpm поставляемых в составе дистрибутива openScaler. Для этого была продела работа по выявлению и сборке недостающих пакетов.

Что бы понять, а каких пакетов не хватает в дистрибутиве, необходимо ознакомится с процессом загрузки целевой системы.

При первом погружении в этот вопрос возникнет понимание, что для почти всех одноплатных компьютеров используются SocC изначально созданные для телефонов, планшетов или ТВ-приставок, и все эти устройства в основном работают под управлением Android. А процесс загрузки Android сильно отличается от общепринятого механизма загрузки ОС.

На рисунке выше видна схема загрузки процессора Rockchip. Процесс загрузки может состоять из 7 различных фаз. Из видно, что u-boot, ядро, initrd загружаются из разделов на SD-карте, а не из фалов на ФС, как в случае обычной загрузки в мире PC.

Задача стоит в том чтобы заставить процессор загружаться как PC, то есть по пути:
ROM Boot -> U-Boot -> Kernel
Для этого необходимо пересобрать загрузчик, в частности u-boot.
Для сборки u-boot под архитектуру aarch64 или riscv64 необходимо иметь установленную ОС этой же архитектуры или кросс-компилятор. openScaler имеет нативную поддержку aarch64 и готовится начать поддерживать riscv64.

Сборка u-boot под каждый одноплатный компьютер своя, так как EDGE и Embeded системы не обладают ACPI или EFI режимами, которые есть в мире X86 или на серверном оборудовании aarch64. Так как отсутствуют механизмы автоматического нахождения и конфигурирования периферийных устройств, то разработчикам платы необходимо подготовить DTS (Device Tree Source) файл с описанием того что, где и как подключено. В upstream проектов u-boot и kernel уже включены все необходимые данные и можно их собрать почти под любой одноплатник на рынке.

Проблемы с ARM Trusted Firmware
При попытке в лоб собрать u-boot для, например, nanoPi M4 возникает ошибка:

Ошибка связана с отсутствием файла bl31.elf, данный файл является частью проекта ARM Trusted Firmware и обеспечивает связь между обычным миром, где живет ОС и зоной безопасности (trusted zone). Вот его описание из проекта ARM Trusted Firmware:

Для сборки bl31.elf необходим компилятор arm-none-eabi, данный компилятор отличается от системного тем, что генерирует код для исполнения кода без привязки к ОС и ее методам ABI.

Данного компилятора нет в составе openEuler, и для его появления в openScaler был взять src.rpm из Fedora 37, а так же и все его зависимости, адаптирован для работы в среде openScaler. Таким образом пакетная база openScaler была расширена пакетами:

  • arm-none-eabi-binutils-cs
  • arm-none-eabi-newlib
  • arm-none-eabi-gcc-cs
  • pl
  • cloog
  • gprolog
  • ppl

После добавления arm-none-eabi компилятора появилась возможность собрать все компоненты u-boot на базе toolchain openScaler.

Для тех кто не желает что-либо компилировать есть пакет u-boot-images, который содержит собранные образы u-boot под различные одноплатные компьютеры. Таким образом, есть возможность установить загрузчик не выполняя компиляции.

Сборка ядра для rockship тоже не является обязательной в openScaler, так как подготовлен пакет rockchip-kernel с уже собранным ядром, то же самое ядро, что и kernel.rpm, только с другим конфигурационным файлом, включающим опции для SoC rockchip.

Для чистоты эксперимента соберем все руками.

Готовим ВМ aarch64, установив openScaler 22.03 SP2. Так как часть пакетов была добавлена командой openScaler, то необходимо прописать дополнительный репозиторий с новыми пакетами:

cat /etc/yum.repos.d/extra.repo
[extra]
name=extra packages
baseurl=http://repo.openscaler.ru/openScaler-22.03-LTS-SP2/extra/$basearch
enabled=1
gpgcheck=1
gpgkey=http://repo.openscaler.ru/openScaler-22.03-LTS-SP2/OS/$basearch/RPM-GPG-KEY-openScaler

Теперь можно установить следующие пакеты:

dnf install vim wget gcc make m4 python3-pyelftools git bison flex swig python3-devel openssl-devel tar arm-none-eabi-gcc-cs

Создаем рабочий каталог:

mkdir nanoPi-M4
cd nanoPi-M4/

Теперь необходимо скачать u-boot и ARM Trusted Firmware:

git clone https://github.com/u-boot/u-boot
git clone https://github.com/ARM-software/arm-trusted-firmware.git

Первым делом собирается ATF:

cd arm-trusted-firmware

И собираем бинарник для rk3399

make PLAT=rk3399 bl31

Теперь время собрать u-boot, для этого переходим в каталог u-boot и переключаем ветку на стабильную:

cd ../u-boot/
git branch -a
git checkout u-boot-2023.07.y

Использовать не стабильные ветки крайне не рекомендуется, так как возможно различные ошибки, например не работает mmc или SD карточка.

Перед началом сборки необходимо поместить собранный бинарник из ATF:

cp ../arm-trusted-firmware/build/rk3399/release/bl31/bl31.elf atf-bl31

Сборка производится в два шага:

  • на первом шаге задается конфигурационный файл
  • на втором сама сборка

make nanopi-m4-rk3399_defconfig
make -j5

При успешной сборке появится файл u-boot-rockchip.bin, который и есть искомый загрузчик.
Теперь необходимо подготовить загрузочный образ SD-карты. Создаем каталог для работы с образом:

cd /root/nanoPi-M4
mkdir image
cd image

Создаем файл размером 2GB который и будет использован в качестве образа.

truncate -s 2G sd.img

Для работы с файлом как с блочным устройством используем losetup:

losetup /dev/loop0 sd.img

Создаем разметку диска, первый раздел должен начинаться со смещением 20480

fdisk /dev/loop0

Перечитываем таблицу разделов и создаем ФС:

partprobe /dev/loop0
mkfs.ext4 /dev/loop0p1

Для установки загрузчика используем dd

cp ../u-boot/u-boot-rockchip.bin .
dd if=u-boot-rockchip.bin of=/dev/loop0 seek=64

Смещение можно найти в документации к плате.

Видно что было записано 9 MB данных, и для этого первый раздел был создан со смещением в 10 MB.

После установки загрузчика настало время подготовки корневой ФС. Создаем каталог и монтируем туда созданный раздел:

mkdir mnt
mount /dev/loop0p1 mnt/

Инициализируем новую БД rpm:

rpm –root /root/nanoPi-M4/image/mnt/ –initdb

Перед установкой rpm пакетов рекомендуется отключить установку слабых зависимостей, например к ним относится grub, который не нужен в данной инсталяции. Для этого необходимо добавить строку в файл /etc/yum.conf:

install_weak_deps=False

Теперь необходимо установить минимальный набор пакетов:

dnf install –installroot /root/nanoPi-M4/image/mnt dnf yum alsa-utils haveged wpa_supplicant vim net-tools iproute iputils NetworkManager openssh-server openssh-clients passwd hostname bluez pulseaudio-module-bluetooth parted linux-firmware gdisk ntp bc systemd-timesyncd openScaler-repos

Как видно, в этом списке отсутствует ядро, оно будет установлено в chroot окружении, чтобы не повлиять на установленную систему. Так как были внесены настройки в yum, то их необходимо перенести в вновь создаваемую ФС, дл этого копируем файлы /etc/yum.conf и /etc/yum.repos.d/extra.repo в mnt:

cp /etc/yum.conf mnt/etc/
cp /etc/yum.repos.d/extra.repo mnt/etc/yum.repos.d/

Временно отключим SElinux, так как он помешает задать пароль root в chroot окружении, и узнаем UUID нашей ФС:

setenforce 0
blkid

Наша ФС имеет UUID=251c6b52-70b3-4707-84b2-9f78325f6c84

Переходим во вновь создаваемую систему и задаем пароль root:

[root@soc image]# chroot mnt /bin/bash
bash-5.1# passwd

Теперь необходимо обеспечить новую систему интернетом, чтобы можно было доустановить пакеты:

echo ‘nameserver 77.88.8.8’ > /etc/resolv.conf

Установим rockchip-kernel, drakut и uboot-tools:

dnf install rockchip-kernel dracut uboot-tools

Подготовим initrd образ и сделаем его доступным для u-boot:

dracut –kver 5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64
mkimage -A arm64 -T ramdisk -C none -n uInitrd -d /boot/initramfs-5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64.img /boot/uInitrd-5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64
cd /boot
ln -s uInitrd-5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64 uInitrd

Теперь необходимо написать загрузочный скрипт, который будет прочитан u-boot и загрузит указанные образы ядра и initrd:

cat /boot/boot.cmd
###############################################
# DO NOT EDIT THIS FILE boot.scr
# Please edit boot.cmd
# And run: mkimage -C none -A arm64 -T script -d /boot/boot.cmd /boot/boot.scr
##############################################
echo “Boot script loaded from ${devtype}”
setenv bootargs “root=/dev/mmcblk1p1 ro rootfstype=ext4 earlyprintk rootwait console=ttyS2,1500000 console=tty1 consoleblank=0”
load ${devtype} ${devnum} ${kernel_addr_r} ${prefix}Image
load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}uInitrd
load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}/dtb/rk3399-nanopi-m4.dtb
fdt addr ${fdt_addr_r}
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}

И добавим бинарные заголовки для u-boot:

mkimage -C none -A arm64 -T script -d /boot/boot.cmd /boot/boot.scr

Итоговая картина каталогу /boot будет выглядеть так:

Осталось создать файл /etc/fstab

Его содержимое основывается на знании UUID нашей ФС

cat /etc/fstab

UUID=251c6b52-70b3-4707-84b2-9f78325f6c84   /  etx4 defaults  1 1

Подготовка образа завершена, теперь попробуем со всем этим взлететь.

Для этого отмонтируем образ, отключим от loop0 и запишем на SD-карту:

setenforce 1
mount mnt
losetup -D
dd if=sd.img of=/dev/sdb status=progress

Вставляем получившуюся SD-карту в устройство, подключаем UART, включаем minicom, подаем питание и молимся

u-boot был успешно загружен.

Ждем загрузки ядра.

Успешная попытка загрузить ядро.

Успешный вход в систему и дальше можно настраивать как обычную ОС.

Консоль – это хорошо, но графика лучше. Поставим пакеты с каким-либо окружением, а заодно проверим аппаратное ускорение.

Установить GNOME можно командой:

dnf groupinstall gnome

После установки можно подключить монитор/телевизор и использовать все прелести графического режима.

GNOME успешно работает, но что там с аппаратным ускорением? SoC имеет на борту GPU Mali T860, посмотрим задействован ли он:

egrep -i ‘mali|rockchip’ /var/log/Xorg.0.log
[ 14.647] Current Operating System: Linux openScaler-nanoPi-M4 5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64 #1 SMP PREEMPT Mon Oct 30 12:18:44 UTC 2023 aarch64

Видно, что аппаратного ускорения нет.

Но в проект mesa были добавлены свободные реализации драйверов для семейства GPU Mali: panfrost и lima. Наша задача как сообщества – сделать доступными данные драйвера. Для этого был создан fork пакета mesa с внесением в него изменений, направленных на добавление драйверов GPU Mali.

Установить драйвера можно командой:
dnf install mesa-mali-dri-drivers

Для проверки можно включить ролик на youtube и посмотреть на разницу в картинке. Без ускорения ролик похож на слайд-шоу, а с ним уже вполне плавная картинка. Так же можно проверить состояние загруженного драйвера:

egrep -i 'mali|rockchip' /var/log/Xorg.0.log
[ 14.562] Current Operating System: Linux openScaler-nanoPi-M4 5.10.0-153.12.0.93.os2203sp2.rockchip.aarch64 #1 SMP PREEMPT Mon Oct 30 12:18:44 UTC 2023 aarch64
[ 18.840] (II) modeset(0): glamor X acceleration enabled on Mali-T860 (Panfrost)
[ 19.114] (II) modeset(0): [DRI2] DRI driver: rockchip
[ 19.115] (II) modeset(0): [DRI2] VDPAU driver: rockchip
[ 19.146] (II) AIGLX: Loaded and initialized rockchip

Видно, что драйвер успешно загрузился.