format_list_bulleted

ArchLinux on Spacemit K1 RISC-V Processor

dark_mode
ArchLinux on Spacemit K1 RISC-V Processor
The most full tutorial about running ArchLinux on Spacemit K1.
archlinux
riscv
visibility -- public -- group --

NOTE for lazy person: I’ve packed the ROM package for eMMC with

  • Kernel 6.1.15 version: Build the images as following by yourself if you want newer.
  • /boot/bianbu.bmp is the boot splash image of ArchLinux
  • /etc/resolve.conf with nameserver 1.1.1.1
  • /etc/systemd/network/0-end.network with DHCP configuration set up

[!TIP] You’d better to build it by yourself for better customization.

Build the images by yourself

Felix Yan’s wiki about the ArchLinux RISC-V porting.

postmarketOS Wiki about Banana Pi F3 with Spacemit K1 SoC.

Banana Pi forum question about booting with root filesystem on NVMe.

Make the ext4 rootfs image

Download the ArchLinux RISC-V porting rootfs archive here.

# Allocate image file. Count defined by your eMMC free size.
dd if=/dev/zero of=rootfs.ext4 bs=1G count=14

# Copy file system tree.
mkfs.ext4 rootfs.ext4
mount rootfs.ext4 /mnt
cp -rp .../archriscv/* /mnt/
umount /mnt

Modify the fstab

The rootfs may will be mounted as read-only due to filesystem check. If it happens, remount it with option -o rw,remount then modify the fstab.

/dev/mmcblk2p5 /boot ext4 defaults,nofail 0 0
/dev/mmcblk2p6 /     ext4 defaults,rw     0 0

Replace boot splash image (optional)

The splash image file is in the BMP bitmap format by Microsoft and location specified by the variable defined under U-Boot: splashfile which is usually bianbu.bmp on bootfs.ext4.

Fetch the U-Boot and kernel

Download the Bianbu distro image archive at archive.spacemit.com. I chose this.

[!NOTE]

Different release version has different kernel version.

It looks like:

.
├── bootfs.ext4
│     ^ /dev/mmcblk2p5
├── env.bin
├── factory
│        ├── bootinfo_emmc.bin
│        ├── bootinfo_sd.bin
│        ├── bootinfo_spinand.bin
│        ├── bootinfo_spinor.bin
│        └── FSBL.bin
├── fastboot.yaml
├── fw_dynamic.itb
├── genimage.cfg
├── partition_2M.json
├── partition_flash.json
├── partition_universal.json
├── rootfs.ext4
│     ^ /dev/mmcblk2p6: The image to be replaced.
└── u-boot.itb

Replace the rootfs.ext4 with the image you made.

Kernel modules

Copy all modules under /lib/modules from Bianbu’s rootfs.ext4 image to ArchLinux’s.

Some Bianbu releases does not contain kernel modules such as [ btrfs, xfs ] in the init ramdisk. Instead, they are stored on root filesystem. So you can only use ext4 for your root filesystem unless you build the kernel that with the modules static-linked in.

U-Boot environment variables

Force U-Boot falling back to prompt by removing SD Card from slot while U-Boot is booting.

env print -a

Option: Specify the root filesystem such as partition on NVMe

[!TIP]

Spacemit’s firmware does not support boot from NVMe. The options are 「eMMC」「SDcard」and「NAND/NOR SPI flash」only.

If you want to specify which partition or device should the kernel mounts as root filesystem, you have to append the lines below before the end of /boot/env_k1-x.txt.

lets_boot=setenv bootargs earlyprintk quiet clk_ignore_unused swiotlb=65536 workqueue.default_affinity_scope=system earlycon=sbi console=ttyS0,115200n8 loglevel=8 rdinit=/init rootwait rootfstype=ext4 root=${ROOT_FS}
autoboot=run lets_boot; run detect_dtb; run loadknl; run loaddtb; run loadramdisk; run start_kernel;

Substitute ${ROOT_FS} with the target partition or device.

  • /dev/mmcblk2p6
  • /dev/nvme0n1p1

Example: Specify /dev/nvme0n1p1 as the root.

The root partition filesystem has to be ext4 because the initramfs does not contain kernel module for btrfs.

The kernel on /dev/mmcblk2p5 (which is from bootfs.ext4) will mount /dev/nvme0n1p1 as the root filesystem.

/dev/mmcblk2p5 ext4  /boot
/dev/nvme0n1p1 ext4  /
/dev/nvme0n1p2 btrfs /var

Troubleshooting

Q: The U-Boot env var and boot args does not work on other Bianbu release.

A: For other Bianbu release version, try checking the U-Boot environment variables and the related booting commands and make effective one.

Help: How to get the boot args?

It’s /proc/cmdline.

cat /proc/cmdline

Help: How to inspect U-Boot environment variables so that I can set correct boot args and command sequence?

Make sure your board can NOT boot from any boot options so that it will fallback to U-Boot shell.

# This command will print all env variables.
==> env print

Choice 1: Flashing to SD Card

Use the genimage to generate sdcard image.

# Installation, for NixOS user.
nix-shell -p genimage

# Generate image.
cd .../archriscv
ln -s . input
genimage

# Write to the microSD.
dd if=./images/...-sdcard.img of=/dev/mmcblk2 bs=4096 status=progress

Choice 2: Flashing to eMMC

The SoC will load one program, for processing packets from the host about firmware flashing.

The tool is flashing the target device via executing fastboot commands. You may have heard of it on Android.

Requires fastboot CLI utility.

Flash tool

The board supports flashing firmware in fastboot mode.

The utilities below are required:

fastboot

Connect to the board

Connect USB port on the board to your computer. It will show as a DFU device, and turn to U-Boot USB download gadget while flashing.

lsusb
Bus 001 Device 009: ID 361c:1001 U-Boot USB download gadget

Help: Allow unprivileged users to access the board on DFU mode

Make the users in the group plugdev able to access it.

nano /etc/udev/rules.d/99-spacemit.rules
SUBSYSTEMS=="usb", ATTR{idVendor}=="361c", ATTR{idProduct}=="1001", GROUP="plugdev", MODE:="0660"

Flash images

[!TIP]

For BPi-F3 board: Press and hold the [FDL] and [RST] buttons in order to enter firmware update mode.

fastboot stage factory/FSBL.bin
fastboot continue
fastboot stage u-boot.itb
fastboot continue
fastboot flash gpt partition_universal.json
fastboot flash bootinfo factory/bootinfo_sd.bin
fastboot flash fsbl factory/FSBL.bin
fastboot flash env env.bin
fastboot flash opensbi fw_dynamic.itb
fastboot flash uboot u-boot.itb
fastboot flash bootfs bootfs.ext4
fastboot flash rootfs rootfs.ext4

It takes about 100 seconds when the rootfs.ext4 image is 2GiB.

Enjoy!

To view the latest build status about RV64 porting of ArchLinux see archriscv.felixc.at/.status/status.htm.

ArchLinux is now available on your board.

Reset your board. ArchLinux will boot!

The password of root is archriscv by Felix Yan.

Start services

Network

systemctl enable --now systemd-networkd systemd-resolved

Time Sync

systemctl enable --now systemd-timesyncd

[!NOTE]

SSL connections only work with correct time.

Install packages

pacman -Syu
pacman -S nano openssh

Choose the best mirror

nano /etc/pacman.d/mirrorlist
##
## Arch Linux RISC-V repository mirrorlist
##

## Worldwide
Server = https://riscv.mirror.pkgbuild.com/repo/$repo

## Canada
#Server = https://archriscv.felixc.at/repo/$repo

## China
#Server = https://mirror.iscas.ac.cn/archriscv/repo/$repo
#Server = https://mirrors.sustech.edu.cn/archriscv/repo/$repo
#Server = https://mirror.nju.edu.cn/archriscv/repo/$repo
#Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

## Finland
#Server = https://mirrors.felixc.at/archriscv/repo/$repo

Desktop Environment

Recommend to enable GPU acceleration you’re going to see later.

KDE

pacman -S icu plasma-desktop plasma-nm plasma-pa plasma-workspace plasma-workspace-wallpapers xdg-desktop-portal-kde dolphin kate konsole okular spectacle
dbus-run-session startplasma-wayland

Xfce4

pacman -S icu xfce4 xorg
dbus-run-session startxfce4

GNOME

pacman -S gnome

Peripherals on Chip

[!TIP] This chapter is updated on 2025-12-21 and the content is available

In this chapter you have to download Bianbu Linux image for its proprietary userspace drivers.

Mount Bianbu ROM rootfs.ext4 to /bianbu or somewhere else.

Migrate programs and drivers designed for Bianbu Linux

[!TIP] These properietary programs and drivers will make you fully use its performance.

[!IMPORTANT] Assume that we mounted Bianbu Image / to /bianbu

Prepare

Now we have to remove loader and libc shared objects so that the Bianbu’s program won’t be linked with incompatible libc

cd /bianbu/lib

# Firmware
cp -r /bianbu/usr/lib/firmware /lib/

# Correct symlinks
rm ld-* libc.so* libblas.so* liblapack.so*
ln -s blas/lib* .
ln -s lapack/lib* .

# Codec
# IMPORTANT: its location MUST BE /lib/libv4l2_linlonv5v7_codec.so
# FFmpeg requires this codec plugin for h264_stcodec
ln -s /bianbu/lib/libv4l2_linlonv5v7_codec.so /lib/

# Vulkan
cp -r /bianbu/etc/dri /bianbu/usr/share/dri /usr/share/

# Libraries, Mesa/PowerVR Drivers, Spacemit MPP
# Override graphics libraries
ln -sf /bianbu/lib/lib*GL* /lib/
# Keep existing files
ln -s /bianbu/lib/lib*so*  /lib/

# Remove soft renderer
rm -f $(find /bianbu/lib/ | grep swrast) $(find /lib/ | grep swrast)

ldconfig

Useful scripts

/usr/local/bin/bianbu

And now we write a script /usr/local/bin/bianbu for invoking programs with correct environment variables including LD_LIBRARY_PATH

# /usr/local/bin/bianbu

#!/bin/fish

set -gx PATH /bianbu/bin:$PATH

set -gx LD_LIBRARY_PATH /bianbu/lib/riscv64-linux-gnu:/bianbu/lib

$argv

/usr/local/bin/bianbu-gl

And another variant bianbu-gl for GNOME GDM.

# /usr/local/bin/bianbu-gl

#!/bin/fish

set -gx PATH /bianbu/bin:$PATH

set -gx LD_LIBRARY_PATH /lib:/bianbu/lib/riscv64-linux-gnu:/bianbu/lib

$argv

And when we want to invoke ffmpeg provided by Bianbu, we type:

bianbu ffmpeg -codecs
DEV.LS h264   H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_stcodec) (encoders: h264_stcodec libx264 libx264rgb h264_v4l2m2m h264_vaapi h264_vulkan)

For gdm, we type:

bianbu-gl gdm

/bin/sh

You may meet missing symbol problems when your program invoking /bin/sh so we have to make /bin/sh as a agent. Remove the binary, and we will rewrite it:

# /bin/sh

#!/bin/fish

if test -z "$LD_LIBRARY_PATH"
	/bin/bash $argv
else
	/bianbu/bin/bash $argv
end

GPU

The SoC integrated Imagination BXE-2-32 with no opensource userspace driver.

You have to copy them from Bianbu Linux image.

Install Mesa

pacman -S mesa mesa-utils

[!WARNING] Mesa’s drivers WILL NOT work.

Use PowerVR’s userspace driver instead of Mesa’s

If there is SIGSEGV problem, they are probably caused by incompatible libraries.

Keep setting correct LD_LIBRARY_PATH for these programs.

It should print some information about your GPU like this:

bianbu eglinfo -B
GBM platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL_ES 
OpenGL ES profile vendor: Imagination Technologies
OpenGL ES profile renderer: PowerVR B-Series BXE-2-32
OpenGL ES profile version: OpenGL ES 3.2 build 24.2@6603887
OpenGL ES profile shading language version: OpenGL ES GLSL ES 3.20 build 24.2@6603887

Wayland platform:
eglinfo: eglInitialize failed

X11 platform:
eglinfo: eglInitialize failed

Surfaceless platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL_ES 
OpenGL ES profile vendor: Imagination Technologies
OpenGL ES profile renderer: PowerVR B-Series BXE-2-32
OpenGL ES profile version: OpenGL ES 3.2 build 24.2@6603887
OpenGL ES profile shading language version: OpenGL ES GLSL ES 3.20 build 24.2@6603887

Device platform:
Device #0:

Platform Device platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL_ES 
OpenGL ES profile vendor: Imagination Technologies
OpenGL ES profile renderer: PowerVR B-Series BXE-2-32
OpenGL ES profile version: OpenGL ES 3.2 build 24.2@6603887
OpenGL ES profile shading language version: OpenGL ES GLSL ES 3.20 build 24.2@6603887

Device #1:

Platform Device platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL OpenGL_ES 
OpenGL compatibility profile vendor: Mesa
OpenGL compatibility profile renderer: zink Vulkan 1.3(PowerVR B-Series BXE-2-32 MC1 (IMAGINATION_PROPRIETARY))
OpenGL compatibility profile version: 2.1 Mesa 24.0.1
OpenGL compatibility profile shading language version: 1.20
OpenGL ES profile vendor: Mesa
OpenGL ES profile renderer: zink Vulkan 1.3(PowerVR B-Series BXE-2-32 MC1 (IMAGINATION_PROPRIETARY))
OpenGL ES profile version: OpenGL ES 2.0 Mesa 24.0.1
OpenGL ES profile shading language version: OpenGL ES GLSL ES 1.0.16
bianbu vulkaninfo
==========
VULKANINFO
==========

Vulkan Instance Version: 1.4.304


Instance Extensions: count = 15
-------------------------------
VK_EXT_debug_report                    : extension revision 10
VK_EXT_debug_utils                     : extension revision 2
VK_EXT_headless_surface                : extension revision 1
VK_KHR_device_group_creation           : extension revision 1
VK_KHR_external_fence_capabilities     : extension revision 1
VK_KHR_external_memory_capabilities    : extension revision 1
VK_KHR_external_semaphore_capabilities : extension revision 1
VK_KHR_get_physical_device_properties2 : extension revision 2
VK_KHR_get_surface_capabilities2       : extension revision 1
VK_KHR_portability_enumeration         : extension revision 1
VK_KHR_surface                         : extension revision 25
VK_KHR_wayland_surface                 : extension revision 6
VK_KHR_xcb_surface                     : extension revision 6
VK_KHR_xlib_surface                    : extension revision 6
VK_LUNARG_direct_driver_loading        : extension revision 1

Instance Layers: count = 2
--------------------------
VK_LAYER_MESA_device_select Linux device selection layer 1.3.211  version 1
VK_LAYER_MESA_overlay       Mesa Overlay layer           1.3.211  version 1

Devices:
========
GPU0:
	apiVersion         = 1.3.277
	driverVersion      = 1.588.1135
	vendorID           = 0x1010
	deviceID           = 0x36052182
	deviceType         = PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
	deviceName         = PowerVR B-Series BXE-2-32 MC1
	driverID           = DRIVER_ID_IMAGINATION_PROPRIETARY
	driverName         = PowerVR B-Series Vulkan Driver
	driverInfo         = 24.2@6603887
	conformanceVersion = 1.3.8.1
	deviceUUID         = 33362032-3920-1234-1234-123400000000
	driverUUID         = 36363033-3838-1234-0000-000000000000

systemd service

For GDM, modify this row:

# From
ExecStart=/usr/bin/gdm
# To
ExecStart=bianbu-gl gdm

Benchmark

bianbu glmark2-es2-drm
=======================================================
    glmark2 2023.01
=======================================================
    OpenGL Information
    GL_VENDOR:      Imagination Technologies
    GL_RENDERER:    PowerVR B-Series BXE-2-32
    GL_VERSION:     OpenGL ES 3.2 build 24.2@6603887
    Surface Config: buf=32 r=8 g=8 b=8 a=8 depth=24 stencil=0 samples=0
    Surface Size:   1920x1080 fullscreen
=======================================================
[build] use-vbo=false: FPS: 320 FrameTime: 3.131 ms
[build] use-vbo=true: FPS: 373 FrameTime: 2.688 ms
[texture] texture-filter=nearest: FPS: 361 FrameTime: 2.773 ms
[texture] texture-filter=linear: FPS: 356 FrameTime: 2.810 ms
[texture] texture-filter=mipmap: FPS: 358 FrameTime: 2.797 ms
[shading] shading=gouraud: FPS: 319 FrameTime: 3.142 ms
[shading] shading=blinn-phong-inf: FPS: 292 FrameTime: 3.425 ms
[shading] shading=phong: FPS: 222 FrameTime: 4.509 ms
[shading] shading=cel: FPS: 204 FrameTime: 4.925 ms
[bump] bump-render=high-poly: FPS: 218 FrameTime: 4.603 ms
[bump] bump-render=normals: FPS: 334 FrameTime: 2.998 ms
[bump] bump-render=height: FPS: 315 FrameTime: 3.180 ms
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 111 FrameTime: 9.061 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 38 FrameTime: 26.587 ms
[pulsar] light=false:quads=5:texture=false: FPS: 356 FrameTime: 2.813 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 55 FrameTime: 18.259 ms
[desktop] effect=shadow:windows=4: FPS: 172 FrameTime: 5.835 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 112 FrameTime: 8.964 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 110 FrameTime: 9.107 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 169 FrameTime: 5.927 ms
[ideas] speed=duration: FPS: 333 FrameTime: 3.011 ms
[jellyfish] <default>: FPS: 133 FrameTime: 7.546 ms
[terrain] <default>: FPS: 9 FrameTime: 122.080 ms
[shadow] <default>: FPS: 130 FrameTime: 7.709 ms
[refract] <default>: FPS: 23 FrameTime: 43.837 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 407 FrameTime: 2.462 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 190 FrameTime: 5.270 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 406 FrameTime: 2.464 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 264 FrameTime: 3.790 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 145 FrameTime: 6.923 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 263 FrameTime: 3.815 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 262 FrameTime: 3.821 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 252 FrameTime: 3.977 ms
=======================================================
                                  glmark2 Score: 229 
=======================================================

Codec

GStreamer

I didn’t give it a try yet.

Copying GStreamer libraries from Bianbu Linux may work.

FFmpeg

Spacemit provides their hardware codec and it’s integrated in their FFmpeg build from the Bianbu Linux.

Some of the symbol links may refer to /etc/alternative/... and you should correct them.

bianbu ffmpeg -i input.flv -c:v h264_stcodec output.mp4

[!WARNING] FFmpeg parameters order matters!

Banana Pi F3 peripherals on board

Wireless module RTL8852bs

# /etc/modprobe.d/8852bs.conf

options 8852bs rtw_country_code=US
modprobe 8852bs
ip addr

wlan0 will show in the links.

echo '8852bs' > /etc/modules-load.d/8852bs.conf

Install hostapd to launch AP or install wpa_supplicant to connect WiFi.

See also

FAQ

Missing drivers

Official documentation about building drivers and libraries on Spacemit K1.

About the graphics hardware acceleration

I haven’t made them working in success after built on ArchLinux. I gave up discovering this valueless platform.

Now it’s available in GPU chapter.

The Chinese capital Canyon Bridge Capital has been the current parent company of Imagination since 2017.

The alternative is the software implementation llvmpipe.

About the media hardware codec

Spacemit has designed their own media API for their codec. They called it Multi Processing Platform (MPP).

They supported this media API in FFmpeg and Gstreamer on their distro Bianbu. I really couldn’t understand: why didn’t they make it VAAPI-compatible?

Use cases for me

It’s affording a part of functionality of this site with services proxied via Cloudflare Daemon running on it :D