May 3, 2020
Installing solyste on a Turris Omnia
Four years ago, CZ.NIC launched a campaign on Indiegogo to create what they called "The open-source center of your home". The idea sounded kinda interesting to me. I was not really thrilled about the software, I was excited about the hardware. As you can see, the listed features were quite good. Therefore, I decided to pre-order a board. My primary idea was to port my personal Linux distribution called solyste, to it.
Unfortunately, embedded hardware often use custom U-Boot
and also heavily patched Linux kernel. No surprise, it was the
same here. I dislike having to build custom kernels from obscure
and sometimes unmaintained trees, because it is not a long-term
solution. What can we do when manufacturers decide to (silently)
drop the hardware ? We become stuck with old, buggy and flawed
software. For those reasons, I had to wait for patches in
upstream / mainline Linux
repo.
As I write these lines, front LEDs are not really supported by
5.4.x
and we can't control them. It seems to work
with OpenWrt and LEDE, though (I didn't test by myself).
Upstreaming support took a long time, but eventually it came later. Even if a few bits are still missing, I knew I could try to boot on the board. Due to the Covid-19 crisis, I had to stay at home like many people across the globe. After all those years, it was the occasion to work on solyste and Omnia, in my spare time.
Kernel
Booting a kernel on the default system was not really hard.
I had to compile it with mvebu_v7_defconfig
and
it went surprisingly fine. The device tree file is mandatory too.
The kernel (without loadable modules) will be meticulously tuned
later. Make sure you can access U-Boot prompt with
serial
connection preliminarily. Then, using TFTP I could "send" it to
the board, with the following commands :
tftpboot 0x01000000 zImage
tftpboot 0x02000000 armada-385-turris-omnia.dtb
bootz 0x01000000 - 0x02000000
You only need to make sure that your kernel supports Btrfs, to be able to mount the first partition (and to avoid a kernel panic). That's what the vanilla system uses.
Userland
Few years ago, I embraced
musl libc for my own
projects and I never looked back. Rich, by any chance, if you
read these lines, you are truly awesome.
The repository
musl-cross-make
provides a makefile to build the musl cross-compiler. That's
what I use in solyste (before, I was also building the
cross-compiler with my own scripts). Boosted by the previous
success, I wrote the proper code to cross-compile the softwares
for armv7
architecture.
Embedded MMC
It was is the scary part. Managing the eMMC is
sometimes extremely difficult. An innocent tiny mistake can
brick your device for good. What a harsh reward. Turris Omnia
has 8Go NAND flash. It would be very sad to not use all that
space. Anyway, at the moment we simply CAN'T boot from both
USB3, because of U-Boot version. mSATA SSD or mPCIe to USB boot
is
possible,
but it requires you to buy something else, one more time.
Luckily, in addition to the default operating system, a
rescue system is installed in SPI flash. We can exploit it to
install solyste. To switch to rescue, follow this
page.
It is based on a busybox
and a few other tools.
There is a script called rescue.sh
in
/bin
directory to reflash the router, as described
here.
We won't use it because it supports btrfs
only.
/ # ls bin/
[ date head mktemp rmdir tr
[[ dd hostid mount sed traceroute
ash df hostname mv seq true
awk dirname id nc setsid umount
basename dmesg ipcalc netmsg sh uname
bunzip2 du kill nice sha256sum uniq
busybox echo killall nslookup sleep unxz
bzcat egrep less pgrep sort uptime
bzip2 expr ln pidof strings vi
cat false lock ping stty wc
chgrp fgrep logger ping6 sync wget
chmod find ls printf tail which
chown free lspci ps tar xargs
clear fsync lsusb pwd tee xz
cmp ftpget md5sum readlink test yes
cp grep mkdir rescue.sh tftp zcat
cttyhack gunzip mkfifo reset time
cut gzip mknod rm touch
fdisk
binary is present in /sbin
but we still lack e2fsprogs
to create
ext4
filesystem. ext4
is perfect for
me (my systems are read-only anyway). Not a problem here as
e2fsprogs
is included in base
group in
solyste. That means I can easily build a static
mke2fs
binary. That's neat, isn't it ?
$ file mke2fs
mke2fs: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
That mke2fs
binary could be also very useful
in the future. I decided to copy it in /sbin
. Maybe
we should ask CZ.NIC to do it, but I feel it would be too much
hassle, as they are focusing on Btrfs. Now, we create the
filesystem :
/ # fdisk /dev/mmcblk0
/ # mke2fs -t ext4 /dev/mmcblk0p1
We are (very) good so far.
solyste is finally ready to be deployed in eMMC. Let's
extract the archive stored on an external USB drive, with
tar
:
/ # mount -t ext4 /dev/mmcblk0p1 /mnt
/ # tar xvf SOLYSTE-OMNIA.tar.gz -C /mnt
/ # chown -R 0:0 /mnt/*
/ # sync
/ # umount /mnt
Press the reset button to reboot. Before we edit U-Boot
environment variables, we verify if the ext4
partition is correctly listed :
=> ext4ls mmc 0:1 /
<DIR> 4096 .
<DIR> 4096 ..
<DIR> 16384 lost+found
<DIR> 4096 bin
<DIR> 0 boot
<DIR> 0 dev
<DIR> 0 etc
<DIR> 0 mnt
<DIR> 0 proc
<DIR> 0 root
<DIR> 0 sys
<DIR> 0 tmp
<DIR> 0 var
Hum, it does not seem to be very good… The directories were simply empty and the files inside them were missing :
=> ext4ls mmc 0:1 /boot
** Can not find directory. **
At this point, I thought there was a problem with the eMMC, even if I didn't do something wrong. But it was still correctly detected :
=> mmcinfo
Device: mv_sdh
Manufacturer ID: 90
OEM: 14a
Name: H8G4a
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.0
High Capacity: Yes
Capacity: 7.3 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
Thanks to TFTP, I could boot on my kernel and the main
partition was totally fine. Something was bad with U-Boot.
Maybe the ext4
implementation is too simple.
In embedded world, filesystems in 64-bit mode can lead to
erratic behavior. I decided to boot once again in rescue mode
to create the ext4
filesystem, in 32-bit this time.
Do you remember when I told you earlier that mke2fs
could be necessary ? So, here we go again :
/ # mke2fs -t ext4 -O ^64bit /dev/mmcblk0p1
Then, after extracting the archive and rebooting, the
ext4ls
command was more realistic :
=> ext4ls mmc 0:1 /
<DIR> 4096 .
<DIR> 4096 ..
<DIR> 16384 lost+found
<DIR> 4096 bin
<DIR> 4096 boot
<DIR> 4096 dev
<DIR> 4096 etc
<DIR> 4096 mnt
<DIR> 4096 proc
<DIR> 4096 root
<DIR> 4096 sys
<DIR> 4096 tmp
<DIR> 4096 var
=> ext4ls mmc 0:1 /boot
<DIR> 4096 .
<DIR> 4096 ..
17506 armada-385-turris-omnia.dtb
3793992 zImage
VICTORY ! As the main ext4
filesystem is
completely detected by U-Boot, we can now setup the boot
itself.
U-Boot variables
The default environment variables can be listed with
printenv
. Here the default bootargs
and mmcboot
variables. We will modify them :
bootargs=earlyprintk console=ttyS0,115200 rootfstype=btrfs rootdelay=2 root=b301 rootflags=subvol=@,commit=5 rw
mmcboot=setenv bootargs "$bootargs cfg80211.freg=$regdomain"; btrload mmc 0 0x01000000 boot/zImage @; btrload mmc 0 0x02000000 boot/dtb @; bootz 0x01000000 - 0x02000000
First, we will replace bootargs
with
setenv
. I tried the following, but I had many
kernel panics :
setenv bootargs rootfstype=ext4 root=/dev/mmcblk0p1 rw console=ttyS0,115200
The kernel was booting too fast and the eMMC was not
discovered in time. It's also quite common. Let's add
rootdelay
. Even default variable has it. I appended
quiet
too.
setenv bootargs rootfstype=ext4 root=/dev/mmcblk0p1 rootdelay=2 rw console=ttyS0,115200 quiet
mmcboot
variable is similar to
tftpboot
command. Defining
cfg80211.freg
makes no sense here, because my board
do not have WiFi. Secondly, btrload
is for
btrfs
. The ext4
counterpart is
ext4load
. With those parameters, we can compose
the variable :
setenv mmcboot "ext4load mmc 0:1 0x01000000 boot/zImage ; ext4load mmc 0:1 0x02000000 boot/armada-385-turris-omnia.dtb ; bootz 0x01000000 - 0x02000000"
Do not get fooled by my words, I had to try four or five
times to find the correct value. Once bootargs
and
mmcboot
variables are setup, we save them with
saveenv
command and… we are done ! You can either
push the reset button on the back or directly launch
run mmcboot
command.
RAM issues
Usually, when the Omnia was unplugged from electrical source or after a reset, the DDR3 RAM will fail to initialize. Here the output :
Memory config in EEPROM: 0x01
ddr3_tip_pbs_rx failure CS #0
Title: I/F# , Tj, Calibration_n0, Calibration_p0, Calibration_n1, Calibration_p1, Calibration_n2, Calibration_p2,CS0 ,
VWTx, VWRx, WL_tot, WL_ADLL, WL_PH, RL_Tot, RL_ADLL, RL_PH, RL_Smp, Cen_tx, Cen_rx, Vref, DQVref, PBSTx-Pad0,PBSTx-Pad1,PBSTx-Pad2,PBSTx-Pad3,PBSTx-Pad4,PBSTx-Pad5,PBSTx-Pad6,PBSTx-Pa
d7,PBSTx-Pad8,PBSTx-Pad9,PBSTx-Pad10, PBSRx-Pad0,PBSRx-Pad1,PBSRx-Pad2,PBSRx-Pad3,PBSRx-Pad4,PBSRx-Pad5,PBSRx-Pad6,PBSRx-Pad7,PBSRx-Pad8,PBSRx-Pad9,PBSRx-Pad10,
Data: 0,72,19,15,19,15,20,20,CS0 ,
0,0,10,10,0,423,7,1,6,23,10,4,0, 63,63,63,63,31,31,63,63,63,63,63, 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,
0,0,6,6,0,422,6,1,6,19,10,4,0, 63,63,63,63,31,31,63,63,63,63,63, 0,0,0,0,0,0,0,0,0,0,0, 0,4,2,8,0,0,3,8,8,10,0,
0,0,6,6,0,421,5,1,6,19,10,4,0, 63,63,63,63,31,31,63,63,63,63,63, 0,0,0,0,0,0,0,0,0,0,0, 2,0,0,6,0,0,0,2,6,3,0,
0,0,10,10,0,423,7,1,6,23,10,4,0, 63,63,63,63,31,31,63,63,63,63,63, 0,0,0,0,0,0,0,0,0,0,0, 1,2,1,5,0,0,2,0,4,1,0,
Run_alg: tuning failed 0
DDR3 run algorithm - FAILED 0x1
DDR3 Training Sequence - FAILED
I share it to you in case you noticed it on your board. I do not know if my unit is defective or not. I just hope it will not happen when it's deployed, in a remote location. I would be unable to access it.
solyste on Turris Omnia
After the previous steps, solyste is now perfectly booting. The board is ready to be used. Needless to say, I'm quite happy. Maybe it's time to brag a little bit…
Kernel :
solyste armv7l on 5.4.33-SOLYSTE (/dev/ttyS0)
solyste-omnia login: root
Password:
Welcome to your solyste box!
[solyste-omnia] /root # cat /proc/version
Linux version 5.4.33-SOLYSTE (ypnose@solyste) (gcc version 9.2.0 (GCC)) #1 SMP Sat May 2 13:46:17 CEST 2020
[solyste-omnia] /root # uname -a
Linux solyste-omnia 5.4.33-SOLYSTE #1 SMP Sat May 2 13:46:17 CEST 2020 armv7l GNU/Linux
[solyste-omnia] /root # du -h /boot/zImage
3.6M /boot/zImage
[solyste-omnia] /root # zcat /proc/config.gz | grep CONFIG_MODULES
# CONFIG_MODULES is not set
cpuinfo :
[solyste-omnia] /root # cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 1 (v7l)
BogoMIPS : 1600.00
Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
processor : 1
model name : ARMv7 Processor rev 1 (v7l)
BogoMIPS : 1600.00
Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
Hardware : Marvell Armada 380/385 (Device Tree)
Revision : 0000
Serial : 0000000000000000
Daemons / services :
[solyste-omnia] /root # perpls -G
[+ +++ +++] crond uptime: 107s/107s pids: 147/146
[+ +++ ---] getty-ttyS0 uptime: 107s/-s pids: 145/-
[+ +++ ---] klogd uptime: 107s/-s pids: 155/-
[- --- ---] monit (service not activated)
[- --- ---] openntpd (service not activated)
[+ +++ +++] sshd uptime: 107s/107s pids: 152/150
[+ +++ ---] syslogd uptime: 107s/-s pids: 144/-
[- --- ---] unbound (service not activated)
[- --- ---] vnstatd (service not activated)
[+ +++ ---] watchdog uptime: 107s/-s pids: 148/-
[solyste-omnia] /root # pstree
init---rc.intro---perpboot-+-perpd-+-crond
| |-klogd
| |-mksh---pstree
| |-sshd
| |-syslogd
| |-2*[tinylog]
| `-watchdog
`-tinylog
[solyste-omnia] /root # print $KSH_VERSION
@(#)MIRBSD KSH R59 2020/04/14
The end
Even if I plan to write an article explaining why solyste is different and how it works, you can visit my "Projects" page in the meantime. Have a nice day and take care of you.