Как стать автором
Обновить

Сборка прошивки из исходников для Orange PI i96(Orange PI 2g-iot)

Уровень сложностиПростой
Время на прочтение18 мин
Количество просмотров9.5K

Здраствуйте меня зовут Дмитрий. Как-то я купил OrangePI i96, но к сожалению производитель давно забыл об этой плате, прошивки для неё построены на ядре 3.10.62(актуальная версия на момент написания статьи 6.5.1). Поэтому я решил собрать собственную прошивку на актуальной версии ядра. Сборка будет проходить полностью из исходников.

Для начала хочу отметить что для сборки прошивки я использовал WSL (Windows Subsystem for Linux) второй версии, а в качестве гостевой системы была установлена Ubuntu, в принципе все собирается прекрасно но были некоторые проблемы, о которых будет сказано позже. Также хочу отметить что несмотря на то что во время работы над проектом, мне пришлось переустановить Windows я не потерял свои файлы. Если по каким-то причинам WSL потеряет образ, то систему можно восстановить из ext4.vhdx файла при помощи команды:

wsl --import-in-place <new_distro_name> <path_to_ext4.vhdx>

Главное не потеряйте ext4.vhdx файл и все будет в порядке.

Компиляция uboot

Сначала создадим папку в которой будем проводить сборку:

mkdir OrangePI
cd OrangePI

Поскольку Uboot идущий по умолчанию все прекрасно запускает, то менять его нет никакого смысла. Поэтому будем делать все по инструкции от авторов OrangePI i96:

wget https://github.com/orangepi-xunlong/toolchain/archive/refs/heads/arm-linux-gnueabi-1.13.1.zip
unzip arm-linux-gnueabi-1.13.1.zip

Хочу заметить, что этот тулчайн мы будем использовать только для компиляции uboot.

wget https://github.com/orangepi-xunlong/OrangePiRDA_uboot/archive/refs/heads/master.zip
unzip master.zip
cd OrangePiRDA_uboot-master

Создаем конфиг и компилируем. Путь к тулчайну у вас может отличатся. Цифра после j равна количеству потоков вашего процессора.

make CROSS_COMPILE=/home/dmitry/OrangePI/toolchain-arm-linux-gnueabi-1.13.1/gcc-linaro-1.13.1-2012.02-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi- rda8810_config
make CROSS_COMPILE=/home/dmitry/OrangePI/toolchain-arm-linux-gnueabi-1.13.1/gcc-linaro-1.13.1-2012.02-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi- -j16

У меня во время компиляции возникла ошибка (error while loading shared libraries: libz.so.1). Я преодолел её командой:

sudo apt-get install lib32z1

После компиляции должен появится файл u-boot.rda следует его запомнить он понадобится нам в будущем.

Создание корневой директории

Cоздадим директорию rootfs, это будет образ файловой системы нашего устройства. Для корректной работы устройства в этой директории должны находится определенные папки, в которые в последствии будут примонтированы необходимые для работы системные каталоги.

mkdir rootfs
cd rootfs
mkdir -p dev root sys proc run tmp var/run var/log

Компиляция ядра

Сначала нужно определится с тулчайном. Чип RDA8810PL использует набор команд ARMv7 с аппаратной поддержкой команд с плавающей запятой. Я использовал gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf (hf значит аппаратная поддержка команд с плавающей запятой)

wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

Потом надо скачать исходники ядра с сайта kernel.org. На момент создания статьи актуальная версия 6.5.1, с ней и будем работать.

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.5.1.tar.xz
tar -xvf linux-6.5.1.tar.xz
cd linux-6.5.1

Необходимо отметить что Opange PI i96 построена на основе чипа RDA8810PL, для работы которого необходимы драйверы которых нету в стандартном ядре. И хотя у нас есть исходники старого ядра от разработчиков . Просто взять файлы драйверов из старого ядра и положить их в новое нельзя, потому что с тех пор изменилась архитектура ядра. Современное ядро использует архитектуру которая называется Device Tree.

