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:

  1. a bootloader
  2. a kernel which includes support for this specific device
  3. 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 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 script is modified to support a new riscv64 device (it could/should probably have been named vf2, but remember this is only a quick and dirty experiment), using the riscv64 architecture and fetching its device-specific recipes from devices/riscv64
  • the devices/riscv64 is mostly a copy from devices/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 a run action
    • no package is installed for phosh as we want to create a minimal system.
  • the global packages-base.yaml sub-recipe is modified to always include openssh-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 the riscv64 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 the debian-ports-archive-keyring package on the host system).
    • as debootstrap won’t install it, we install the debian-ports-archive-keyring package to the rootfs so it can be updated over time.
    • we drop the packages-$environment sub-recipe (minimal system, remember?)

With those changes, building the image is as simple as running ./ -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.