Installing Ubuntu Server on the StarFive VisionFive 2
A Step-by-Step guide to installing Ubuntu on RISC-V
In the evolving landscape of computer architectures, bringing familiar operating systems to new platforms presents a unique set of challenges. A recent endeavour of mine involved installing Ubuntu Server on the StarFive VisionFive 2 RISC-V board.
Unlike the straightforward installation process we're accustomed to with more mainstream architectures, this task required delving into the nuances of UEFI bootloader configurations and intricately managing the board's boot process.
This blog post is a deep dive into that journey, aiming to demystify the steps needed to achieve a stable and functional Ubuntu setup on this emerging architecture.
⚠️ Before you begin, your VisionFive 2 board will need to be running the latest firmware. For a guide on how to do this, check out my previous blog post ⚠️
Hardware you will need:
A MicroSD card (8GB+)
NVME SSD (installed on the underside of the VisionFive 2 board)
USB to UART dongle
- Ubuntu Server Installer (choose the StarFive VisionFive 2 option, then download the "live installer"
✅ Board Setup
Flash the installer to the MicroSD card using Etcher and insert it into the MicroSD slot of the board.
Set the DIP switches to set the Boot Mode to
Finally, set up the UART to USB connection. I have been using the Raspberry Pi Debug Probe which works great. Connect the UART leads to the board as follows:
Pin 6 ->
Pin 8 ->
Pin 10 ->
Next, you need to connect to the serial terminal. If you are using macOS for example, the serial device will show with a prefix of
tty.usbmodem, so you can search for it with the command:
ls /dev | grep tty.usb
Then initialise a connection to it using
sudo picocom -b 115200 /dev/tty.usbmodem2112402
Now we are ready to install Ubuntu!
👢Booting the Ubuntu Installer
To successfully boot the installer on the StarFive VisionFive 2 board, we must first identify the appropriate MicroSD Card and manually load essential files using U-Boot commands. Unlike more conventional systems where this process might be automated, the Ubuntu Installer for this specific RISC-V architecture requires direct intervention through the serial console. This step is crucial for initiating the installation process.
Firstly, power on the VisionFive board and interrupt the boot process when we see the following:
Hit any key to stop autoboot: 2
We start by listing all available memory cards with
mmc list to see what options we have:
StarFive # mmc list
In this case, we can see two devices listed; however, only one will be the MicroSD card with the installer on it. We can use the
part list command to probe the device for partitions, and from there, determine which device and partition we need.
Let's examine the first device:
StarFive # part list mmc 0
Card did not respond to voltage select! : -110
Any time you see
Card did not respond to voltage select! : -110, this generally means the device does not exist, or is not valid. So in this case we need to inspect the device with ID
StarFive # part list mmc 1
Partition Map for MMC device 1 -- Partition Type: EFI
Part Start LBA End LBA Name
1 0x0000a000 0x0003efff "EFI System"
2 0x0003f000 0x0063efff "Live Media"
3 0x00000022 0x00000821 "loader1"
4 0x00000822 0x00002821 "loader2"
5 0x0063f000 0x0e81f7ff ""
We are looking for the
EFI System partition, which in this case is partition number
1 of device
Next, we load a crucial hardware configuration file called the Device Tree Blob (DTB) from the the
EFI Partition of the MicroSD Card (
mmc 1:1) into the system's memory using the
load command as below:
load mmc 1:1 $fdt_addr_r dtb/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb
Following that, we also load the RISC-V Linux kernel, located in an EFI file, into memory using the
load mmc 1:1 $kernel_addr_r EFI/boot/bootriscv64.efi
You will know the
load command has run successfully if you see a message in the format of
12345 bytes read in 10 ms.
Finally, we initiate the boot process with the
bootefi $kernel_addr_r $fdt_addr_r
This uses the loaded kernel and hardware configuration file to start up the installer. This sequence of commands essentially prepares the system and directs it to boot up from the specified files located on the memory card.
If successful, after a few seconds you should be greeted with the GRUB bootloader screen:
Hit enter, or wait 30s, to proceed to the installer.
⚙️ Running Through the Installer
The installer can take a few minutes to run through the boot process and can, at times, appear to hang, but just let it run and it will eventually show you the following screen:
From this menu, you can continue working with the installer via the serial console in either
basic mode. However, personally I found it easier, and more reliable, to use the SSH method. If you choose this method, you will be provided instructions on how to access the installer over SSH:
Once you SSH in, you will see the standard Ubuntu Server installer program:
The rest of the installer is the same as any other system, so work through it and configure the installation to your needs. Be sure to install Ubuntu on the NVME drive when prompted for the disk configuration - this will likely be the default option.
Once installed, let the device reboot automatically and move on to the final stage of configuring Ubuntu on the StarFive 2 board.
🥾Booting Ubuntu on NVME
Once the board reboots, you will likely be greeted with error messages in the serial console and Ubuntu will not boot automatically from the NVME drive:
Retrieving file: /extlinux/extlinux.conf
Can't set block device
Error reading config file
Don't panic, this is normal! In most systems, the Ubuntu installer will automatically configure UEFI variables to tell the bootloader how to boot into GRUB, however, U-Boot does not allow operating systems to configure these directly. So, we will have to do this manually.
Once the board has hit the error, it should drop you into the U-Boot prompt. From here you can run commands to boot Ubuntu manually:
efidebug boot add -b 0001 'Ubuntu' nvme 0:1 /EFI/ubuntu/grubriscv64.efi
efidebug boot order 0001
We first enumerate the PCI devices on the board with
pci enum, then we use
nvme scan to identify and prepare any connected NVMe drives for use, allowing the system to recognize and interact with them.
Next, we need to add a UEFI boot entry with
efidebug boot add. In this case, we are setting boot entry
1 and pointing it to the NVME drive with
nvme 0:1 and finally pointing it to the EFI executable
We then set the boot order with
efidebug boot order and then use
bootefi bootmgr to boot the system using the UEFI boot manager. This will attempt to boot from the boot entries in the order they are set in the UEFI configuration, starting with the entry you specified (
0001 in this case).
🔄 Getting Ubuntu to Boot Automatically from NVME
This above commands will boot Ubuntu fine every time, but this will not "stick" and the next time you boot the board you will face the same error and the OS will not load automatically. So just how do we achieve automatic boots?
Once again, we need to drop into the U-Boot console. This time we can set some UEFI environment variables to store the commands and run them automatically each time the board is booted:
env default -f -a
setenv bootcmd_nvme0 "pci enum; nvme scan; efidebug boot add -b 0001 'Ubuntu' nvme 0:1 /EFI/ubuntu/grubriscv64.efi; efidebug boot order 0001; bootefi bootmgr"
setenv bootcmd 'run bootcmd_nvme0'
First, we clear any existing variables to ensure a clean slate. Afterwards, we bundle the chain of commands into the
bootcmd_nvme0 variable for use later.
Then we point the
bootcmd variable to run our custom boot command. The
bootcmd variable defines the series of commands that U-Boot will automatically execute during the boot process. Essentially, it's the default action that U-Boot will take unless interrupted or directed otherwise.
Finally, save the variables and you are good to go!
The support for this board and RISC-V is still early for Ubuntu and certain things, such as HDMI output, may not be functional at the time of writing this. I suggest accessing the device through the serial console first, enabling SSH and going from there.
In summary, installing and running Ubuntu on the StarFive VisionFive 2 board is a journey through the intricacies of U-Boot/UEFI, highlighting the adaptability required when working with emerging architectures.
By manually configuring the UEFI boot process, we can successfully navigate these hurdles and get our favourite distros up and running. This process not only underscores the importance of a solid foundational understanding of system boot mechanisms but also opens the door to the vast potential of RISC-V boards in the world of Linux computing.
Have you ventured into installing operating systems on unconventional architectures like RISC-V? Do you have experiences, insights, or questions about running Ubuntu on the StarFive VisionFive 2 or similar boards? I’d love to hear about your journey and any challenges or triumphs you’ve encountered along the way. Feel free to share in the comments below or reach out to me on Mastodon!