Раньше само ядро инициализировало устройства. А поскольку у каждого одноплатника свой набор устройств, то ядро у каждого было свое. Теперь список устройств задается в файле Device Tree(который имеет расширение .dts , .dtb после компиляции), а ядро уже считывает устройства из этого файла. Благодаря этому ядро у всех одноплатников одно и то же отличается только файл Device Tree.

К счастью я подправил файлы драйверов чтобы они могли работать с новым ядром. Мой репозиторий. Вам нужно распаковать его в паку с исходниками ядра. Хочу заметить что я сначала положил оригинальные файлы а потом уже модифицированные, так что можно посмотреть что мне пришлось подправить.

Если вы вдруг на компилируете что-то не то всегда можно ввести команду:

make distclean

И она вернет все к первоначальному виду.

Приступим к компиляции. Задаем настройки по умолчанию. Путь к тулчайну у вас может быть другой.

make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- defconfig
make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- menuconfig

Заходим в меню и отмечаем опции:

  • System type-->RDA Micro SoCs

  • Device drivers-->Character devices-->Enable TTY-->Serial Drivers-->RDA Micro serial port support-->Console on RDA Micr serial port

  • Device drivers-->GPIO Support-->Memory Mapped GPIO drivers-->RDA Micro GPIO controller support

  • Device drivers-->RDA support

RDA support это не опция а подменю. В него нужно войти и выбрать все опции в нем. После этого выходим и сохраняемся.

Когда вы попытаетесь включить опцию "RdaMicro IEEE802.11 emdedded FullMac WLAN driver". То система скажет вам что она зависит от другой опции которая включена как модуль и поэтому эта опция тоже будет включена как модуль. К сожалению если включить эту опцию как модуль то не произойдет инициализации сети при загрузке (я проверял). Поэтому надо найти опцию:

Networking support-->Wireless-->cfg80211-wireless configuration API

И изменить её тип с m на просто включено. После этого удастся нормально включить опцию "RdaMicro IEEE802.11 emdedded FullMac WLAN driver".

Компиляция j равно количеству потоков вашего процессора.

make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j16

Также можно компилировать ядро по частям:

make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j16 zImage
make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j16 dtbs
make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j16 modules

Если вы используете WSL и копировали файлы драйверов через проводник Windows то все папки будут иметь владельца root и вы получите ошибку permission denay. Чтобы это избежать нужно ввести команду:

sudo chown -R "имя вашего акаунта":"имя вашего акаунта" drivers/rda 

После компиляции. Устанавливаем модули ядра в нашу папку rootfs.

make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=../rootfs

Также создаем папку sysroot в которой будут хранится заголовки библиотек и устанавливаем их.

mkdir -p ../sysroot/usr
make ARCH=arm CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- INSTALL_HDR_PATH=../sysroot/usr headers_install

Ядро мы объединяем с файлом Device tree командой cat. Тут может возникнуть вопрос а зачем это нужно ведь мы положим файл Device tree в образ. Здесь я сам не понимаю до конца (возможно это вызвано тем что u-boot у нас старой версии и он ни знает ничего о Device tree), но при загрузке будет использоваться тот файл который мы присоединим к ядру.

cat /home/dmitry/OrangePI/linux-6.5.1/arch/arm/boot/zImage /home/dmitry/OrangePI/linux-6.5.1/arch/arm/boot/dts/unisoc/rda8810pl-orangepi-i96.dtb > zImage+dtb

Компиляция glibc

glibc это стандартная библиотека языка C. Поскольку все программы в Linux написаны на C то без этой библиотеки ничего не запустится.

Для кроcс-компиляции необходимо задать несколько переменных среды. Эти переменные будут сохранятся до перезагрузки консоли.

export PATH=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export CHOST=arm-linux-gnueabihf
export CC=arm-linux-gnueabihf-gcc
export AR=arm-linux-gnueabihf-ar
export CXX=arm-linux-gnueabihf-g++

