Skip to content

Experimental Debian based OS and application for VisionFive SBC.

License

Notifications You must be signed in to change notification settings

cristicc/visionfive-debos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

75 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Evaluation of StarFive VisionFive SBC

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, kmake is configured to use all available processing units, plus one. To set it to a custom value, e.g. 2, it’s necessary to update docker/Dockerfile and rebuild the container:

$ 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:

usb drive select
⚠️

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 /path/to/device with your specific destination path (e.g. /dev/sda):

$ 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

About

Experimental Debian based OS and application for VisionFive SBC.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published