This is an experimental Debian based OS and application for the VisionFive SBC from StarFive [1].
The main purpose of the project is to evaluate the mainline kernel support and to find areas of further improvements.
Connect one of the USB to serial adapters to the 40-Pin GPIO header (PIN6-GND, PIN10-RXD, PIN8-TXD):
-
FTDI TTL-232R-3V3 Cable (BLACK-GND, ORANGE-TXD, YELLOW-RXD)
-
PL2303TA TTL-232R-3V3 Cable (BLACK-GND, GREEN-TXD, WHITE-RXD)
-
PL2303HX TTL-232R-3V3 Cable (BLUE-GND, RED-TXD, GREEN-RXD)
Assuming the serial adapter on the host system is available under ttyUSB0
,
open a serial console using either screen
or minicom
utilities:
$ screen /dev/ttyUSB0 115200
$ minicom -D /dev/ttyUSB0 -b 115200 -c on
Use the command below to build a Docker image containing a toolchain to be used
for building the Linux kernel for the RISC-V architecture. The image will be
named visionfive/cross
.
$ docker/docker.sh [-p WORK_DIR] build
[...]
Successfully built 801f692ad877
Successfully tagged visionfive/cross:latest
$ docker images visionfive/cross
REPOSITORY TAG IMAGE ID CREATED SIZE
visionfive/cross latest 801f692ad877 2 minutes ago 626MB
The optional -p
or --project-dir
parameter allows to map a path in the host
system to the guest environment. By default it is the current project root
directory.
The docker/docker.sh
script above can be used to quickly run a build container
or execute commands inside the development environment:
$ docker/docker.sh --help
Usage: docker.sh [OPTION]... COMMAND
Helper script to automate Docker container creation for building VisionFive sources.
Options:
-h, --help Display this help text and exit.
-p, --project_dir DIR
Set project directory to a custom location.
Commands:
build Build docker image.
run [--new] [STTY]
Run docker container. Pass '--new' to ensure a new container
instance is created, i.e. any existing container is removed.
Optionally, a host serial device STTY can be added to the
container. This will also start a TFTP server.
exec [COMMAND] Execute a command in the container.
stop Stop docker container.
status Show docker container status.
Pass the run
command to instantiate a container named visionfive-build
and
provide an interactive console terminal. Note the project content is made
available in the container under the path specified on image creation.
$ docker/docker.sh run
visionfive-build:~/visionfive-debos$ ls
LICENSE README.adoc debos docker docs tools
You may check the container status from a host console terminal:
$ docker/docker.sh status
'visionfive-build' container status: running
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f5524864bb34 visionfive/cross "/bin/bash" 11 minutes ago Up 11 minutes visionfive-build
The build environment provides the kmake
alias which can be used as a helper
to configure and build the kernel sources:
visionfive-build:~/visionfive-debos$ alias kmake
alias kmake='make -j 9 O=build ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- LOCALVERSION=""'
Letβs create the work
directory for cloning any git repositories required by
the project:
visionfive-build:~/visionfive-debos$ mkdir work && cd work
visionfive-build:~/visionfive-debos/work$
Now clone linux
Git repository and, optionally, also checkout linux-next
in
a separate git working tree:
visionfive-build:~/visionfive-debos/work$ git clone -o linux git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
visionfive-build:~/visionfive-debos/work$ cd linux
# Skip the commands below if linux-next is not of interest.
visionfive-build:~/visionfive-debos/work/linux$ git remote add -t master linux-next https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
visionfive-build:~/visionfive-debos/work/linux$ git fetch linux-next
visionfive-build:~/visionfive-debos/work/linux$ git worktree add --checkout -b linux-next ../linux-next next-20221028
It might be useful to have quick access to the downstream kernel repository, as well:
visionfive-build:~/visionfive-debos/work/linux$ git remote add starfive [email protected]:starfive-tech/linux.git
visionfive-build:~/visionfive-debos/work/linux$ git fetch starfive
visionfive-build:~/visionfive-debos/work/linux$ git worktree add --checkout -b linux-starfive ../linux-starfive starfive/visionfive
To enable support for the StarFive VisionFive SBC in mainline kernel, itβs necessary to apply a few patches. Note a patch series has been already submitted upstream and should be merged soon:
The patch series can be easily downloaded and applied using the b4
utility:
visionfive-build:~/visionfive-debos/work/linux$ b4 am -l [email protected]
visionfive-build:~/visionfive-debos/work/linux$ git am ./v4_20221018_cristian_ciocaltea_enable_initial_support_for_starfive_visionfive_v1_sbc.mbx
Alternatively, the patches are also stored in this project repository, so one may apply them by running:
visionfive-build:~/visionfive-debos/work/linux$ git am --empty=drop ../../linux/patches/*.patch
β
|
The patches have been merged in
linux-next.
Hence, if building the next-20221114 kernel or newer, there is no need to
apply the above mentioned patches anymore.
|
While still in the work/linux
folder, letβs create a subfolder build
for
configuring and compiling the kernel using the already provided defconfig
.
This is a minimal configuration to get StartFive VisionFive SBC booting with
the mainline kernel.
π‘
|
The kmake alias already passes the name of the build subfolder to make
via O=build argument.
|
visionfive-build:~/visionfive-debos/work/linux$ mkdir -p build
visionfive-build:~/visionfive-debos/work/linux$ cp ../../linux/visionfive_defconfig build/.config
visionfive-build:~/visionfive-debos/work/linux$ kmake olddefconfig
Optionally adjust the configuration by calling kmake menuconfig
.
Having .config
file ready, itβs time to start compiling the sources.
visionfive-build:~/visionfive-debos/work/linux$ kmake
[...]
DTC arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dtb
[...]
LD vmlinux
NM System.map
SORTTAB vmlinux
OBJCOPY arch/riscv/boot/Image
GZIP arch/riscv/boot/Image.gz
Kernel: arch/riscv/boot/Image.gz is ready
make[1]: Leaving directory '~/visionfive-debos/work/linux/build'
π‘
|
By default, $ sed -i 's/$(($(nproc)+1))/2/' docker/Dockerfile
$ docker/docker.sh build |
Generate Debian packages and, optionally, install the kernel image and DTB to
build/dist
folder:
visionfive-build:~/visionfive-debos/work/linux$ kmake bindeb-pkg
visionfive-build:~/visionfive-debos/work/linux$ ls -1 *.deb
linux-image-6.1.0-rc1-visionfive_6.1.0-rc1-visionfive-1_riscv64.deb
linux-libc-dev_6.1.0-rc1-visionfive-1_riscv64.deb
# Local install (optional)
visionfive-build:~/visionfive-debos/work/linux$ mkdir build/dist
visionfive-build:~/visionfive-debos/work/linux$ kmake INSTALL_PATH=dist zinstall dtbs_install
This can be done either from a console on the host system or on the build container:
$ cd work/
$ git clone https://git.savannah.gnu.org/git/grub.git
$ # TODO: Drop the commands below when upstream support is complete
$ cd grub
$ git remote add tekkamanninja https://github.com/tekkamanninja/grub.git
$ git fetch tekkamanninja
$ git switch -C riscv_devel tekkamanninja/riscv_devel_Nikita_V3
Run the following commands from the build container:
visionfive-build:~$ cd visionfive-debos/work/grub
visionfive-build:~/visionfive-debos/work/grub$ ../../grub/build.sh
./bin/grub-mkimage: info: reading ~/visionfive-debos/grub/default.cfg.
./bin/grub-mkimage: info: kernel_img=0x7f1179bd4010, kernel_size=0x1a000.
./bin/grub-mkimage: info: the core size is 0x2e75f0.
./bin/grub-mkimage: info: writing 0x2ea000 bytes.
Successfully built GRUB2 image: ~/visionfive-debos/grub/dist/grubriscv64.efi
For this task we are going to use the debos utility [3], which simplifies the creation of various Debian-based OS images.
debos requires a YAML file as input, which should provide a list of actions to be executed sequentially.
From the project root directory, run the command below in a host console:
$ debos/debos.sh
Using existing rootfs base
Syncing build resources
cd+++++++++ scripts/
>f+++++++++ scripts/setup-visionfive.sh
>f+++++++++ linux-image-6.1.0-rc1-visionfive_6.1.0-rc1-visionfive-1_riscv64.deb
>f+++++++++ grubriscv64.efi
Running /debos --artifactdir /recipes --template-var use_rootfs_base:"yes" [...]
[...]
2022/10/31 16:57:17 ==== Setup OS for VisionFive ====
2022/10/31 16:57:18 setup-visionfive.sh | Installing kernel packages
[...]
2022/10/31 16:57:23 setup-visionfive.sh | Setting up linux-image-6.1.0-rc1-visionfive (6.1.0-rc1-visionfive-1) ...
2022/10/31 16:57:23 setup-visionfive.sh | update-initramfs: Generating /boot/initrd.img-6.1.0-rc1-visionfive
[...]
2022/10/31 16:57:32 setup-visionfive.sh | Configuring U-Boot
2022/10/31 16:57:32 setup-visionfive.sh | Configuring GRUB
2022/10/31 16:57:32 setup-visionfive.sh | Configuring system
[...]
2022/10/31 16:57:32 ==== image-partition ====
[...]
2022/10/31 16:57:32 Formatting partition 3 | Creating filesystem with 196284 4k blocks and 49152 inodes
[...]
2022/10/31 16:57:32 ==== Deploying filesystem onto image ====
2022/10/31 16:57:33 Setting up fstab
[...]
2022/10/31 16:57:33 ==== Compressing final image ====
2022/10/31 16:57:46 ==== Recipe done ====
Created disk img: ~/visionfive-debos/work/debos/debian-riscv64.img.gz
Insert the micro SD card in a USB card reader attached to the host system and run the following command, assuming the current working directory is still the project root folder:
$ IMAGE_FILE=work/debos/debian-riscv64.img.gz
$ tools/prepare-sd-card.sh ${IMAGE_FILE}
A dialog box should pop up and show a list of all removable USB drives currently accessible:
|
Make sure to double check your choice before proceeding since the following operation will permanently destroy any existing data on the selected device! |
Select the target drive and press OK
to start flashing the device using the
image file we have just created:
Please wait while writing 'work/debos/debian-riscv64.img.gz' to '/dev/sda'
[...]
900000256 bytes (900 MB, 858 MiB) copied, 27.3587 s, 32.9 MB/s
Done.
π‘
|
If you know exactly the path to the removable device, use may use the following
command to directly write the image. Just replace $ gzip -dc "${IMAGE_FILE}" | sudo dd bs=4M of=/path/to/device conv=fsync iflag=fullblock oflag=direct status=progress |
Insert the uSD card into the board and plug the power supply. Check your serial console for the boot messages:
$ screen /dev/ttyUSB0 115200
[...]
U-Boot 2022.04-rc2-VisionFive (Mar 07 2022 - 21:12:22 +0800)StarFive
CPU: rv64imafdc
Model: StarFive VisionFive V1
DRAM: 8 GiB
[...]
Welcome to GRUB!
[...]
GNU GRUB version 2.11
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β*Debian kernel 6.1.0-rc1-visionfive β
β β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Use the β² and βΌ keys to select which entry is highlighted.
Booting `Debian kernel 6.1 for visionfive'
loader/efi/linux.c:81:linux: UEFI stub kernel: [ vmlinuz-6.1.0-rc1-vi 5.92MiB 100% 0.22B/s ]
[...]
loader/efi/linux.c:462:linux: kernel @ 0xfd10c000 [ vmlinuz-6.1.0-rc1-vi 5.92MiB 100% 13.09TiB/s ]
loader/efi/linux.c:381:linux: LoadFile2 initrd loading protocol installed [ jh7100-starfive-visi 6.13KiB 100% 231.70B/s ]
loader/efi/fdt.c:63:linux: allocating 7305 bytes for fdt
loader/efi/linux.c:181:linux: linux command line: 'BOOT_IMAGE=/boot/vmlinuz-6.1.0-rc1-visionfive root=/dev/mmcblk0p3 rw console=tty0
[...]
EFI stub: Booting Linux Kernel...
loader/efi/linux.c:333:linux: Providing initrd via LOAD_FILE2_PROTOCOL
EFI stub: Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path [ initrd.img-6.1.0-rc1 4.18MiB 100% 1.94MiB/s ]
EFI stub: Using DTB from configuration table
[...]
Linux version 6.1.0-rc1-visionfive (riscv64-linux-gnu-gcc (Debian 10.2.1-6) [...]
[...]
Machine model: StarFive VisionFive V1
[...]
Unpacking initramfs...
[...]
Run /init as init process
Loading, please wait...
Starting systemd-udevd version 252~rc3-2
[...]
Gave up waiting for root file system device.
[...]
(initramfs) uname -a
Linux (none) 6.1.0-rc1-visionfive #1 SMP Sun Oct 30 19:45:43 UTC 2022 riscv64 riscv64
Note there is no driver for the eMMC storage in the mainline kernel 6.1, hence the rootfs cannot be mounted.
To speedup the development process, it is possible to boot the kernel directly from U-Boot using TFTP.
Provide the path to the serial device and pass the --new
argument to ensure
any existing container is discarded.
$ docker/docker.sh run --new /dev/ttyUSB0
Jan 29 15:47:17 visionfive-build syslog.info syslogd started: BusyBox v1.30.1
visionfive-build:~/visionfive-debos$ busybox netstat -ul
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 0.0.0.0:10069 0.0.0.0:*
A TFTP server listening on UDP port 10069 is automatically started in the container and is able to serve content from the projectβs work directory. The service is further published to the host via the standard port 69.
π‘
|
Also note a syslog daemon is also available in order to give access to the tftpd
log messages. Run docker logs visionfive-build on a host console to show the
container log buffer.
|
In order to boot the kernel and get access to a shell console, we need to provide a ramdisk with the rootfs, i.e. an initramfs.
Instead of creating the rootfs from scratch, e.g. using buildroot or similar tools, we can use a prebuilt one:
visionfive-build:~/visionfive-debos$ mkdir -p work/ramdisk && cd work/ramdisk
visionfive-build:~/visionfive-debos/work/ramdisk$ curl -fLO \
https://storage.kernelci.org/images/rootfs/buildroot/buildroot-baseline/20230703.0/riscv/rootfs.cpio.gz
Now run the command below to create a RISC-V compatible ramdisk image for U-Boot:
visionfive-build:~/visionfive-debos/work/ramdisk$ mkimage -A riscv -T ramdisk \
-C none -d rootfs.cpio.gz rootfs.cpio.gz.uboot
Image Name:
Created: Sun Jan 29 17:50:36 2023
Image Type: RISC-V Linux RAMDisk Image (uncompressed)
Data Size: 7837576 Bytes = 7653.88 KiB = 7.47 MiB
Load Address: 00000000
Entry Point: 00000000
Use the tools/tftp-boot.py
utility to automate the communication with U-Boot
via the serial port. It is able to provide the required U-Boot commands for
loading the kernel image, DTB and initramfs from the TFTP server running on the
visionfive-build Docker container.
visionfive-build:~/visionfive-debos$ tools/tftp-boot.py -h
usage: tftp-boot.py [-h] [--kernel-root KERNEL_ROOT] [--ramdisk-file RAMDISK_FILE]
[--kernel-args KERNEL_ARGS] [--tftp-server-ip TFTP_SERVER_IP]
[--skip-boot] serialport [baud]
Utility to automate booting Linux via U-Boot TFTP.
positional arguments:
serialport Serial device path or telnet port number
baud The baud rate when using serial device path (default: 115200)
optional arguments:
-h, --help show this help message and exit
--kernel-root KERNEL_ROOT
Linux kernel top directory relative to project "work" folder (default: linux)
--ramdisk-file RAMDISK_FILE
U-Boot ramdisk file path relative to project "work" folder (default: )
--kernel-args KERNEL_ARGS
Arguments passed to the linux kernel before booting
(default: console=ttyS0,115200n8 root=/dev/ram0 console_msg_format=syslog earlycon ip=dhcp)
--tftp-server-ip TFTP_SERVER_IP
The IP address of the TFTP server hosting the boot files (default: 192.168.1.90)
--skip-boot Skip U-Boot TFTP boot procedure (default: False)
β
|
Make sure the board is connected to a local network providing a DHCP service, which is used by U-Boot to get an IP address. Additionally, the network setup should allow TFTP access to the host system where the Docker container has been started. |
visionfive-build:~/visionfive-debos$ tools/tftp-boot.py \
--kernel-root linux-wip \
--ramdisk-file ramdisk/rootfs.cpio.gz.uboot \
--tftp-server-ip 192.168.1.10 /dev/ttyUSB0
Connecting to /dev/ttyUSB0 @115200
> Waiting for U-Boot prompt..
VisionFive #setenv autoload no
setenv autoload no
VisionFive #setenv initrd_high 0xffffffffffffffff
setenv initrd_high 0xffffffffffffffff
VisionFive #setenv fdt_high 0xffffffffffffffff
setenv fdt_high 0xffffffffffffffff
VisionFive #dhcp
dhcp
Speed: 1000, full duplex
BOOTP broadcast 1
DHCP client bound to address 192.168.1.67 (3 ms)
VisionFive #setenv serverip 192.168.1.10
setenv serverip 192.168.1.10
VisionFive #tftpboot 0x84000000 linux-wip/build/arch/riscv/boot/Image
tftpboot 0x84000000 linux-wip/build/arch/riscv/boot/Image
Speed: 1000, full duplex
Using dwmac.10020000 device
TFTP from server 192.168.1.10; our IP address is 192.168.1.67
Filename 'linux-wip/build/arch/riscv/boot/Image'.
Load address: 0x84000000
Loading: Jan 29 22:29:16 visionfive-build daemon.notice in.tftpd[149]: RRQ from 192.168.1.67 filename linux-wip/build/arch/riscv/boot/Image
################################################## 20.8 MiB
11.3 MiB/s
done
Bytes transferred = 21828608 (14d1400 hex)
[...]
VisionFive #setenv bootargs 'console=ttyS0,115200n8 root=/dev/ram0 console_msg_format=syslog earlycon ip=dhcp'
setenv bootargs 'console=ttyS0,115200n8 root=/dev/ram0 console_msg_format=syslog earlycon ip=dhcp'
VisionFive #booti 0x84000000 0x88300000 0x88000000
booti 0x84000000 0x88300000 0x88000000
Moving Image from 0x84000000 to 0x80200000, end=8172a000
## Loading init Ramdisk from Legacy Image at 88300000 ...
Image Name:
Image Type: RISC-V Linux RAMDisk Image (uncompressed)
Data Size: 7837576 Bytes = 7.5 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 88000000
Booting using the fdt blob at 0x88000000
Using Device Tree in place at 0000000088000000, end 00000000880054e4
Starting kernel ...
[...]
/ # --- Miniterm on /dev/ttyUSB0 115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
/ #
/ # uname -a
Linux buildroot 6.2.0-rc5-next-20230124-visionfive #3 SMP Wed Jan 25 01:18:38 UTC 2023 riscv64 GNU/Linux