Ключевое слово export нужно для экспортирования этих переменных в дочерние процессы. Если установочный скрипт будет производить настройки не в основном а в дочернем процессе, то без export произойдет ошибка.

Итак приступим:

wget https://ftp.gnu.org/gnu/glibc/glibc-2.38.tar.gz
tar -xzf glibc-2.38.tar.gz
cd glibc-2.38
mkdir build
cd build
../configure --prefix=/usr --host=arm-linux-gnueabihf CFLAGS="--sysroot=/home/dmitry/OrangePI/sysroot -O2" CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++
make CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++ -j16
make DESTDIR=`pwd`/glibcBuild install

Я на всякий случай передаю переменные CC AR CXX, хотя этого можно и не делать.

Также во время компиляции возникали ошибки.

fatal error: gmp.h: No such file or directory

решение:

sudo apt-get install libgmp3-dev libmpfr-dev
fatal error: mpc.h: No such file or directory

решение:

sudo apt-get install libmpc-dev

Теперь можно зайти в папку glibcBuild и рассортировать полученные файлы.

В папку rootfs:

etc
lib
sbin
usr/bin
usr/lib/*.so
usr/libexec
usr/sbin
usr/share

Здесь и далее в папку rootfs мы будем класть только файлы *.so это динамические библиотеки файлы с расширениями *.o *.a нас не интересуют.

В папку sysroot:

lib
usr/include
usr/lib

В sysroot кладем все подряд эту папку мы будем использовать для компиляции программ.

Компиляции busybox

Busybox это легковесный набор утилит для встраиваемой электроники. Самое то для одноплатника.

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xvjf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
make CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- defconfig
make CROSS_COMPILE=/home/dmitry/OrangePI/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j16

Busybox ставится в папку _install. Все содержимое этой папки надо перенести в rootfs.

Компиляция библиотеки libxcrypt

wget https://github.com/besser82/libxcrypt/releases/download/v4.4.36/libxcrypt-4.4.36.tar.xz
tar -xvf libxcrypt-4.4.36.tar.xz
cd libxcrypt-4.4.36
mkdir build
./configure --prefix=/home/dmitry/OrangePI/libxcrypt-4.4.36/build --host=arm-linux-gnueabihf
make CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++ -j16
make install

Содержимое папки build/lib/*.so в rootfs всё остальное в sysroot.

Компиляция DropBear

Поскольку Orange PI i96 не имеет ни каких способов вывода изображения, то единственный способ взаимодействия с ним это через терминал. Поэтому будем ставить ssh сервер DropBear.

wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2022.83.tar.bz2
tar -xjf dropbear-2022.83.tar.bz2
cd dropbear-2022.83
./configure --prefix=/home/dmitry/OrangePI/rootfs --disable-zlib --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld
make install 

Для корректной работы DropBear необходимо сгенерировать ключи.

cd ../rootfs
mkdir etc/dropbear
dropbearkey -t dss -f etc/dropbear/dropbear_dss_host_key
dropbearkey -t rsa -f etc/dropbear/dropbear_rsa_host_key

Компиляция библиотеки libnl-3

wget http://www.infradead.org/~tgr/libnl/files/libnl-3.2.25.tar.gz
tar -xzf libnl-3.2.25.tar.gz
cd libnl-3.2.25
mkdir build
./configure --host=arm-linux-gnueabihf --prefix=/home/dmitry/OrangePI/libnl-3.2.25/build
make -j16 CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++ 
make install
cd include
make install

Из папки build копируем в rootfs все кроме include. А в sysroot все папки.

Компиляция iw

Чтобы воспользоваться терминалом нам понадобится сеть, iw это утилита для настройки wi-fi соединения.

Перед тем как мы начнем нужно задать переменную PKG_CONFIG_PATH и установить пакет pkg-config если его нет.

export PKG_CONFIG_PATH=/home/dmitry/OrangePI/sysroot/lib/pkgconfig
sudo apt-get install -y pkg-config

wget https://www.kernel.org/pub/software/network/iw/iw-3.15.tar.gz
tar -xzf iw-3.15.tar.gz
cd iw-3.15
make -j16 CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++
cp iw ../rootfs/sbin/

Компиляция библиотеки OpenSSL

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
tar -xzf openssl-1.1.1h.tar.gz
cd openssl-1.1.1h
mkdir build
./Configure linux-generic32 --prefix=/home/dmitry/OrangePI/openssl-1.1.1h/build
make -j16 CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++
make install

Как всегда в rootfs папка lib\libcrypto.so и lib\libssl.so. В sysroot все остальное.

Компиляция wpa_supplicant

При помощи iw мы можем устанавливать соединение только с точками доступа на которых не используется шифрование. Чтобы установить соединение с шифрованием нам понадобится пакет wpa_supplicant.

wget https://w1.fi/releases/wpa_supplicant-2.10.tar.gz
tar -xzf wpa_supplicant-2.10.tar.gz
cd wpa_supplicant-2.10/wpa_supplicant
cp defconfig .config

Мне пришлось внести некоторые изменения в файл .config. Во первых я раскоментировал строки с путями к OpenSSL и подправил эти пути:

CFLAGS += -I/home/dmitry/OrangePI/sysroot/include
CFLAGS += -I/home/dmitry/OrangePI/sysroot/include/libnl3
LIBS += -L/home/dmitry/OrangePI/sysroot/lib

После закомментировал следующие строки:

#CONFIG_DRIVER_MACSEC_LINUX=y
#CONFIG_MACSEC=y
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
#CONFIG_CTRL_IFACE_DBUS_NEW=y

Компиляция:

make CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar CXX=arm-linux-gnueabihf-g++ -j16
make install DESTDIR=/home/dmitry/OrangePI/rootfs

Создание конфигурационных файловой

При создании конфигурационных файлов самое главное не использовать блокнот Windows, потому что Windows и Linux используют разные символы окончания строки. Если не хочется использовать консоль то можно например использовать Notepad++, у него в меню Edit->EOL Conversion можно выбрать Unix подобное окончание строки.

Создаем файл с пользователем root у которого домашняя папка /. То есть при входе мы будем видеть корневой каталог.

cd rootfs/etc
cat >> passwd
root:x:0:0:root:/:/bin/sh
^D

Символ ^D означает что надо нажать сочетание клавиш CTRL+D, чтобы закончить редактирование.

В файле shadow содержатся пароли в зашифрованном виде. Здесь зашифрован пароль root.

cat >> shadow
root:LlNBpbQmj8p7g:1:0:99999:7:::
^D

Также создадим файл group. Группа wheel нужна для wpa_supplicant.

cat >> group
root:x:0:root
wheel:x:10:root
^D

В файле wpa_supplicant.conf хранится информация о том к какой сети мы будем подключатся. Также хранится пароль в виде шестнадцатеричного числа. Чтобы получить это число нужно установить wpa_supplicant на компьютер и воспользоваться утилитой wpa_passphrase:

wpa_passphrase i96 123456789

Здесь имя сети i96 пароль 123456789

cat >> wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
network={
       ssid="i96"
        psk=c96a7f97cfee8b9f9ce9aae88c4cc6c5f1962f6dca48ea7444d80a70a300b5b1
}
^D

Файл resolv.conf содержит адреса DNS серверов:

cat >> resolv.conf 
nameserver 1.1.1.1
nameserver 1.0.0.1
^D

Добавим ещё несколько файлов для конфигурации сети.

cat >> hosts
127.0.0.1	localhost
^D
cat >> hostname
OrangePI
^D
cat >> host.conf
order hosts, bind
multi on
^D
cat >> networks
loopback	127.0.0.0
localnet	127.0.0.0
^D

Дальше пойдут файлы которые слишком большие для ввода c помощью cat. Ссылка на эти файлы будет приведена в конце статьи.

Файл profile содержит начальное значение переменной PATH. Это полезно, например wap_suplicant устанавливается не в /usr/sbin а в /usr/local/sbin. Также я добавил пути к каталогу opt.

Скрипты инициализации системы

Файл inittab отвечает за такие вещи как загрузка, выключение а также нажатие AltCtrlDel. Справка.

cat >> inittab
::sysinit:/etc/rc.d/rc.S
::respawn:-/bin/sh -l
::ctrlaltdel:/sbin/reboot 
::shutdown:/etc/rc.d/rc.0
^D

Создадим папку для скриптов:

mkdir rc.d
cd rc.d

Скрипт rc.0 размонтировывает диски при выключении.

cat >> rc.0
#!/bin/sh
sync
/sbin/umount -a -r > /dev/null 2>&1
^D

Дальше файл rc.S который выполняется при загрузке:

Hidden text
#!/bin/sh
# Первым делом смонтируем procfs. Без нее ничего не полетит
/bin/mount -v proc /proc -t proc 1> /dev/null

/bin/mkdir /dev/pts
/bin/mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts 

PATH=/bin:/usr/bin:/sbin:/usr/sbin
# Мы не будем насиловать карточку временным файлами, будем держать их в пямяти
/bin/mount -t tmpfs none -o size=150M,nodev,nosuid,noatime /tmp
/bin/mount -t tmpfs none -o size=10M,nodev,nosuid,noatime /var/log
/bin/mount -t tmpfs none -o size=5M,nodev,nosuid,noatime /var/run
/bin/mount -t tmpfs none -o size=5M,nodev,nosuid,noatime /run

# Удалим (если он был) файл о смонтированных ранее ФС и создадим пустой
/bin/rm -f /etc/mtab{,~,.tmp} && /bin/touch /etc/mtab

# Смонтируем sysfs и запустим ldconfig для обновления информации о библиотеках
/bin/mount -v sysfs /sys -t sysfs 1> /dev/null
if [ -x /sbin/ldconfig ]; then
  /sbin/ldconfig 1> /dev/null
fi

# Запустим системный логгер и логгер ядра
/sbin/syslogd 2> /dev/null
sleep 1
/sbin/klogd -c 3 1> /dev/null

modprobe loop 1> /dev/null 2> /dev/null

if [ -x /etc/rc.d/rc.modules ]; then
. /etc/rc.d/rc.modules
fi

if [ -x /etc/rc.d/rc.network ]; then
. /etc/rc.d/rc.network start
fi

# Очистим экран
/bin/setterm -blank 0 2>/dev/null

# Создадим файл приглашений
echo > /etc/motd
echo "`/bin/uname -a | /usr/bin/cut -d\  -f1,3`." >> /etc/motd
echo >> /etc/motd

# Выдадим прилашение для входа в консоль
echo "Press <Enter>..."

Скрипт инициализации сети rc.network:

Hidden text
#!/bin/sh

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin

net_start() {
    
    ifconfig wlan0 up
	iw dev wlan0 scan > /dev/null 
	wpa_supplicant -B -D nl80211 -i wlan0 -c /etc/wpa_supplicant.conf
	sleep 2
	ifconfig lo up 127.0.0.1
    route add -net 127.0.0.0 netmask 255.255.255.0 lo
	ifconfig wlan0 192.168.1.252 netmask 255.255.255.0
	route add default gw 192.168.1.1 wlan0
	dropbear
	route 
}

net_stop() {
    if [ -f /var/run/udhcpc.pid ]; then
      kill -9 `cat /var/run/udhcpc.pid`
      rm /var/run/udhcpc.pid
    fi
    ip set link wlan0 down
}

case "$1" in
'start')
    net_start
    ;;
'stop')
    net_stop
    ;;
'restart')
    net_stop
    net_start
    ;;
*)
    echo "Usage $0 start|stop|restart"
esac

Скрипт сканирует точки доступа и подключается к точки доступа параметры которой записаны в файле wpa_supplicant.conf. После этого назначается IP адрес. Если вы хотите подключится к незащищённой точки доступа (хотя я бы не советовал создавать такие точки доступа) то вместо строчки wap_suplicant нужно ввести строку iw dev wlan0 connect "имя незащищённой точки доступа". А если вы просто хотите узнать статус соединения можно использовать команду iw dev wlan0 link. Команда ifconfig -a выводит список сетевых интерфейсов

Здесь надо пояснить. У меня скрипт устроен так что IP адрес всегда выбирается 192.168.1.252. А IP адрес роутера с которым связывается одноплатник равен 192.168.1.1. Но если вы хотите чтобы при инициализации система сама находила адрес роутера, а также присваивала себе незанятый IP. Нужно строчки:

ifconfig wlan0 192.168.1.252 netmask 255.255.255.0
route add default gw 192.168.1.1 wlan0

Заменить на:

udhcpc -i wlan0 -p /var/run/udhcpc.pid -s /etc/scripts/udhcp.sh 

И добавить в папку /etc/scripts скрипт udhcp.sh

Hidden text
#!/bin/sh

ACTION="$1"

case "${ACTION}" in
"renew"|"bound")
    /sbin/ifconfig ${interface} ${ip} netmask ${subnet}
    /sbin/route del default > /dev/null 2>&1
    for i in "${router}"; do
        /sbin/route add default gw $i dev ${interface}
    done
    ;;
esac

Не забываем разрешить выполнение всех скриптов.

chmod u+x rc.0
chmod u+x rc.S
chmod u+x rc.network

Создание файла uInitrd

Чтобы загрузка системы считалась успешной. Ядро должно выполнить две вещи. Это смонтировать корневую директорию и выполнить скрипт инициализации. Но чтобы смонтировать корневую директорию на раздел SD карты например нужно загрузить драйверы SD карты, но чтобы их загрузить нужно уже иметь корневую директорию из которой мы подгрузим драйверы. Отсюда возникает дилемма чтобы смонтировать корневую директорию нам нужно уже иметь корневую директорию. Чтобы разорвать этот порочный круг создается образ uInitrd, в котором содержатся драйверы для дальнейшей работы. Этот образ разворачивается в оперативной памяти.

Кстати если в образ uInitrd положить загрузочный скрипт например такой файл init

Hidden text
#! /bin/sh
mount -t sysfs sysfs /sys
mount -t proc proc /proc
mount -t devtmpfs udev /dev
mkdir /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts 
/sbin/syslogd
sleep 1
/sbin/klogd -c 3
. /etc/rc.d/rc.network start
dropbear
sysctl -w kernel.printk="2 4 1 7"
/bin/sh
poweroff -f

То система выполнит его и на этом остановится и мы получим Linux с корневой системой смонтированной в оперативной памяти, любые изменения в которой после перезагрузки исчезают.

Итак приступим к созданию uInitrd. Сначала мы архивируем папку rootfs и потом сжимаем её утилитой gzip.

cd rootfs
find . | cpio -H newc -ov --owner root:root > ../initramfs.cpio
cd ..
gzip initramfs.cpio

Утилита mkimage добавляет заголовок необходимый для u-boot.

mkimage -A arm -T ramdisk -n uInitrd -d initramfs.cpio.gz uInitrd

Создание файла boot.scr

boot.scr это сценарий загрузки системы. Этот сценарий предназначается для u-boot.

Создаем файл boot.cmd

setenv bootargs "earlycon initcall_debug console=ttyRDA2,921600n8 root="/dev/mmcblk0p2" rootfstype="ext4" rootwait rw"
ext2load mmc 0:1 ${kernel_addr} zImage+dtb
ext2load mmc 0:1 ${script_addr} rda8810pl-orangepi-i96.dtb
ext2load mmc 0:1 ${initrd_addr} uInitrd
ext2load mmc 0:1 ${modem_addr} modem.bin
mdcom_loadm ${modem_addr}
mdcom_check 1
bootz ${kernel_addr} ${initrd_addr}:${filesize} ${script_addr}

И cкомпилируем его утилитой mkimage:

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

Файл modem.bin необходим, без него ядро не стартует. Кроме того он нужен если вы хотите передать файл по UART в u-boot. Например когда я редактировал файлы драйверов мне постоянно приходилось загружать новые ядра но перезаписывать их на SD карту очень долго. Поэтому я создал образ без ядра системы. В результате чего u-boot загружался но загрузить ядро он не мог и загрузка останавливалась. После этого я вводил команду loady в консоль u-boot это переводило u-boot в режим получения файла (как раз эта команда не работает без modem.bin) и в TerTetm меню File->Transfert->YMODEM->send после пересылки ядра загружал его командой:

0x82000000 ${initrd_addr}:${filesize} ${script_addr}

Ссылка на modem.bin в конце статьи.

Сборка образа

Ну собственно все приготовления закончились дальше будет быстрее.

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

dd if=/dev/zero bs=1M count=2 of="NewImg.img"

Копируем u-boot по смещению 256. 256 это не 256 байт а 256 блоков (dd это утилита блочного копирования) по умолчанию один блок равен 512 байт. Почему именно это смещение? Потому что оно зашито в более "глубокой" прошивки. Ну то есть наша прошивка, а есть ещё одна прошивка которая зашита прямо в чип RDA, она исполняется сразу после включения и передает управление по смещению 256*512. Там находится u-boot который уже решает откуда брать ядро и прочие файлы необходимые для загрузки операционной системы.

dd if=OrangePiRDA_uboot-master/u-boot.rda conv=notrunc seek=256 of="NewImg.img"

Создадим раздел для загрузки. И раздел для корневой директории здесь я установил размер 300Мб но по желанию можно увеличить:

dd if=/dev/zero bs=1M count=50 of="NewImg.img"1
dd if=/dev/zero bs=1M count=300 of="NewImg.img"2

Создаем файловые системы на этих разделах.

mkfs.ext2 -L BOOT "NewImg.img"1
mkfs.ext4 -O ^metadata_csum -F -b 4096 -E stride=2,stripe-width=1024 -L rootfs "NewImg.img"2

Монтируем загрузочную директорию и копируем в неё ядро системы device tree файл и сценарий загрузки:

mkdir -p /tmp/tmp
sudo mount "NewImg.img"1 /tmp/tmp
sudo cp -rf linux-6.5.1/zImage+dtb /tmp/tmp
sudo cp -rf linux-6.5.1/arch/arm/boot/dts/unisoc/rda8810pl-orangepi-i96.dtb /tmp/tmp
sudo cp -rf uInitrd /tmp/tmp
sudo cp -rf boot.cmd /tmp/tmp
sudo cp -rf boot.scr /tmp/tmp
sync
sudo umount /tmp/tmp

Монтируем вторую директорию и копируем в неё содержимое папки rootfs:

sudo mount "NewImg.img"2 /tmp/tmp
sudo cp -rT rootfs /tmp/tmp
sync
sudo umount /tmp/tmp

Объединяем все части в одну:

dd if="NewImg.img"1 conv=notrunc oflag=append bs=1M seek=2 of="NewImg.img"
dd if="NewImg.img"2 conv=notrunc oflag=append bs=1M seek=52 of="NewImg.img"

Создание таблицы разделов

Пока что образ нерабочий поскольку нет таблицы разделов. Таблица разделов создается при помощи программы fdisk.

fdisk "NewImg.img"
o
n
p
1
4096
+50M

n
p
2
106496

w

После начала редактирования мы вводим команду "o" чтобы создать пустую таблицу разделов MBR. Затем командой "n" создаем новый раздел. Выбираем тип номер и первый сектор. Дело в том что размер сектора равен 512 байт, то есть один килобайт равен двум секторам. Размер заголовка 2 мегабайта то есть 2048 килобайт или 4096 сектора. Размер раздела можно указать в мегабайтах. Тоже самое делаем со вторым разделом с той лишь разницей что программа автоматически предложит последний сектор и останется только с ней согласится. Выход командой w.

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

sudo parted NewImg.img unit s print

Можно также монтировать эти разделы только смещение нужно указывать не в секторах а в байтах (2097152 = 4096 * 512) и (54525952 = 106496 * 512).

sudo mount -o loop,offset=2097152 NewImg.img /tmp/tmp 
sudo mount -o loop,offset=54525952 NewImg.img /tmp/tmp 

Всё осталось только записать образ на SD карту например при помощи Win32DiskImager.

Запуск

Как я уже говорил нужно на роутере настроить точку доступа с именем i96 и паролем 123456789, у роутера IP должен быть 192.168.1.1. Параметры сети настраиваются в файле /etc/wpa_supplicant.conf а IP в файле /etc/rc.d/rc.network. После включения нужно подождать некоторое время i96 не самый быстрый одноплатник. Вход root root.

Конечно busybox предоставляет широкий выбор приложений но их не всегда хватает. Откуда же можно брать приложения? Ну во первых их можно компилировать из исходников, но делать это очень долго, поэтому в сети существуют проекты которые предоставляют уже скомпилированные пакеты это Entware и Optware. Вот страница форума здесь нужно выбрать набор команд нашего чипа. Давайте для примера установим Entware.

Заходим в папку root и скачиваем установочный скрипт.

cd /root
wget http://bin.entware.net/armv7sf-k3.2/installer/generic.sh
chmod u+x generic.sh
./generic.sh

После этого мы получим целую корневую директорию в папке opt. Также у нас появится менеджер пакетов opkg. Давайте например установим sftp сервер он позволит перебрасывать файлы на одноплатник при помощи приложения WinSCP:

opkg update
opkg install openssh-sftp-server

Здесь есть маленький момент. Дело в том что DropBear мы компилировали из исходников и он расположен в корневой директории поэтому он ищет sftp сервер в директории /usr/libexec/sftp-server. А sftp сервер устанавливается в директорию opt. Чтобы они смогли найти друг друга надо создать символьную ссылку командой.

ln -s /opt/lib/sftp-server /usr/libexec/sftp-server

После перезагрузки sftp сервер начнет работать. Также можно установить текстовый редактор nano. Midnight commander я пытался установить, но у меня не работали стрелки и функциональные клавиши, поэтому я не смог даже из него выйти. На этом все.

Про камеру.

Не знаю помогут-ли кому-то мои изыскания но отрицательный результат тоже результат. Итак я пытался заставить работать камеру через интерфейс SCI. Но после нескольких недель мучения я понял несколько вещей.

1) Напряжение питания ядра камеры 2,9В (пин 10) а должно быть 1,8В. И изменить это никак не получается, я перепробовал все доступные регуляторы напряжения, которые есть в i96 ноль реакции.

2) Кроме SCI интерфейса камера так-же подключается к i2c интерфейсу. По этому интерфейсу идет управление камерой. I2c интерфейс выведен на пины 3 и 5 это линии SCK и SDA. На линии SCK всегда +3 вольта, так и должно быть, а вот на линии SDA 0. И этого быть не должно, интерфейс i2c предполагает что линии SCK и SDA должны быть подтянуты к шине питания, 0 на них может появляется лишь во время обращения к устройству и то только на короткое время.

Из всего этого можно заключить что интерфейс SCI на i96 нерабочий. Ну либо у меня бракованная плата, хотя Wi-Fi работает а чип Wi-Fi также подключается к RDA через i2c.

У меня даже возникло сомнение, а кто-либо подключал когда-нибудь к i96 камеру через SCI интерфейс?

Ссылки:

Файлы modem.bin, profile, protocols, services, termcap. (Если ссылка не действует, то файлы можно достать из готового образа)

Мой репозиторий с файлами ядра.

Собранный образ. (В принципе он должен работать и на Orange PI 2g-iot но у меня нет этой платы, проверить не могу.)

Ссылка на файлы взятые из оригинального ядра OrangePI i96. Они получены путем сравнения образа от разработчиков и ядра Linux 3.10.62.

On english please.

Теги:
Хабы:
Всего голосов 32: ↑32 и ↓0+32
Комментарии17

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань