Orange Pi RV - My new Risc V NAS

I got myself a new toy. Yet another Risc V SBC! I already have a VisionFive 2 that is serving as a "virtualisation platform" (running several containers) and now I wanted to redo my NAS setup and as I have my drives connected via USB, I was looking for a board with at least 4 USB 3.0. I was thinking some cheap ARM board but than I saw that Orange Pi has RV board. It is same SoC as my VisionFive and device tree is in vanilla kernel starting 6.19. What more to ask for? I ordered it right away and now I have it at home.

Orange Pi RV board

Specs

Let’s start with what I ordered. My intention is to re-build a simple NAS with USB attached drives. That means, I don’t need ton of RAM, 90 cores et cetera. Orange Pi RV offers 4 USB 3.0 ports and one gigabit Ethernet interface. It is running on top of quad-core JH7110 CPU up to 1.5 GHz. From the features that I will not use, it has M.2 PCIe slot (I’m using that one for NVMe on my VisionFive 2), HDMI and Wi-Fi 4.

StarFive JH7110 CPU

Geeting it running

Somehow

I had some issues getting it running. I was worried, that the device is broken. But after quite some time, I chickened out and started to search for a user manual. It was tricky, as the official web site didn’t work. But luckily, there was a copy in the internet archive and used manual was a PDF on Google drive. And there I found what I was doing wrong. Contrary to all other SBC I have, you actually have to turn the device on for it to start doing anything. Connecting power source doesn’t trigger any action.

Getting rootfs

After figuring this thing out, the way forward was much smoother. Device has an SPI NOR from which it can boot and it actually has U-Boot burned in from the factory. So the only thing I was missing was a rootfs. From the internet archive I found also the originally supplied rootfs. It booted and worked, but I wanted to run openSUSE, so after a little bit of testing of provided Debian, I started working on that.

openSUSE

At the moment I was trying to get device running, there was only 6.18 kernel in Tumbleweed. And as I said, the board is supported since 6.19 kernel. Bummer. It probably would have worked with just a device tree from a newer kernel, but that sounded messy. I found a better solution. There is a StarFive devel project in OBS including images. Downside is that these are ext4 based and I use Btrfs everywhere. Another problem is that they don’t work with U-Boot in the NOR. They used openSUSE way of booting SBC. That means that they expect U-Boot will run EFI boot to load Grub and then Grub will load system.

The included U-Boot didn’t even tried EFI boot. When I tried it manually, it loaded grub, but grub ended with some memory error. Since I wanted to redo the image anyway, I decided to opt in for a simpler solution.

Making it boot

I created a new partition layout on my uSD card by myself. I created one 500M FAT32 partition, so I could potentially migrate to Grub setup. But I put device tree and kernel there. As well as initramdisk. But I had to convert it to a format U-Boot understands. That was easy:

mkimage -A riscv -T ramdisk -C none -n uInitrd -d ../initrd-6.19.0-rc4-198-default uInitrd

All that was left was to instruct U-Boot how to find kernel and initramdisk. I used extlinux for that as I find it the simplest one. This is content of my /boot/efi/extlinux/extlinux.conf

label Orange Pi
  kernel /Image
  initrd /uInitrd
  fdt /dtb/starfive/jh7110-orangepi-rv.dtb
  append root=UUID=b3f4e6dc-0487-423a-8469-7b09b7932c88 rootflags=subvol=/@ console=tty0 console=ttyS0,115200 earlycon rootwait

Keeping it booting

Manual setup has a disadvantage. I have to keep content of my EFI partition in sync with the rest of the system. I wrote a simple shell script for that.

#!/bin/sh
SYS_KERNEL="$(md5sum /boot/Image | cut -f 1 -d ' ')"
SYS_INITRD="$(md5sum /boot/initrd | cut -f 1 -d ' ')"
if [ "${SYS_KERNEL}" != "$(cat /boot/efi/Image.md5)"  ]; then
        cp -r /boot/dtb/starfive /boot/efi/dtb
        cp -L /boot/Image /boot/efi/Image
        echo "${SYS_KERNEL}" > /boot/efi/Image.md5
fi
if [ "${SYS_INITRD}" != "$(cat /boot/efi/initrd.md5)" ]; then
        mkimage -A riscv -T ramdisk -C none -n uInitrd -d /boot/initrd /boot/efi/uInitrd
        echo "${SYS_INITRD}" > /boot/efi/initrd.md5
fi

Sometimes ramdisk changes because something got updated, but if kernel changed, ramdisk has to change. Because of the included kernel modules. So the only thing I need to monitor for is for ramdisk changes. And ramdisks live in /boot. I decided to leverage systemd path activation.

Wrote a unit file:

[Unit]
Description=Updates kernel and initramdisk on FAT partition

[Service]
Type=simple
ExecStart=/root/update_boot

[Install]
WantedBy=multi-user.target

And the path file:

[Unit]
Description=Monitor the new kernel

[Path]
PathChanged=/boot
Unit=update_boot.service

[Install]
WantedBy=multi-user.target

Now systemd will make sure that my ramdisk is always up to date.

Non-oss repo

One tricky part about running openSUSE was that I was missing some packages. Because the image I used contained only oss repo and some tools are not part of it. Namely nmap. Took me a while to find a URL to add. So just in case, here is how I fixed it.

zypper ar -f \
    https://download.opensuse.org/repositories/openSUSE:/Factory:/RISCV:/NonFree/standard/ \
    repo-non-oss

Fixing the Wi-Fi

Orange Pi RV Wi-Fi chip

There is an onboard Wi-Fi on that Orange Pi. It is AP6256. But underneath, it is a Broadcom and it was just missing a firmware. Luckily I was able to find one in LibreELEC repository. So I downloaded it, rebooted and Wi-Fi started working right a way :-)

wget -O /lib/firmware/brcm/brcmfmac43456-sdio.xunlong,orangepi-rv.bin \
    https://github.com/LibreELEC/brcmfmac_sdio-firmware/raw/refs/heads/master/brcmfmac43456-sdio.bin
wget -O /lib/firmware/brcm/brcmfmac43456-sdio.txt \
    https://github.com/LibreELEC/brcmfmac_sdio-firmware/raw/refs/heads/master/brcmfmac43456-sdio.txt

"Fixing" the power button

The current through the power on switch when pressed is 0,75 mA. And if I press it and keep it pressed, the board still boots up and keeps running. So the solution for board to automatically boot up whenever the power is turned on (one of the "features" I need from NAS) was easy. Just connecting the pins on the board. Just to be safe, I used 200 Ω resistor. And it works.

Resistor keeping button pressed

Basic benchmarks

As my intended usage is NAS, I was wondering how fast will it be. I run cryptsetup benchmark. Here are the results (from openSUSE image, but the original Debian didn’t differ that much).

#     Algorithm |       Key |      Encryption |      Decryption
        aes-cbc        128b        27.1 MiB/s        27.6 MiB/s
    serpent-cbc        128b        17.4 MiB/s        19.8 MiB/s
    twofish-cbc        128b        28.2 MiB/s        28.9 MiB/s
        aes-cbc        256b        21.0 MiB/s        21.2 MiB/s
    serpent-cbc        256b        17.6 MiB/s        19.6 MiB/s
    twofish-cbc        256b        28.5 MiB/s        30.8 MiB/s
        aes-xts        256b        31.5 MiB/s        30.5 MiB/s
    serpent-xts        256b        20.7 MiB/s        21.2 MiB/s
    twofish-xts        256b        33.6 MiB/s        31.4 MiB/s
        aes-xts        512b        22.4 MiB/s        22.4 MiB/s
    serpent-xts        512b        20.4 MiB/s        21.5 MiB/s
    twofish-xts        512b        31.1 MiB/s        30.9 MiB/s

After getting it running I connected all four of my USB 3.0 3,5" 5400 rpm drives, encrypted using AES-XTS with Btrfs on top of them in RADI1 mode and compression enabled (zstd). And I started scrubbing. Speed of scrub was pretty consistent.

Rate:             69.77MiB/s

It is not the fastest NAS out there, but for intended usage, it is good enough and improvement over previous setup (all drives connected through one unstable USB HUB). So I’m happy in the end :-)