ArchLinux on an Android TV Box
From old Android TV Box to server: teardown, device tree extraction and ArchLinuxARM install.
I needed a mini PC running Linux, with an ethernet port and low power consumption. I had an old TV Box (Mecool BB2 Pro) that is the perfect candidate while also being completely silent. There are tons of use for this kind of systems: NVR, 3D printing server, homemade VPN, NAS etc. Moreover, Linux replaces the default Android OS that comes preinstalled which is old, no longer updated, insecure and/or infected.
Some of the main OS to install on this kind of devices are Armbian and LibreELEC. The latter is focused on media consumption so it takes specific care to make media-related thing work (hardware acceleration, video/sound, …), while Armbian is a port of Debian for ARM devices. Since my end goal was an ArchLinuxARM system, I based my work converting a working Armbian install into an Arch one.
On the board we have:
- Amlogic
S912
SOC, under the heatsink - Female
SMA
antenna connector G2401SG
, 1 GBit Ethernet controller, top rightRTL8211F
, Ethernet transceiver, top center-rightK4A4G165WE-BCRC
, RAM, center leftTHGBMBG7D2KBAIL
, 16 GB eMMC, bottom rightKM63350504
, WiFi/BT controller, bottom left (AP6335
-compatible?)K4A8G165WB-BCRC
, RAM, bottom side
If you prefer skipping all the explanations, jump to the Image Creation section at the end.
Armbian Install
The following procedure is specific for my TV Box's CPU but can be adapted easily. Follow the instructions reported here to get to a bootable Armbian system installed on an USB (in my case) or an SD card (/dev/sdb
for me):
# The download link will change!
set IMAGE 'Armbian_23.11.1_Aml-s9xx-box_bookworm_current_6.1.63.img'
wget https://redirect.armbian.com/aml-s9xx-box/archive/$IMAGE.xz
unxz $IMAGE.xz
sudo dd if=$IMAGE of=/dev/sdb status=progress
sudo mkdir -pv /mnt/TVBOX/{B,R}OOT/
sudo mount /dev/sdb1 /mnt/TVBOX/BOOT/
sudo mount /dev/sdb2 /mnt/TVBOX/ROOT/
In my case the box has a S912
CPU so I selected the correct u-boot file and renamed it: sudo cp /mnt/TVBOX/BOOT/u-boot-s905x-s912 /mnt/TVBOX/BOOT/u-boot.ext
Device Tree
The dtb
is a file that tells the kernel where the different component are located since it contains information about the board and the peripherals. There is no dtb
(Device Tree Blob) specific for my box so I used one from a similar model (/dtb/amlogic/meson-gxm-mecool-kiii-pro.dtb
in the Armbian image). The two box are indeed very similar, here is a Kiii Pro
model teardown. The Linux kernel contains several dts
files, you can browse them here. They can be compiled from source (with some gcc
command and then using device-tree-compiler
with the command dtc -@ -O dtb -o mecool_bb2_pro_v1.dtb mecool_bb2_pro_extracted.dts
) or extracted from the ArchLinuxARM tarball. Additionally, I saved the dtb
file from the installed Android ROM (located at /dev/dtb
while booted) which should contain all the necessary information to write one for Linux. I also extracted it by using a dtc
binary that I statically compiled on an aarch64/arm64
system (git clone
https://android.googlesource.com/platform/external/dtc
; cd dtc; make STATIC_BUILD=1 NO_YAML=1
), uploaded to the TVBox running Android and, as the root
user, running the command ./dtc -I fs /proc/device-tree -O dts -o fs_extracted.dts
to extract it from memory. The Android dtb
files however can not be used directly since Android use a (really) old kernel and drivers name are different.
I also had to modify the extlinux
bootloader configuration file to convert to uppercase some keywords (like APPEND
) and remove the splash option (to read the boot log process). The final /boot/extlinux/extlinux.conf
is this one:
LABEL Armbian
LINUX /Image
INITRD /uInitrd
FDT /dtb/amlogic/meson-gxm-mecool-kiii-pro.dtb
APPEND root=UUID=a6cf29bd-49ae-4d3b-bf22-800408ae1fba rootflags=data=writeback console=ttyAML0,115200n8 console=tty0 rw no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 plymouth.ignore-serial-consoles
Note that the UUID may depend on the specific Armbian version. Now Armbian should be bootable with a working ethernet port. To boot the new OS from the external media (USB/SD card), plug in the power while pressing the reset button, then release it after a few seconds. At this point the TV Box runs a Linux distro, based on Debian, but we can take it even further and install Arch on it.
ArchLinuxARM from Armbian
To convert the Armbian to ArchLinuxARM we basically need to convert the root partition (/dev/sdb2
mounted on /mnt/TVBOX/ROOT/
in my case) and update the bootloader configuration file to boot from the new kernel.
wget http://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz
sudo rm -r /mnt/TVBOX/ROOT/*
sudo tar -xf ArchLinuxARM-aarch64-latest.tar.gz -C /mnt/TVBOX/ROOT/
At this point the TV Box boots ArchLinuxARM but with the old kernel:
[root@alarm ~]# head -n4 /etc/os-release
NAME="Arch Linux ARM"
PRETTY_NAME="Arch Linux ARM"
ID=archarm
ID_LIKE=arch
[root@alarm ~]# uname -a
Linux alarm 6.1.11-meson64 #23.02.2 SMP PREEMPT Sat Feb 18 00:07:55 UTC 2023 aarch64 GNU/Linux
Now we need to tell the bootloader to boot the new kernel image and add the correct mount options for the boot partition. To do so shut down the box, plug the USB/SD back in the PC, mount again the two partition and update the content of the boot partition (/dev/sdb1
mounted on /mnt/TVBOX/BOOT/
in my case) with the boot
folder present in ROOT
:
sudo mv /mnt/TVBOX/ROOT/boot/* /mnt/TVBOX/BOOT/
Note that some of the old (Armbian) files are required to boot, so don't delete them. They are the bootloader (U-Boot) files. Some information on how to build the bootloader can be found here (archived). Update /mnt/TVBOX/ROOT/etc/fstab
to mount the two partitions and since we are at it reduce the number of writes made to the disk to increase the USB/SD longevity:
echo '/dev/sda1 /boot vfat defaults 0 2
/dev/sda2 / ext4 defaults,noatime,commit=4780,barrier=0,data=writeback,nobarrier,max_batch_time=0 0 1' \
| sudo tee -a /mnt/TVBOX/ROOT/etc/fstab
Now create the new extlinux config file /mnt/TVBOX/BOOT/extlinux/extlinux.conf
with the following content:
LABEL ArchLinuxARM
LINUX /Image
INITRD /initramfs-linux.img
FDT /dtbs/amlogic/meson-gxm-mecool-kiii-pro.dtb
APPEND root=LABEL=armbi_root rootflags=data=writeback console=ttyAML0,115200n8 console=tty0 rw no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 plymouth.ignore-serial-consoles
If you want to (temporary) enable SSH login for the root user using password (for configuration purposes) modify /mnt/TVBOX/ROOT/etc/ssh/sshd_config
to add the line PermitRootLogin yes
. Remember to later change it back to PermitRootLogin prohibit-password
. Now boot the system and verify that it's booting the ArchLinuxARM kernel. Finally tweak a couple of system's parameters to further reduce the number of writes to the disk:
echo 'Storage=volatile' | sudo tee -a /etc/journald.conf
echo 'vm.dirty_background_ratio = 20
vm.dirty_expire_centisecs = 360000
vm.dirty_writeback_centisecs = 360000' | sudo tee -a /etc/sysctl.conf
Note that Armbian deploys other measures to optimize the device performance, they are shortly described in the documentation here. From now on follow the ArchLinux Wiki to finish installing the OS (vconsole, locale, hostname, networking …).
Additional Tinkering
Since the default brcm
firmware present in ArchLinuxARM doesn't seem to support my wireless (WiFi and Bluetooth) chip, it needs to be replaced with the LibreELEC version (archived). There is also an Armbian version (archived) but it does not seem to work out of the box (probably some files with a specific name need to be symlinked in the firmware folder). In Arch, the content of /usr/lib/firmware/brcm/
must be replaced by content of the downloaded brcm
folder.
If you want to expand the filesystem and partition to fill all the SD Card/USB, use either gparted
on the PC or the script armbian-resize-filesystem
to be adapted for non-Armbian installations (remove sourcing of other files, define missing variables i.e. $Log, remove systemd stuff, …). The parted
program is needed to run it. If you plan on installing the OS on eMMC resize it later (better to do it manually).
After ensuring that the system is fully configured and working, you can even install the OS on the integrated eMMC (16GB for my box). However this is strongly discouraged for (at least some) Amlogic boards due to a proprietary partitioning scheme (LibreELEC short explanation, S905 thread). If you still want do so, utilize the script provided by Armbian located in /root/install-aml.sh
of the Armbian installation or on the GitHub repo (archived). If you already converted the installation to ArchLinuxARM, you can retrive the file by mounting the Armbian image as a loop device:
sudo losetup --find --show Armbian_*.img
sudo fdisk -l /dev/loop*
sudo mount /dev/loop0p2 /mnt/TVBOX/ROOT
ls -l /mnt/TVBOX/ROOT/root/install-aml.sh
The Infra Red receiver should be functional by default (e.g. the ON/OFF switch on the remote is fully working, even if the box is off) and can be customized by installing and configuring LIRC
. In my case also the physical ON/OFF button is working.
Image Creation
To quickly make changes, I later created an image that can directly be flashed on the SD/USB and booted with Arch.
# Image Creation
fallocate -l 5G TVBox.img
sudo losetup --find --show TVBox.img
sudo dd if=Armbian_23.11.1_Aml-s9xx-box_bookworm_current_6.1.63.img of=/dev/loop0 status=progress
sudo parted /dev/loop0 resizepart 2 100%
tune2fs -O extents,uninit_bg,dir_index,has_journal,flex_bg,huge_file,extra_isize,dir_nlink,uninit_bg /dev/loop0p2
sudo e2fsck -f /dev/loop0p2
sudo resize2fs /dev/loop0p2
sudo fatlabel /dev/loop0p1 BOOT
sudo e2label /dev/loop0p2 root
sudo fdisk -l
sudo mount /dev/loop0p1 mnt/boot/
sudo mount /dev/loop0p2 mnt/root/
# /boot partition changes
sudo cp -v mnt/boot/u-boot-s905x-s912 mnt/boot/u-boot.ext
echo 'LABEL ArchLinuxARM
LINUX /Image
INITRD /initramfs-linux.img
# use the Arch dtb file
FDT /dtbs/amlogic/meson-gxm-mecool-kiii-pro.dtb
APPEND root=UUID=a6cf29bd-49ae-4d3b-bf22-800408ae1fba rootflags=data=writeback console=ttyAML0,115200n8 console=tty0 rw no_console_suspend consoleblank=0 net.ifnames=0 fsck.fix=yes fsck.repair=yes plymouth.ignore-serial-consoles' \
| sudo tee mnt/boot/extlinux/extlinux.conf
# /root from Armbian To ArchLinuxARM
sudo rm -r mnt/root/*
sudo tar -xf ArchLinuxARM-aarch64-latest.tar.gz -C mnt/root/
sudo mv -v mnt/root/boot/* mnt/boot/
sudo umount mnt/boot
sudo mount /dev/loop0p1 mnt/root/boot/
# Wireless driver fix
# another version, from Armbian: https://github.com/armbian/firmware/tree/master/brcm
wget -qO- https://github.com/LibreELEC/brcmfmac_sdio-firmware/archive/refs/heads/master.tar.gz | tar -xzf -
sudo rm mnt/root/usr/lib/firmware/brcm/*
sudo cp -v brcmfmac_sdio-firmware-master/* mnt/root/usr/lib/firmware/brcm/
echo '/dev/sda1 /boot vfat defaults 0 2
/dev/sda2 / ext4 defaults,noatime,commit=4780,barrier=0,data=writeback,nobarrier,max_batch_time=0 0 1' \
| sudo tee -a mnt/root/etc/fstab
# Script (adapted from /usr/bin/armbian/armbian-resize-filesystem)
sudo cp resize-filesystem mnt/root/root/
sudo arch-chroot mnt/root/
pacman-key --init
pacman-key --populate archlinuxarm
pacman --noconfirm -Sy parted # needed for the resize-filesystem script
Future Works
- Armbian performance tweaks in Arch
- eMMC installation
- IR remote as automation triggers in HomeAssistant
Notes
(Re)booting may take a long time (~1 min), depends on how fast is the disk on which the system has been installed (USB, SD, eMMC) since on shutdown all the files cached in RAM must be synced to the disk.
A display (or an HDMI capture card) and a keyboard to connect to the Box are strongly suggested. The display output is required to read possible boot error.