суббота, 11 апреля 2020 г.

Сборка Linux на Lichee Pi Nano

Приобрел себе плату Lichee Pi Nano. Производителем заявлена поддержка USB OTG, LCD экрана, SD карта и сборок Linux для ARM процессоров.

Как бывает часто с китайскими поделками - плата с наскоку не завелась. Оказалось, что сдохла встроенная SPI Flash. Сперва определялась 1 раз из 5, а после прогрева контактов паяльником вообще перестала работать. Пришлось делать загрузку с SD карты.

Сперва необходимо подготовить SD карту. Рекомендуется создать на карте 3 раздела:
  • FAT раздел для скриптов и zImage 
  • EXT4 раздел для данных
  • раздел для SWAP
После чего необходимо собрать uboot и записать его начиная с 8 сектора на SD карту (там его ищет встроенный в ПЗУ бутлоадер). Для этого необходим Linux с установленным GCC для arm-linux-gnueabi-. Отмечу, что на китайских сайтах часто используют arm-linux-gnueabihf- - но при ядре, собранном для hardware float платформы у меня не заработал ни один готовый пакет с сайта Debian.

Инструкция по сборке лежит на сайте http://www.programmersought.com/article/5946691191/, приведу здесь только набор команд:
Bash 0.54 KB
  1. sudo apt install gcc-arm-linux-gnueabi  # если не установлен ранее
  2. git clone https://github.com/Lichee-Pi/u-boot.git -b nano-v2018.01
  3. cd u-boot/
  4. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- licheepi_nano_spiflash_defconfig
  5. make ARCH=arm menuconfig                # не обязательно, я там ничего не правил
  6. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8
  7. # после успешной сборки записать на карту
  8. sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8

Просто для информации. Есть проект, в котором запускают uboot и Linux на F1C100s: https://github.com/thirtythreeforty/businesscard-linux и там вроде как есть конфиги для Lichee Pi Nano - но код там с наскоку не собрался, да и основан на более старой версии uboot.

Отмечу, что USB в uboot, собранном по китайской инструкции не работает, поэтому всё общение идет только через COM порт.

Залив uboot и удостоверившись, что он работает, приступаем к сборке Linux. Здесь есть неприятный момент - в последних версиях исходников с GIT не работает USB. Для меня это критично, поэтому воспользуюсь инструкцией отсюда: https://blog.csdn.net/u012577474/article/details/102895602 и соберу ядро 5.2, а не более свежее.

Необходимо загрузить архив исходников, после чего пропатчить его.
Bash 0.46 KB
  1. wget https://codeload.github.com/Lichee-Pi/linux/zip/nano-5.2-flash
  2. unzip linux-nano-5.2-flash.zip
  3. cd linux-nano-5.2-flash/
  4. patch -p1 <../usb.patch # патч тут: https://pastebin.com/9c4C8nuq
  5. #make sunxi_defconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
  6. # ^^ этот конфиг кривой. Брать работающий отсюда: https://pastebin.com/PW1C7ERK
  7. # плюс я в нем включил сборку дополнительных USB драйверов
  8. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8 modules dtbs zImage

Полученные файлы suniv-f1c100s-licheepi-nano.dtb и zImage записать на FAT раздел. Туда же положить скрипт boot.scr, взять его можно из любого архива от китайцев. Например, с официального сайта. Можно проверить - устройство должно начать загружаться, после чего не найдя ROOTFS ожидаемо крашнется по "Kernel panic - not syncing: No working init found.".
Готовый архив выложил на google drive. Собранные драйвера, например, lib80211.ko и 8188eu.ko можно взять тут.

А вот дальше начинается интересное. Необходимо получить работающий ROOTFS, и, желательно с нормальным набором пакетов.
Для этого воспользуюсь пакетом multistrap.
Вот содержимое моего конфиг файла:
INI file 0.45 KB
  1. [General]
  2. #noauth=true  --- обязательно убрать, иначе будут ошибки GPG NO_PUBKEY
  3. unpack=true
  4. debootstrap=Grip
  5. aptsources=Grip
  6. arch=armel
  7. #cleanup=true
  8. [Grip]
  9. # space separated package list
  10. source=http://ftp.debian.org/debian
  11. suite=stretch
  12. keyring=debian-archive-keyring
  13. components=main non-free
  14. #packages=
  15. packages=wpasupplicant wireless-tools mc mcedit systemd busybox-static sysvinit-core kmod initscripts apt libpam-modules libpam-modules-bin libpam-pwdfile libpam-runtime usbutils net-tools iproute2 tinysshd

После чего скармливаем конфиг в multistrap и ждем.
Bash 0.12 KB
  1. rm -rf /путь_куда_замонтирован_ext4_раздел_sd_карты/
  2. multistrap -a armel -d /путь_куда_замонтирован_ext4_раздел_sd_карты/ -f multistrap.conf

Отмечу, что раздел SD карты должен быть пустым, иначе, если несколько раз запускать multistrap в одну и ту же папку SD, уже на самом устройстве получим ошибки dpkg. Поэтому: rm -rf.

По завершению процесса - создаем на SD карте файл /etc/hostname с указанием желаемого имени устройства. Также можно создать файл /etc/fstab с указанием раздела под своп и boot (система нормально загрузится и без fstab):
Bash 0.12 KB
  1. # <file system> <mount pt> <type> <options> <dump> <pass>
  2. /dev/mmcblk0p3 none swap sw 0 0
  3. /dev/mmcblk0p1 /boot vfat rw 0 0

Кроме того, создаем папку /var/run, иначе не развернется пакет base-files (который ее наличие проверяет при первоначальной настройке).

