Збираємо u-boot для Андроїд-ТВ приставки на s805!
Опубліковано 09.12.2025, 12:39 в категорії Гайди
Пролог

Є в мене ось такий Android-TV бокс, на SoC - s805. Доволі довгий час на ньому стояв або Armbian або Arch Linux, і там крутились деякі мої невеличкі проєкти. І от одного разу, я вирішив випаяти звідти NAND пам'ять, щоб впаяти її в USB перехідник, і тим самим сдампити прошивку, тобто зробити повний образ наявної там системи, бо з під Armbian-а NAND пам'ять не була доступна, а з іншими способами возитись мені було лінь. Нічого гарного з цього не вийшло, і в решті решт я залишився з мертвим NAND чіпом, та цегляним Android-TV боксом :D

Linux стояв на SD картці, чому ж тоді бокс перетворився на цеглу? А все просто - в NAND пам'яті був bootloader - u-boot, який і завантажував систему з SD картки.
Пошукавши в інтернеті образи для прошивки таких ТВ-боксів, звідти можна легко витягти bootloader, та записати його в початок картки пам'яті, і ТВ-бокс магічним чином оживе. Але є одна проблема - bootloader з тих образів компілювався таким чином, що він очікує побачити певний Recovery скрипт в пам'яті. Там же він шукає і налаштування для себе, і тому змінити їх як на звичайному u-boot-і неможливо. Тобто такий bootloader ніяким чином (мабуть) не зможе автоматично завантажити систему з SD картки, і при кожному запуску ТВ-бокса, треба буде підключатись до нього по UART, та робити запуск системи руцями. Погодьтесь, таке собі. Тому сьогодні я розповім, як налаштувати та скомпілювати u-boot власноруч!
Компілюємо u-boot
Підготовка build environment-у
Перш за все, треба підготувати ваш Linux для того щоб збирати та компілювати код. Велика вірогідність того, що в вас вже встановлені всі необхідні пакети. Якщо ні, то зазвичай більшість речей можна встановити, встановивши відповідний пакет - наприклад base-devel якщо у вас Arch Linux, або build-essential якщо Ubuntu/Debian. Туди входять різного роду інструменти, наприклад gcc, make, bison, flex, і тд, які знадобляться для того, щоб скомпілювати u-boot. Також треба ще встановити git, wget, тощо. Через варіативність дистрибутивів, детально я на цьому зупинятись не буду - ви можете знайти інформацію для вашого дистрибутива в інтернеті.
Також в подальшому будуть використовуватись 32х бітні бінарники, і щоб ваша система могла їх запустити, так як у вас скоріше за все х64, треба провести певні маніпуляції. Наприклад на Arch Linux треба встановити два пакети - lib32-glibc та lib32-gcc-libs:
sudo pacman -S lib32-glibc lib32-gcc-libs
Також довелось ще встановити lib32-zlib з репозиторія Multilib. Тож все дуже ситуативно, і залежить від вашого дистрибутиву, а також системи - щось у вас вже встановлено, щось ні. Так чи інакше, в подальшому по помилкам це можна буде побачити.
Встановлюємо toolchain
Наступна задача - встановити toolchain. Це ще один набір інструментів, необхідних для компіляції u-boot. Але разом з цим, він виконує ще одну важливу роль, а саме забезпечує умови для кросскомпіляції - справа в тому що ви скоріше за все використовуєте комп'ютер/ноутбук з архітектурою x64, в той час як u-boot ви збираєте під ARMv7-A.
Завантажуємо архів з необхідними бінарниками toolchain-а:
wget http://releases.linaro.org/archive/14.04/components/toolchain/binaries/gcc-linaro-arm-none-eabi-4.8-2014.04_linux.tar.xz
Разархівовуємо його в зручне місце на системі:
sudo mkdir -p /opt/toolchains
sudo tar xJvf gcc-linaro-arm-none-eabi-4.8-2014.04_linux.tar.xz -C /opt/toolchains/
Та додаємо в $PATH, щоб користувач або скрипти могли використовувати бінарники не прописуючи шлях до них. Це можна зробити двома способами - тимчасово та постійно.
Тимчасово:
export PATH=/opt/toolchains/gcc-linaro-arm-none-eabi-4.8-2014.04_linux/bin:$PATH
Тимчасовий спосіб додасть бінарники в $PATH лише для поточного вікна терміналу. Якщо ви його закриєте, або відкриєте інший, треба буде знову виконувати команду вище.
Постійно:
Щоб уникнути цього, можна додати цю команду в кінець вашого .bashrc файлу, який знаходиться в $HOME директорії. Це можна зробити вручну через текстовий редактор, а можна виконати наступну команду:
echo "export PATH=/opt/toolchains/gcc-linaro-arm-none-eabi-4.8-2014.04_linux/bin:\$PATH" | tee --append ~/.bashrc
Тепер треба оновити зміни за допомогою наступної команди:
source ~/.bashrc
І можна впевнитись в тому що система бачить бінарники, перевіривши їх версію:
arm-none-eabi-gcc -v
Повинно вивестись багато інформації:
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
COLLECT_LTO_WRAPPER=/opt/toolchains/gcc-linaro-arm-none-eabi-4.8-2014.04_linux/bin/../libexec/gcc/arm-none-eabi/4.8.3/lto-wrapper
Target: arm-none-eabi
Configured with: /cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/src/gcc-linaro-4.8-2014.04/configure --build=i686-build_pc-linux-gnu --host=i686-build_pc-linux-gnu --target=arm-none-eabi --prefix=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/install --with-local-prefix=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/install/arm-none-eabi --without-headers --with-newlib --enable-threads=no --disable-shared --with-pkgversion='crosstool-NG linaro-1.13.1-4.8-2014.04 - Linaro GCC 4.8-2014.04' --with-bugurl=https://bugs.launchpad.net/gcc-linaro --disable-__cxa_atexit --with-gmp=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --with-mpfr=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --with-mpc=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --with-isl=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --with-cloog=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --with-libelf=/cbuild/slaves/oorts/crosstool-ng/builds/arm-none-eabi-linux/.build/arm-none-eabi/build/static --enable-lto --enable-linker-build-id --enable-libmudflap --disable-libgomp --enable-libssp --disable-libstdcxx-pch --enable-multilib --enable-languages=c,c++,fortran --with-multilib-list=aprofile
Thread model: single
gcc version 4.8.3 20140401 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.04 - Linaro GCC 4.8-2014.04)
Якщо у вас такий самий вивід - все зроблено правильно. Якщо пише щось на кшталт - command not found - переконайтесь що ви правильно додали все в $PATH. Якщо cannot execute: required file not found - переконайтеся що забезпечили всі умови для виконання 32х бітних бінарників на вашій 64х бітній системі.
Завантажуємо вихідний код та компілюємо
В якості джерела вихідного коду для u-boot під s805 я раджу вам обрати ось цей репозиторій. Клонуємо та відкриваємо його:
git clone https://github.com/hzyitc/u-boot-onecloud
cd u-boot-onecloud
Виправляємо баг з sha1.h
В цій версії u-boot присутній баг, через який компілятор буде намагатись використати системний файл sha1.h за шляхом /usr/include/sha1.h, в той час як в репозиторії лежить інший, який йому необхідно використати. Найлегше що можна зробити - забекапити, за наявності, системний файл:
sudo mv /usr/include/sha1.h /usr/include/sha1.hBAK
І додати на його місце файл з репозиторія:
sudo cp include/sha1.h /usr/include/
Після компіляції можна повернути все назад:
sudo rm /usr/include/sha1.h
sudo mv /usr/include/sha1.hBAK /usr/include/sha1.h
В цілому, тепер можна компілювати u-boot - для цього готуємо конфіг файл для нашої плати, та запускаємо процес компіляції:
make m8b_onecloud_config
make -j$(nproc)
Бінарник u-boot з'явиться в папці build, про що свідчить кінець логів команди make:
uclpack: using block-size of 262144 bytes
uclpack: algorithm NRV2D-99/7, compressed 639608 into 313205 bytes
/home/ctl/u-boot-onecloud/build/tools/convert --soc m8b -s /home/ctl/u-boot-onecloud/build/firmware.bin -i /home/ctl/u-boot-onecloud/build/u-boot-comp.bin -o /home/ctl/u-boot-onecloud/build/u-boot.bin
Якщо процес компіляції обривається помилкою, запустіть make без флагу -j, та шукайте більш детальну помилку - скоріше за все відсутні якісь 32х бітні бібліотеки чи щось таке.
make
Тож, u-boot готовий, але для моїх цілей він не підходить через відсутність NAND пам'яті, і на відміну від u-boot витягнутого з образів для прошивки - взагалі висне і не запускається :0
Налаштовуємо u-boot
Більшість налаштувань можна змінити у відповідному .h файлі для нашого ТВ бокса. Цей файл знаходиться за шляхом board/amlogic/configs/m8b_onecloud.h.
Мені наприклад треба вимкнути параметр CONFIG_STORE_COMPATIBLE. Наскільки я розумію - він відповідає за можливість зберігання конфігу/змінних для u-boot на накопичувачі. І через те, що в мене відсутня nand пам'ять - u-boot висне через цей параметр. Тож я знайшов його і закоментував:
//#define CONFIG_STORE_COMPATIBLE
Також, раз вже ми модифікуємо файл плати, можна поглянути і на параметр CONFIG_BOOTCOMMAND. Цей параметр, як видно з назви, вказує як саме u-boot буде намагатись запустити ядро Linux при старті. Стандартний виглядає так:
#define CONFIG_BOOTCOMMAND "print 'Autobooting...'; run boot_usb_armbian; run boot_sdcard_armbian; run boot_emmc_armbian; print 'Failed to boot'; "
Тобто він:
- Пише по UART "Autobooting..."
- Намагається запуститись з USB (boot_usb_armbian)
- Далі намагається запуститись з SD карти (boot_sdcard_armbian)
- Потім намагається запуститись з eMMC/NAND (boot_emmc_armbian)
- Пише "Failed to boot"
З USB я запускати систему не планую. З NAND пам'яті - вочевидь, теж. Тому я модифікував цей параметр, залишивши лише запуск з SD картки:
#define CONFIG_BOOTCOMMAND "print 'Autobooting...'; run boot_sdcard_armbian; print 'Failed to boot'; "
Чудово. Але, що ж таке цей boot_sdcard_armbian? А це не що інше, як така собі умовна функція, записана в параметр CONFIG_EXTRA_ENV_SETTINGS.
Там можна знайти, і подивитись, що саме вона робить:
"boot_sdcard_armbian=" \
"print -n 'Try to boot from SDCard...'; " \
"mmc rescan 0; " \
"setenv bootdev 'mmc 0'; " \
"fatload ${bootdev} ${loadaddr} boot.scr && autoscr ${loadaddr}; " \
"print 'Fail'; " \
"\0" \
Тобто вона:
- Пише по UART "Try to boot from SDCard..."
- Сканує доступні MMC девайси (0 - це наче режим роботи MMC, legacy)
- Встановлює змінну середовища
bootdevяка містить "mmc 0", тобто найперший MMC девайс, з якого і буде здійснюватись запуск - Завантажує за допомогою команди fatload з FAT розділу на MMC скрипт
boot.srcв пам'ять за адресою loadaddr, після чого запускає його за допомогоюautoscr(наче в більш нових версіях u-bootautoscrзамінили командоюsource) - Відповідно цей скрипт і завантажує ядро Linux, тобто якщо все гаразд - ви потрапили в Linux. Якщо запустити Linux не вдалось, по UART виводиться "Fail"
Тож тепер ви хоч трохи знаєте, що там відбувається під капотом, та що і де можна якщо що підлаштувати під себе!
Записуємо U-Boot на SD картку
Тепер найцікавіше - а як же записати U-Boot на картку пам'яті? Адже він повинен знаходитись на початку карти пам'яті, і якщо просто записати його поверх записаного туди Armbian-а або Arch Linux-а, ми просто зітремо таблицю розділів, і нічого не буде працювати (ну, окрім U-Boot :D).
Щоб уникнути затирання таблиці з розділами, нам треба записати bootloader в два місця - невеличку частину в спеціально призначене для цього місце (перші 442 байти MBR сектору), і потім весь bootloader повністю, після таблиці з розділами. Зробити це можна таким чином:
sudo umount /dev/sdX
sudo dd if=u-boot.bin of=/dev/sdX bs=1 count=442
sudo dd if=u-boot.bin of=/dev/sdX seek=1 skip=1 bs=512
sync
Де sdX - ваша SD картка. Правильну назву можна подивитись, виконавши команду lsblk, але ДУЖЕ ВАЖЛИВО не переплутати SD картку з іншим девайсом, адже іншим девайсом може бути ваш системний диск (якщо ви використовуєте SATA SSD/HDD, а не NVMe), і якщо записати bootloader туди, це може призвести до втрати даних.
Епілог
Більшість інформації для цієї статті я взяв з Wiki ODROID-C1. В них навіть є свій форк u-boot для процесора s805. Чого ж ми тоді використали інший? Справа в тому, що в них є спеціальний "1st stage bootloader", який потрібен для нормального функціонування їх u-boot-у:
- The 1st stage bootloader, bl1.bin.hardkernel, is provided as prebuilt binary only.
І от що цей bl1 робить, так це перевіряє умовний Serial Number (в процесорі, або десь на платі, не впевнений), і порівнює його зі своїм якимось списком та/або ключами. Якщо серійний номер не співпадає - bootloader не запуститься :D А він звісно не співпаде, так як в нас не ODROID плата, а AndroidTV приставка.

Тому й довелось використовувати сторонній форк u-boot від onecloud - якоїсь іншої китайської AndoidTV приставки чи чогось схожого