Установка Linux на калькулятор. Часть II
Как вы помните, в прошлой статье мне удалось стартануть linux на калькуляторе. Однако, работать на нём было невозможно, и я считаю это незачётом. Тогда я понял, что кроличья нора достаточно глубока и придётся полностью пересобирать всю систему, разбираясь с кодом. В итоге, я кратко прошёлся по всем этапам, которые описывал автор проекта. И результат полностью того стоит. Итак, поехали!
Аппаратные доработки: подключаем UART
Я написал обо всех моих бедах создателю этого linux, заодно попросив прислать мне бекап его прошивки (хотя его лучше, не заливать). И спросил, как же мне подключить UART к моему калькулятору? На что он мне прислал следующую картинку, и сказал: ищи это на другой стороне платы.
В результате, мне предстоял сложный квест — отклеить плату от дисплея, не расколов дисплей и не сломав плату. Пихая туда все возможные металлические предметы, очень аккуратно, в течении часа мне удалось её отделить. Самое сложное было не оборвать тончайшие шлейфы.
Отделяем плату.
Наконец-то, нашему вниманию представляется просто невероятный зоопарк тестовых падов, выводы JTAG и, по моему, SPI, интерфейс SD. Но, самое главное, наш отладочный UART.
Скорее всего там использована логика 1,8 В, но у меня не было такого адаптера, и я решил рискнуть и использовать адаптер с логикой 3,3 В (вам же настоятельно рекомендую использовать 1,8). Попытка, заставить мой адаптер работать на напряжении 1,8 вольта, не увенчалась успехом. Таким образом, я вывел сигналы на гребёнку, в т.ч. опорные 1,8 вольта (но они не пригодились).
Можно приклеивать плату обратно и продолжать работать.
Давайте сразу посмотрим, почему же у нас не запускается система, при загрузке в ОЗУ? Хотя вроде всё работает. Во-первых, давайте глянем скрипт запуска. Содержимое файла run_linux_in_ram.uu:
uuu_version 1.2.135
# This script allows you to run the Linux OS in the RAM without altering the NAND Flash
SDP: boot -f boot/u-boot-dtb.imx -nojump
SDP: write -f firmware/zImage -addr 0x80800000
SDP: write -f firmware/imx6ull-14x14-prime.dtb -addr 0x83000000
SDP: write -f firmware/rootfs.cpio.uboot -addr 0x86800000
SDP: jump -f boot/u-boot-dtb.imx -ivt
SDP: done
Загружаем в память загрузчик u-boot, ядро, dts (точнее, скомпилированный бинарник dtb), initramfs и передаём управление загрузчику, после чего с успехом завершаем приложение uuu.
По логам всё идёт отлично, до момента окончательной загрузки ядра, а там начинается вот такая петрушка.
clk: Not disabling unused clocks
ALSA device list:
No soundcards found.
Freeing unused kernel memory: 1024K
can't open /dev/null: No such file or directory
...
can't open /dev/null: No such file or directory
Starting syslogd: OK
Starting klogd: OK
Starting network: OK
Starting Xorg: OK
can't open /dev/ttymxc0: No such file or directory
....
can't open /dev/ttymxc0: No such file or directory
imx-sdma 20ec000.sdma: external firmware not found, using ROM firmware
input: Goodix Capacitive TouchScreen as /devices/soc0/soc/2100000.aips-bus/21a4000.i2c/i2c-1/1-0014/input/input3
И так до посинения. Всё банально, /dev/ не создана. И проблема эта открылась позже, при конфигурировании rootfs. Шикарно, мы теперь имеем отличный инструмент отладки. Начнём всё собирать!
Сборка софта
Если вы дойдёте самостоятельно до этого этапа, то надеюсь у вас есть какой-никакой опыт сборки ядра, rootfs, конфигурирования через make menuconfig. Так как описывать весь необходимый список установочных пакетов мне уже лениво (надо установить как минимум кросскомпилятор arm-linux-gnueabihf-, ncurses и многое другое, у меня просто уже всё давно стоит). Будем считать, что вы всё умеете, я лишь заострю ваше внимание на некоторые моменты. Для начала процитирую, то как рекомендуется делать сборку на официальном сайте проекта, а потом я внесу некоторые комментарии.
4. Сборка из исходника
Этот процесс протестирован под Ubuntu 18.04 LTS. Рекомендуется делать сборку под Linux.4.1 u-boot
Как правило, пересобирать u-boot вам не нужно, и нижеприведенные инструкции даются в качестве справочного материала.
Чтобы собрать u-boot из исходника:git clone git://github.com/zephray/uboot.git cd uboot git checkout imx_v2018.03_4.14.98_2.0.0_ga make mx6ull_prime_defconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make
В результате получится бинарный файл u-boot-dtb.imx.4.2 Ядро
Для включения/отключения конкретных модулей драйверов/ядра потребуется пересобрать все ядро.4.2.1 Компиляция с помощью Buildroot
buildroot соберет ядро автоматически. Конфигурацию же можно изменить с помощью make linux-menuconfig.4.2.2 Сборка ядра вручную
git clone git://github.com/zephray/linux.git cd linux git checkout imx_4.14.98_2.0.0_ga ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make hp_prime_defconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make
В итоге будут собраны файлы arch/arm/boot/dts/imx6ull-14×14-prime.dts и arch/arm/boot/zImage.4.3 Корневая файловая система (rootfs)
На данный момент hp-prime-linux использует для построения корневой файловой системы buildroot. Пакетного менеджера пока что нет, и если вам нужно добавить или удалить пакет, то потребуется пересобрать rootfs.git clone git://git.buildroot.net/buildroot cd buildroot git checkout 2019.02.4 make BR2_EXTERNAL=~/Prinux/buildroot prime_defconfig make
Для установки модулей ядра в rootfs, перейдите в директорию ядра и выполните следующие команды:INSTALL_MOD_PATH=~/buildroot/output/target ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make modules_install
После этого повторно сгенерируйте образы с помощью buildroot.
Для начала, я решил проверить, что, как минимум, всё это собирается из исходников, поэтому решил потренироваться на самом простом — сборке u-boot. Это важно, так как бывает такой момент, что автор написал инструкцию по сборке и прошивке, а забыл закоммитить последние изменения, и в результате его инструкция оказывается бесполезным мусором.
U-boot собирается совершенно 1 в 1 по инструкции, без каких либо тонкостей. В корневой папке после компиляции, мы получим кучу файлов, но нас интересует файл u-boot-dtb.imx. Скопируем его в нашу флеш-утилиту (предварительно создав там папку my):
cp u-boot-dtb.imx /home/dlinyj/tmp/calc/flash_utility/my
И создадим там новый загрузочный скрипт, на котором всё и будем обкатывать:
uuu_version 1.2.135
SDP: boot -f my/u-boot-dtb.imx -nojump
SDP: jump -f my/u-boot-dtb.imx -ivt
SDP: done
Проверяем на калькуляторе (всё как обычно, запускаем скрипт, потом вставляем USB. И в результате должны получить такой результат.
Это полный успех, значит код рабочий и мы можем продолжать. Если вы дойдёте до сборки, то настоятельно рекомендую поглядеть git log и git diff между коммитами, чтобы оценить масштабы проделанной работы. Это восхищает и мотивирует!
Со сборкой ядра у меня тоже практически не возникло никаких проблем, разве что пришлось поставить дополнительный пакет lzop, чтобы ядро корректно сжалось. Протестировать можно точно так же (не забыв добавить загрузку dtb-файла, иначе ядро не стартанёт).
Самым сложным оказалась сборка rootfs, как оказалось, дефолтный конфиг мне не подойдёт для сборки. Для начала. делаем всё точно, как написано в инструкции:
git clone git://git.buildroot.net/buildroot
cd buildroot
git checkout 2019.02.4
А вот теперь начинается самое интересное, хождение по битым ссылкам :). В релизах, кроме flash_utility.tar.gz есть ещё файл Source code, который, совершенно неочевидным образом содержит в себе необходимые конфиги для сборки rootfs! Скачиваем файл prinux-0.1.zip и распаковываем его в удобное для нас место. Либо клонируем репозиторий. У меня это вышел путь /home/dlinyj/tmp/calc/prinux.
Там внутри есть папка buildroot — это и есть внешние конфигурационные файлы для сборки buildroot! И вот этот путь, именно до этой папки указываем в следующей команде:
make BR2_EXTERNAL= /home/dlinyj/tmp/calc/prinux prime_defconfig
Допереть до этого самостоятельно было невозможно, покуда я не прошерстил вообще все репозитории, файлы и не прочитал как же собирается buildroot (к своему стыду, впервые собираю его вот так, с нуля).
Этой конфигурации мало, в целом можно конечно собрать, и даже попробовать запустить, но initramfs он будет слишком здоровым (там стоят Иксы), больше 25 МБ, и он не запуститься. А для прошивки на nand мы будем получать ту же самую проблему, как и в тесте загрузки в память: не будут созданы файл-устройства.
Первое, я отредактировал файл /home/dlinyj/tmp/calc/prinux/buildroot/configs/prime_defconfig и привёл его к виду:
BR2_arm=y
BR2_cortex_a7=y
BR2_ARM_FPU_NEON_VFPV4=y
BR2_OPTIMIZE_3=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TARGET_GENERIC_HOSTNAME="prinux"
BR2_TARGET_GENERIC_ISSUE="Welcome to Prinux"
BR2_INIT_SYSTEMD=y
BR2_TARGET_GENERIC_GETTY_PORT="ttymxc0"
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_PRINUX_PATH)/board/prime/overlay/"
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_PRINUX_PATH)/board/prime/post_build.sh"
BR2_TARGET_ROOTFS_TAR_BZIP2=y
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
Выкинув совершенно лишние на данный момент пакеты иксов (мне бы стартануть систему, а потом всё остальное).
Далее выполняю:
make BR2_EXTERNAL= /home/dlinyj/tmp/calc/prinux prime_defconfig
make menuconfig
В опции Filesystem images включаю:
[*] cpio the root filesystem (for use as an initial RAM filesystem)
[*] Create U-Boot image of the root filesystem
Прохожусь по всем пакетам и отрубаю вообще всё, чтобы не было лишнего.
В разделе System configuration ставлю:
Init system (BusyBox)
/dev management (Static using device table)
Тем самым ещё более уменьшая образ, и наконец у нас будет корректно работать менеджер устройств!
Выходим и сохраняем. И собираем:
make
После успешной компиляции, топаем обратно в папку с собранным ядром и нам необходимо теперь установить модули ядра в нашу rootfs, для этого выполняем:
INSTALL_MOD_PATH=/home/dlinyj/tmp/calc/buildroot/output/target ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make modules_install
И возвращаемся в buildroot и вновь выполняем make. В результате мы получим собранные пакеты в папке /home/dlinyj/tmp/calc/buildroot/output/images:
- rootfs.cpio.uboot — это готовый initramfs
- rootfs.tar.bz2 — образ готовый для прошивки на nand.
Стартуем!
Переписываю готовые образы rootfs в папку my и не забываем переписать туда же свежесобранное ядро из папки /home/dlinyj/tmp/calc/linux/arch/arm/boot, файл zImage. Далее беру за основу скрипт прошивки на nand-флеш и привожу его к виду:
uuu_version 1.2.135
# This script allows you to flash the Linux OS into NAND Flash.
# Boot into flash environment
SDP: boot -f boot/u-boot-dtb.imx -nojump
SDP: write -f boot/zImage -addr 0x80800000
SDP: write -f boot/imx6ull-14x14-prime.dtb -addr 0x83000000
SDP: write -f boot/fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.gz.u-boot -addr 0x86800000
SDP: jump -f boot/u-boot-dtb.imx -ivt
# Flash kernel
FBK: ucmd flash_erase /dev/mtd1 0 0
FBK: ucp my/zImage t:/tmp
FBK: ucmd nandwrite -p /dev/mtd1 /tmp/zImage
# Flash device tree blob
FBK: ucmd flash_erase /dev/mtd2 0 0
FBK: ucp firmware/imx6ull-14x14-prime.dtb t:/tmp
FBK: ucmd nandwrite -p /dev/mtd2 /tmp/imx6ull-14x14-prime.dtb
# Flash rootfs
FBK: ucmd flash_erase /dev/mtd4 0 0
FBK: ucmd ubiformat /dev/mtd4
FBK: ucmd ubiattach /dev/ubi_ctrl -m 4
FBK: ucmd ubimkvol /dev/ubi0 -Nrootfs -m
FBK: ucmd mkdir -p /mnt/mtd
FBK: ucmd mount -t ubifs ubi0:rootfs /mnt/mtd
FBK: acmd export EXTRACT_UNSAFE_SYMLINKS=1; tar -jx -C /mnt/mtd
FBK: ucp my/rootfs.tar.bz2 t:-
FBK: sync
FBK: ucmd umount /mnt/mtd
# Done
FBK: done
Обращаю внимание, что у нас используется специальный образ rootfs для прошивки nand-флеш. Я выкинул прошивку u-boot (так и не понял в чём проблема, и пока не смог победить). device tree blob загружается из другой папки, но никто не мешает его собранный так же переписать либо из u-boot, либо из папки с ядром.
Запускаем этот скрипт, и у нас успешно прошивается nand-флеш. Поскольку загрузчик у нас не прошит, при подаче питания linux не стартанёт. Поэтому вновь правим (или пишем новый скрипт) для загрузки u-boot:
uuu_version 1.2.135
SDP: boot -f my/u-boot-dtb.imx -nojump
SDP: jump -f my/u-boot-dtb.imx -ivt
SDP: done
Запускаем этот скрипт, и шалость удалась!
К сожалению, мне удалось успешно загрузиться на nand только один раз, потом я решил поправить один файл и у меня уже сыпалось всё с паникой ядра. Чуть ниже расскажу о проблемах.
А как на счёт логина с клавиатуры калькулятора и работы экрана?
А, вы хотите нормальной работы калькулятора, прям как настоящего компьютера? Независимо от большого ПК, не работая через консоль? Да?
Да ладно. Их есть у меня, пожалуйста. Для этого, согласно той же инструкции надо поправить один файл. Цитирую:
5.3.1 Активация консоли VT
В данном релизе она активна по умолчанию.vi ~/buildroot/output/target/etc/inittab
Введите следующее:tty0::respawn:/sbin/getty -L tty0 0 vt100 # VT
Хочу обратить внимание, что в оригинальной статье ошибка (забыт нолик), в этой цитате я исправил данную команду. Вписываем эту строку, и перекомпилируем снова rootfs.
Далее пишем загрузочный скрипт, для загрузки нашей сборки initramfs:
uuu_version 1.2.135
# This script allows you to run the Linux OS in the RAM without altering the NAND Flash
SDP: boot -f my/u-boot-dtb.imx -nojump
SDP: write -f my/zImage -addr 0x80800000
SDP: write -f firmware/imx6ull-14x14-prime.dtb -addr 0x83000000
SDP: write -f my/rootfs.cpio.uboot -addr 0x86800000
SDP: jump -f my/u-boot-dtb.imx -ivt
SDP: done
Запускаем его, и вот вам демонстрация работы экрана и клавиатуры, ну чем не компьютер.
После чего я немного разошёлся, и накидал ещё в /root несколько графических файлов, и вывел их с помощью программы fbi (вы их видели в заходниках статей).
Итого
Фух, была проделана громадная работа, растянувшаяся на две недели, но оно того по настоящему стоило!
Если, вы вдруг имеете подобный калькулятор, то вполне можете повторить запуск линукс (как минимум в ОЗУ), с помощью обновленной утилиты, которую можете скачать вот тут.
flash_utility.tar.gz.
К сожалению, с nand-флеш мне не удалось подружиться. После редактирования файлика, и дальнейшей перезагрузки, я получил вот такое сообщение.
Я так и не понял почему так получается, как я не бился, второй раз загрузиться на nand-флеш мне не удалось. Скорее всего, это связанно с тем, что я затёр вспомогательные области nand-флеша, и где-то rootfs и u-boot попадает на эти битые сектора, которые я варварским образом перемаркировал в нормальные. Уже буквально в ночи, перед выходом данной статьи решил собрать initramfs с утилитами mtd и nand и посмотреть, что же происходит. А происходит весьма любопытная петрушка. При загрузке ядро у меня выдаёт.
gpmi-nand 1806000.gpmi-nand: mode:4 ,failed in set feature.
Bad block table found at page 262080, version 0x01
Bad block table found at page 262016, version 0x01
nand_read_bbt: bad block at 0x000000000000
nand_read_bbt: bad block at 0x000000020000
nand_read_bbt: bad block at 0x000000040000
nand_read_bbt: bad block at 0x000000060000
nand_read_bbt: bad block at 0x0000012c0000
nand_read_bbt: bad block at 0x000004e20000
nand_read_bbt: bad block at 0x000005280000
nand_read_bbt: bad block at 0x0000094c0000
nand_read_bbt: bad block at 0x000017b20000
5 cmdlinepart partitions found on MTD device gpmi-nand
Creating 5 MTD partitions on "gpmi-nand":
0x000000000000-0x000000400000 : "boot"
0x000000400000-0x000000c00000 : "kernel"
0x000000c00000-0x000000d00000 : "dtb"
0x000000d00000-0x000000e00000 : "misc"
0x000000e00000-0x000020000000 : "rootfs"
gpmi-nand 1806000.gpmi-nand: driver registered.
Но при этом в системе пятый раздел, на котором собственно и находится rootfs после загрузки отсутствует. Ошибок в логе загрузки нет:
# mtdinfo
Count of MTD devices: 5
libmtd: error!: cannot open "/dev/mtd4"
error 2 (No such file or directory)
Present MTD devices: mtd0, mtd1, mtd2, mtd3, mtd4
Sysfs interface supported: yes
# ls -la /dev/mtd*
crw-r----- 1 root root 90, 0 Feb 16 2021 /dev/mtd0
crw-r----- 1 root root 90, 2 Feb 16 2021 /dev/mtd1
crw-r----- 1 root root 90, 4 Feb 16 2021 /dev/mtd2
crw-r----- 1 root root 90, 6 Feb 16 2021 /dev/mtd3
brw-r----- 1 root root 31, 0 Feb 16 2021 /dev/mtdblock0
brw-r----- 1 root root 31, 1 Feb 16 2021 /dev/mtdblock1
brw-r----- 1 root root 31, 2 Feb 16 2021 /dev/mtdblock2
brw-r----- 1 root root 31, 3 Feb 16 2021 /dev/mtdblock3
Странная, пока непонятная мистика, куда подевался раздел.
Точно так же, мне не удалось прошить u-boot на nand. При прошивке командой:
kobs-ng init -x -v --chip_0_device_path=/dev/mtd0 /tmp/u-boot-dtb.imx
Происходит следующая ошибка:
WOpen:/tmp
WOpen:/tmp/u-boot-dtb.imx
run shell cmd: kobs-ng init -x -v --chip_0_device_path=/dev/mtd0 /tmp/u-boot-dtb.imx
unable to create a temporary file
Это всё, что удалось поймать по UART. Я уже и в исходниках kobs-ng поковырялся, но всё бестолку. Пока непонятно как разрешить этот вопрос.
Вопросы к сообществу
- Кто-нибудь сталкивался с проблемой перепрошивки с помощью утилиты kobs-ng?
Благодарности
- Выражаю огромную благодарность создателю данного проекта ZephRay, без него бы этой статьи бы не было. Это невероятный и очень крутой труд.
- Выражаю благодарность Bright_Translate за помощь с переводом инструкции по установке.
- Главная благодарность моей жене, которая помогала мне в составлении и оформлении данной статьи. А так же терпела мои ночные бдения за этим устройством.
Ссылки
- Основной проект.
- Файлы для сборки rootfs и скрипты прошивальщика.
- Обновлённая мной рабочая прошивка для калькулятора.