И обязательно: скопировать файл /usr/share/sysvinit/inittab в /etc/inittab, иначе получим невнятное "Enter runlevel:" от init.

В файл /etc/inittab необходимо внести правки. В превую очередь - убрать запрос пароля при загрузке в single-user mode. Ведь мы еще не настроили рута, и войти под ним не сможем. Для этого необходимо найти:
# What to do in single-user mode.
~~:S:wait:/sbin/sulogin
и заменить на
# What to do in single-user mode.
~~:S:wait:/bin/bash
И раскомментировать строку, разрешающую логон по COM порту, и поправить ей скорость на 115200:
# Example how to put a getty on a serial line (for a terminal)
#
T0:23:respawn:/sbin/getty -L ttyS0 115200 xterm

Далее необходимо запустить SD карту уже в самом устройстве - Linux пойдет загружаться и повиснет после "Run /sbin/init as init process". Это нормально - так как необходимые пакеты еще не настроены.

Поэтому - перезагружаемся в single-user mode. Для этого останавливаем uboot, нажатием на клавишу и вводим в него следующие команды:
text 0.22 KB
  1. setenv bootargs console=tty0 console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 rw single
  2. load mmc 0:1 0x80C00000 suniv-f1c100s-licheepi-nano.dtb
  3. load mmc 0:1 0x80008000 zImage
  4. bootz 0x80008000 - 0x80C00000
Отмечу, что вариант с указанием init=/bin/bash - хоть и приведет к запуску BASH, но вызовет ошибку в dpkg: "dpkg: dpkg - error: PATH is not set".

В случае single-user mode, произойдет нормальная инициализация переменных окружения и мы попадем в BASH с приглашением "I have no name!@(none):/#".

В командной строке запускаем
Bash 0.02 KB
  1. dpkg --configure -a

и смотрим на прогресс, отвечая по ходу дела на вопросы .

Должна появиться ошибка:
text 0.14 KB
  1. No diversion 'diversion of /bin/sh by dash', none removed.
  2. This should never be reached
  3. dpkg: error processing package dash (--configure):
и в конце dpkg выдаст сообщение, что не смог настроить dash и bash.

Для устранения этой ошибки необходимо выполнить команду:
text 0.03 KB
  1. /var/lib/dpkg/info/dash.preinst
Если кроме dash и bash не смог настроиться пакет base-files - создаем папку /var/run.
После проделанных действий снова запускаем "dpkg --configure -a". На этот раз оно завершается без ошибок.

Следующим шагом - устанавливаем пароль для root командой "passwd root", перезагружаем устройство "reboot -f" - и видим, что опять система повисла после загрузки. Причина тут банальная - dpkg вернул стандартное содержимое файла /etc/inittab, и необходимо повторно раскомментировать в нем строку про serial line.

А теперь главное, ради чего всё затевалось - настройка WiFi.
У меня есть USB свисток на базе Realtek 8188eu, его и буду запускать.
Сперва необходимо создать файл /etc/wpa_supplicant.inf:
text 0.19 KB
  1. ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
  2. country=GB
  3. update_config=1
  4. network={
  5.         ssid="ваш ssid"
  6.         psk=код, сгенерированный wpa_passphrase
  7. }

и загрузить модули:
Bash 0.36 KB
  1. #!/bin/sh
  2. modprobe 8188eu
  3. insmod /lib/modules/5.2.0-licheepi-nano/kernel/net/wireless/lib80211.ko
  4. insmod /lib/modules/5.2.0-licheepi-nano/kernel/net/wireless/lib80211_crypt_wep.ko
  5. ifconfig wlan0 up
  6. wpa_supplicant -B -Dwext,nl80211 -i wlan0 -c/etc/wpa_supplicant.conf
  7. ifconfig wlan0 192.168.1.111 netmask 255.255.255.0
  8. route add default gw 192.168.1.1 wlan0

IP адрес здесь назначается статикой. При желании можно доустановить DHCP - сеть уже есть.

Остается создать resolv.conf:
text 0.19 KB
  1. nameserver 1.1.1.1
и выполнить "apt update"

Еще рекомендую добавить в /etc/sysctl.conf такие строки:
text 0.19 KB
  1. vm.min_free_kbytes=1024
    vm.overcommit_memory=1
Таким образом линукс будет чуть меньше свопить на 32 Мб памяти.

Обновление от 12 апреля 2020 г.
Linux из официального https://github.com/torvalds/linux/ тоже удалось заставить работать.
Также загружаем исходники, применяем патч usb.patch, однако он выдает ошибку на DTS файлах, но хоть C-шный исходник обновляет нормально. Можно поправить DTS файлы вручную - из патча понятно, что именно и куда добавляется, но не мудрствуя лукаво я просто скопировал уже пропатченные DTS, свой .config, сделал "make oldconfig" - всё собралось и заработало. Либо можно не заморачиваться с DTS, а взять готовый DTB из предыдущей сборки.

В отличие от версии ядра 5.2, на текущей 5.6 отсутствует kernel panic, который возникает при обильном свопе во время "тяжелых" apt. Одного этого уже достаточно для обновления.

И еще обновление от 13 апреля 2020 г.
SPI плата оказалась живой - просто она является китайской подделкой под Winbond и ее JEDEC код отличается первым байтом (0b, 40, 18 вместо  ef, 40, 18). Подробности, и какие файлы и как править, тут. Если в двух словах - найти в исходниках строку про winbond с кодом 0xef4018, скопировать ее и поменять код на 0x0b4018.

Комментариев нет: