Off-topic: The importance of efficient tooling
You’re probably aware of the existence and hopes tied to the rise of the RISC-V architecture, which means we should prepare for future (yet hypothetical) RISC-V Linux-based mobile devices.
The first step in this journey being the ability to build binary packages for this architecture, we purchased a StarFive VisionFive v2 SBC with the goal to turn it into a (Debian-powered, of course!) GitLab CI runner. And that’s exactly where the tools developed to build Mobian came in really handy!
Debian on RISC-V
64-bits RISC-V (or riscv64
in Debian terms) is not an architecture officially
supported by upstream Debian. However, the vast majority of packages are built
and available to riscv64
devices thanks to the Debian Ports
initiative.
As an unofficial port, the
riscv64
packages live in a separate archive,
providing only the unstable
and experimental
suites. Those details aside,
all the usual Debian tools work in the exact same way they do on other
architectures.
With this in mind, why not use the tools we’ve been developing for Mobian and create an “almost-pure” Debian image for the VisionFive v2?
The board
The VisionFive 2 is a RISC-V SBC based on StarFive’s JH7110 SoC. This chip includes 4x SiFive U74 cores, Gigabit Ethernet, PCIe and many other interfaces.
The board itself includes a choice of 2, 4 or 8GB RAM, a now-standard 40-pin GPIO header, a microSD card slot, an eMMC socket as well as an M.2 slot for an NVMe SSD, and of course several USB ports and 2 Gigabit Ethernet ports.
OK, but… can it run Debian?
In order to run any kind of Linux system (including a Debian-based one), we need the following elements:
- a bootloader
- a kernel which includes support for this specific device
- a root filesystem containing userspace software, compiled for the device’s CPU architecture
Das U-boot Abenteuer
The first item is already present on the board, in the form of a SPI NOR flash
chip, factory-flashed with u-boot
. However, the one present on our (early
bird) board lacked support for standard “distroboot”, therefore we had to build
a more recent version from StarFive’s u-boot
repository and flash it using the documented
recovery procedure.
It required backporting an upstream
patch
to be able to build using the compiler and binutils
from current Debian
testing. However, for some reason using the latest commit (at the time) of the
JH7110_VisionFive2_devel
branch led to a non-functional binary, unable to
detect the RAM size of our board. One more
patch
later, we could however get a working bootloader!
It wasn’t capable of using the “distroboot” due to wrong and/or missing environment variables, which were later added. Feel free to refer to our patched source tree, or simply download the binary files from our artifacts branch.
A working kernel
Similar to u-boot
, StarFive provides a
kernel
repository, including all needed patches to get it running on the VisionFive 2
board… and just like u-boot
, it doesn’t build from a current Debian
testing…
This is easily solved by, once again, backporting an upstream
patch.
Once built with the usual make bindeb-pkg
command (and, of course, the proper
values for the ARCH
and CROSS_COMPILE
env vars), we get a .deb
containing
the kernel and its modules, which boots just fine. However, the default kernel
config is somewhat limited and doesn’t allow us to run docker
(remember, we
want to make this board a GitLab CI runner!). With some additional
tweaking,
we finally get to a point where this kernel is fully usable for our purpose.
Our patched kernel is of course also available on GitLab.
Tying it all together
Putting the architecture differences aside, this device is quite similar to the PinePhone Pro from a low-level perspective: the bootloader is directly flashed to the board’s SPI flash, and we need to create a bootable image to be written on a microSD card.
We already know how to do this on the PPP, so why not re-use this knowledge for the VisionFive 2? Not wanting to mess with Mobian’s “production” codebase, we imported this repo to gitlab.com and made the necessary changes there. As you’ll notice from the single commit needed to generate the VisionFive 2 image, the changes are very minimal, demonstrating the flexibility and power of the tools we’ve been developing over the past 3 (!) years.
Let’s walk through those changes:
- the
build.sh
script is modified to support a newriscv64
device (it could/should probably have been namedvf2
, but remember this is only a quick and dirty experiment), using theriscv64
architecture and fetching its device-specific recipes fromdevices/riscv64
- the
devices/riscv64
is mostly a copy fromdevices/rockchip
with only a few small adjustments:- as the kernel package is locally-built and not available from the Mobian
repository, it is copied under a subfolder and imported to the rootfs
using the
overlay
action, then manually installed using arun
action - no package is installed for
phosh
as we want to create a minimal system.
- as the kernel package is locally-built and not available from the Mobian
repository, it is copied under a subfolder and imported to the rootfs
using the
- the global
packages-base.yaml
sub-recipe is modified to always includeopenssh-server
, which is pretty much a requirement for a headless system. - the most important changes lie in the
rootfs.yaml
recipe:- use the
debian-ports
archive when building for theriscv64
architecture; as this archive uses different GPG keys than the main Debian archive, we use the relevant key file from the host system (this requires first installing thedebian-ports-archive-keyring
package on the host system). - as
debootstrap
won’t install it, we install thedebian-ports-archive-keyring
package to the rootfs so it can be updated over time. - we drop the
packages-$environment
sub-recipe (minimal system, remember?)
- use the
With those changes, building the image is as simple as running
./build.sh -t riscv64
. It can then be flashed to a microSD and should bring
you a fully functional Debian/Mobian system on your VisionFive 2 :)
Note: we could have easily made it a “pure” Debian image, however we carry a
patched version of u-boot-menu
which simplifies the image generation process
a lot.
Final words
This process can probably easily be replicated for PINE64’s
Star64
once it becomes available, as both boards use the same SoC. Likewise, this
experiment can and will be re-used as the first step towards proper riscv64
support in Mobian, hopefully in a not-so-distant future ;)
We hope this article will also highlight how building and/or using flexible and powerful tools can greatly help expanding a project’s features set, and can even be used for only remotely-related tasks. It also shows how “easy” it can be to create Debian-based images for embedded systems (as opposed to, for example, having to re-compile the whole world twice using Yocto ;) ).
Finally, we want to point out how such things can only happen in the FLOSS world:
- being able to build each package from source is what makes the Debian ports initiative possible at all
- the vendor publishing the source code to the bootloader and kernel allowed us to build those with the needed options to fulfill our needs
- anyone (with decent knowledge of Linux systems internals) can build their own image easily, adding or removing packages and tweaks as they see fit, rather than being stuck with a generic (and probably bloated) third-party image.