DebianOn is an effort to document how to install, configure and use Debian on some specific hardware. Therefore potential buyers would know if that hardware is supported and owners would know how get the best out of that hardware.

The purpose is not to duplicate the Debian Official Documentation, but to document how to install Debian on some specific hardware.

If you need help to get Debian running on your hardware, please have a look at our user support channels where you may find specific channels (mailing list, IRC channel) dedicated to certain types of hardware.

Translation(s): none

Models covered
?StarFive ?VisionFiveV1

Overall Status

Core Components

[ATTACH]

Boot Standard Kernel:

{?}

LAN network card ():

{OK}

Detect hard drives (microSD/NVMe):

{OK}

Xorg

[?]

Extra Features

CPU Frequency Scaling

[?]

Hibernation

[?]

Sleep / Suspend

[?]

Power Off / Reboot

{OK}

Legend :
{OK} = OK ; {X} Unsupported(No Driver) ; /!\ = Error (Couldn't get it working); [?] Unknown, Not Test ; [-] Not-applicable
{i} = Configuration Required; X-( = Only works with a non-free driver and or firmware

Important Note

There are no official Debian images available yet.

Boot process overview

The full boot process is documented in the official documentation. This guide is focused on getting u-boot to boot the Linux kernel.

The board comes with the u-boot bootloader flashed on the internal SPI flash. This u-boot first tries to load the file /boot/uEnv.txt from the third partition of the SD card, allowing to customize the boot process. It then implements the "generic distro" concept of u-boot.

Unfortunately, as of May 2022 (U-Boot 2022.04-rc2-?VisionFive built on Mar 07 2022 - 21:12:22 +0800), the bundled u-boot on the board doesn't do anything except loading the uEnv.txt file, because it's missing a built-in definition of "bootcmd". That is, the uEnv.txt file is currently mandatory and needs to specify how to boot. It also needs to define load addresses for the kernel, FDT, and/or EFI image. See https://github.com/starfive-tech/u-boot/pull/31 and https://github.com/starfive-tech/u-boot/pull/32 for patches fixing these issues.

In any case, u-boot can boot Linux using two main methods:

  1. either it can load an extlinux.conf file describing which kernel/FDT/initrd images to boot, load all three images, and boot the kernel directly. This fits the "generic distro" model.

  2. or it can load an EFI image, typically grub, and delegate the boot process to this second bootloader. Like in the previous case, u-boot will scan partitions to find an EFI image at a specific location (/efi/boot/bootriscv64.efi).

In the long term, using EFI is the preferred and more standard way. However, Debian currently lacks the tooling to make this a straightforward option. The other option, the "legacy" extlinux.conf method, is well integrated in Debian, so it is currently easier to setup. Both options are documented below.

Installing Debian on VisionFive V1

As described above, two boot options are presented in this guide: either using u-boot directly or using a Grub EFI image.

Most of the steps are common for the two options.

Build the kernel

# Install prerequisites on the host machine
sudo apt install libncurses-dev libssl-dev bc flex bison make gcc gcc-riscv64-linux-gnu

# Download and extract latest StarFive JH7100 sources
wget https://github.com/starfive-tech/linux/archive/refs/heads/visionfive.tar.gz
tar xf visionfive.tar.gz

# build the kernel
cd linux-visionfive/
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- starfive_jh7100_fedora_defconfig
nice make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc) bindeb-pkg LOCALVERSION=-starfive

While the kernel is compiling, you can proceed with the next steps.

Bootstrap the root filesystem

This step will bootstrap a minimal RISC-V root filesystem in /tmp/riscv-chroot, which can later be copied to the SD card. This is much faster than bootstrapping directly on the SD card.

# Install prerequisites on host:
sudo apt install qemu-user-static binfmt-support debootstrap debian-ports-archive-keyring systemd-container rsync wget

# The command below will bootstrap debian
sudo debootstrap --arch=riscv64 unstable /tmp/riscv-chroot https://deb.debian.org/debian

# If you get an error "Unable to execute target architecture", try the following process instead:
sudo debootstrap --foreign --arch=riscv64 unstable /tmp/riscv-chroot http://deb.debian.org/debian
sudo mkdir -p /tmp/riscv-chroot/usr/bin/
sudo cp "$(which qemu-riscv64-static)" /tmp/riscv-chroot/usr/bin/
sudo chroot /tmp/riscv-chroot/ /debootstrap/debootstrap --second-stage

While debootstrap is working, you can proceed with the next step.

Create partitions and filesystems

We need to create several partitions on the SD card:

If you want to use a separate boot partition, be aware that it's possible but not straightforward. See "Tips to handle a separate /boot partition" at the end of this page.

We use a GPT partition table to be future-proof, but it could work with a DOS partition table.

# These instructions assume that your microSD card is at /dev/mmcblk0
# The following command will automatically setup all partitions.
# Be careful, it doesn't ask any confirmation!
sudo sgdisk -g --clear --new=1:0:+16M: --new=2:0:+100M: -t 2:EF00 --new=3:0:-1M: --attributes 3:set:2 -d 1 /dev/mmcblk0

# If you choose to create the partitions manually with gdisk, don't
# forget to set the "legacy BIOS bootable" flag on partition 3
# (go to advanced menu, then "set attributes", select partition, and set flag 2)                                                                                                                                                                                      

# You can double check your work with:
fdisk -l /dev/mmcblk0

# Next, prepare the filesystems
sudo mkfs.vfat /dev/mmcblk0p2
sudo mkfs.ext4 -m 0 -L root /dev/mmcblk0p3

# Prepare mountpoint for EFI filesystem in the temporary debian rootfs
sudo mkdir -p /tmp/riscv-chroot/boot/efi

Copy kernel packages

Once the kernel has finished compiling, you need to copy the resulting packages in the chroot:

# Run this from the directory where you compiled the kernel
sudo cp ../*.deb /tmp/riscv-chroot/root/

Configure Debian

At this point, you must wait for debootstrap to finish bootstrapping the Debian root filesystem. Then you can enter the chroot and configure the system:

# Now enter the chroot and ensure that the package db is up to date
sudo systemd-nspawn -D /tmp/riscv-chroot/ -M debian --bind-ro=/etc/resolv.conf
apt update
apt upgrade

# Install initramfs tools, SSH server, NTP client, and various utils
apt install initramfs-tools openssh-server systemd-timesyncd rsync bash-completion

# Clean downloaded packages
apt clean

# Install kernel packages
apt install ./linux-*.deb

# Configure u-boot
# This should eventually become unnecessary, see:
# https://github.com/starfive-tech/u-boot/pull/31
# https://github.com/starfive-tech/u-boot/pull/32
cat <<EOF > /boot/uEnv.txt
fdt_high=0xffffffffffffffff
initrd_high=0xffffffffffffffff
kernel_addr_r=0x84000000
kernel_comp_addr_r=0x90000000
kernel_comp_size=0x10000000
fdt_addr_r=0x88000000
ramdisk_addr_r=0x88300000
# Move DHCP after MMC to speed up booting
boot_targets=mmc0 dhcp
# Fix wrong fdtfile name
fdtfile=starfive/jh7100-starfive-visionfive-v1.dtb
# Fix missing bootcmd
bootcmd=run distro_bootcmd
EOF

# Configure fstab
cat <<EOF > /etc/fstab
/dev/mmcblk0p2 /boot/efi vfat umask=0077 0 1
EOF

# Configure network
cat <<EOF >> /etc/network/interfaces
allow-hotplug eth0
iface eth0 inet dhcp
EOF

# Set root password
passwd

# Change hostname
echo visionfive > /etc/hostname

# sync disks
sync

# exit chroot
exit

Option 1: legacy u-boot through extlinux.conf

With this method, we need to create an extlinux configuration file that will be parsed by u-boot.

During normal operation, the configuration is generated automatically by u-boot-menu. But it doesn't work correctly in a chroot, so we need to fix it manually.

# Enter chroot again
sudo systemd-nspawn -D /tmp/riscv-chroot/ -M debian --bind-ro=/etc/resolv.conf

# Install u-boot-menu
apt install u-boot-menu

# Uncomment U_BOOT_PARAMETERS in /etc/default/u-boot and set it to the following:
# U_BOOT_PARAMETERS="rw console=tty0 console=ttyS0,115200 earlycon rootwait stmmaceth=chain_mode:1 selinux=0"
vi /etc/default/u-boot

# Re-run kernel postinstall hooks
dpkg-reconfigure linux-image-5.18.0-starfive

# Verify extlinux configuration was generated
cat /boot/extlinux/extlinux.conf

# Fix root parameter in extlinux configuration
sed -i -e 's|root=[^ ]*|root=/dev/mmcblk0p3|' /boot/extlinux/extlinux.conf

# exit chroot
exit

Finishing steps on the host:

# Copy the content of the chroot to the SD card
sudo mkdir -p /mnt/sdcard
sudo mount /dev/mmcblk0p3 /mnt/sdcard
sudo cp -a /tmp/riscv-chroot/* /mnt/sdcard/

# Make sure everything is really written (can take a long time)
sync

umount /mnt/sdcard

The SD card should now boot correctly on the ?VisionFive.

Option 2: EFI with grub

With this option, we setup a grub EFI image on the EFI System Partition at the standard path "EFI/boot/bootriscv64.efi". This image will be detected and booted by u-boot.

Unfortunately, Debian is not yet capable of generating a RISC-V grub image. For now, we have to copy it from the Fedora image provided by ?StarFive.

First, configure grub:

# Add a symlink from /grub.cfg to /boot/grub.cfg
# This is a workaround because the Fedora grub image only looks at /grub.cfg
ln -s boot/grub.cfg /tmp/riscv-chroot/grub.cfg

# Write a basic grub.cfg configuration
# You should adapt the paths depending on kernel version
sudo tee /tmp/riscv-chroot/boot/grub.cfg <<EOF
set default=0
set timeout_style=menu
set timeout=2

set debug="linux,loader,mm"
set term="vt100"

menuentry 'Debian kernel 5.18 for visionfive' {
    linux /boot/vmlinuz-5.18.0-starfive root=/dev/mmcblk0p3 rw console=tty0 console=ttyS0,115200 earlycon rootwait stmmaceth=chain_mode:1 selinux=0
    devicetree /usr/lib/linux-image-5.18.0-starfive/starfive/jh7100-starfive-visionfive-v1.dtb
    initrd /boot/initrd.img-5.18.0-starfive
}
EOF

Then, if you already have a SD card with a Fedora image on it, you can just copy the grub image from it:

# Insert Fedora SD card

# Mount EFI partition of Fedora SD card
sudo mkdir -p /mnt/fedora-efi
sudo mount /dev/mmcblk0p2 /mnt/fedora-efi

# Copy EFI grub image somewhere, then unmount partition
sudo cp /mnt/fedora-efi/EFI/fedora/grubriscv64.efi /tmp/
sudo umount /mnt/fedora-efi

# Insert Debian SD card, then mount EFI partition
sudo mount /dev/mmcblk0p2 /tmp/riscv-chroot/boot/efi

# Copy EFI grub image to final destination, then umount partition
sudo mkdir -p /tmp/riscv-chroot/boot/efi/EFI/boot
sudo cp /tmp/grubriscv64.efi /tmp/riscv-chroot/boot/efi/EFI/boot/bootriscv64.efi
sudo umount /tmp/riscv-chroot/boot/efi

Alternatively, if you don't have a Fedora SD card, you need to download the ?StarFive Fedora image and extract the file from it:

# You will need some files from the official StarFive Fedora image.
# Open a terminal on the host machine and download the image from here:
# https://github.com/starfive-tech/Fedora_on_StarFive

# Extract the Fedora image
sudo apt install zstd
zstd -d  Fedora-riscv64-jh7100-developer-xfce-Rawhide-20211226-214100.n.0-sda.raw.zst

# Examine the partitions. Note the partition start locations and units
fdisk -u -l Fedora-riscv64-jh7100-developer-xfce-Rawhide-20211226-214100.n.0-sda.raw

# Mount the partition numbered 2 of the image as follows.
# Compute the offset by multiplying (units * start)
# For example, if the start is 69632 and units is 512 bytes, then (69632 * 512) = 35651584
# Use this offset value to mount the second partition:
sudo mkdir -p /mnt/fedora-efi
sudo mount -o loop,offset=35651584 Fedora-riscv64-jh7100-developer-xfce-Rawhide-20211226-214100.n.0-sda.raw /mnt/fedora-efi

# Mount EFI partition of Debian SD card
sudo mount /dev/mmcblk0p2 /tmp/riscv-chroot/boot/efi

# Now we can copy the grub image from Fedora
sudo mkdir -p /tmp/riscv-chroot/boot/efi/EFI/boot
sudo cp /mnt/fedora-efi/EFI/fedora/grubriscv64.efi /tmp/riscv-chroot/boot/efi/EFI/boot/bootriscv64.efi

# Unmount Debian EFI partition
sudo umount /tmp/riscv-chroot/boot/efi

# Unmount the Fedora partition
sudo umount /mnt/fedora-efi

Run final steps:

# Copy the content of the chroot to the SD card
sudo mkdir -p /mnt/sdcard
sudo mount /dev/mmcblk0p3 /mnt/sdcard
sudo cp -a /tmp/riscv-chroot/* /mnt/sdcard/

# Make sure everything is really written (can take a long time)
sync

umount /mnt/sdcard

The SD card should now boot correctly on the ?VisionFive. To verify if Debian is correctly booted through EFI, you can check if the path "/sys/firmware/efi/" exists on the running system.

Tips to handle a separate /boot partition

In case you want to use a separate boot partition, here are some tips to make it work:

Synchronizing DTBs automatically

There is a small script that automatically synchronizes DTBs to the boot partition each time you install or update a kernel.

First, make sure rsync is installed in the rootfs on the SD card. Then, assuming your rootfs is at "/mnt/sdcard" and the boot partition is mounted:

# If you used option 1 (extlinux.conf generated by u-boot-menu)
cp /mnt/sdcard/usr/share/doc/u-boot-menu/examples/zz-sync-dtb /mnt/sdcard/etc/kernel/postinst.d/zz-sync-dtb
chmod +x /mnt/sdcard/etc/kernel/postinst.d/zz-sync-dtb

# If you used option 2 (grub EFI image)
wget -O /mnt/sdcard/etc/kernel/postinst.d/zz-sync-dtb https://sources.debian.org/data/main/u/u-boot-menu/4.0.4/zz-sync-dtb
chmod +x /mnt/sdcard/etc/kernel/postinst.d/zz-sync-dtb

# In all cases, perform a manual initial sync (adapt kernel version)
mkdir -p /mnt/sdcard/boot/usr/lib/linux-image-5.18.0-starfive
rsync -a /mnt/sdcard/usr/lib/linux-image-5.18.0-starfive/. /mnt/sdcard/boot/usr/lib/linux-image-5.18.0-starfive/.

For option 1, make sure that "/boot/extlinux/extlinux.conf" has a line such as "fdtdir /usr/lib/linux-image-5.18.0-starfive/". If this is not the case, chroot and run "u-boot-update".

For option 2, make sure your "/boot/grub.cfg" has something like "devicetree /usr/lib/linux-image-5.18.0-starfive/starfive/jh7100-starfive-visionfive-v1.dtb"

Updating the kernel

To udpate the kernel, you need to:

The rest should work automatically (DTB synchronisation, extlinux.conf generation for the legacy boot method)