User:Jessesimpson36/HiFive Unmatched Rev-B RISC-V Installation guide

From Gentoo Wiki
Jump to:navigation Jump to:search

HiFive Unmatched Rev-B RISC-V Installation guide

The following is some notes I came across when setting up my RISC-V board. It's also my first time trying to write gentoo documentation, so hopefully I follow through with adding details.

My installation journey

When I first tried to install Gentoo on this board, I mostly struggled with U-boot and getting any sort of serial output. So how I went about installing it was by taking the default SD Card provided by the board, and flashing a new sd card with the same partition scheme and files, with the exception of the linux filesystem, which instead of Ubuntu, I used my own Gentoo filesystem. I am able to boot with that, but I'm eventually going to want to swap out u-boot with a newer version of u-boot that I compile myself (and is more up-to-date), and I will want to compile my own kernel.

I also foolishly bought a USB wifi adapter that I will need to compile my own out-of-tree kernel module in order to get a network connection.

Some of the steps in this guide may be redundant, since I'm first going to write this to mirror my installation journey, and then I will optimize it to be a more generic install guide.

What comes in the default SD Card provided with the board

With the Unmatched board, there is an SD card with the following partition table.

Disk /dev/mmcblk0: 29.72 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 1FB1F4BB-00FC-4169-920A-567D008A5404

Device          Start      End  Sectors  Size Type
/dev/mmcblk0p1     34     2081     2048    1M HiFive FSBL
/dev/mmcblk0p2   2082    10273     8192    4M HiFive BBL
/dev/mmcblk0p3  16384   282623   266240  130M Microsoft basic data
/dev/mmcblk0p4 286720 13918207 13631488  6.5G Linux filesystem

mmcblk0p1: FSBL Partition

explain what FSBL is

mmcblk0p2: BBL Partition

explain what BBL is

mmcblk0p3: NTFS filesystem

This filesystem is a typical /boot mount with a configuration of extlinux, as well as the device tree and a kernel.

mmcblk0p4: Root linux filesystem

This is where typical userspace linux files go. By default, this filesystem seems to be Ubuntu.

Setting up RISC-V cross-compiling chroot environment

Compiling_with_QEMU_user_chroot

The above link helped me set up a chroot environment.

Setting up Serial port

The first thing you'll want to be able to do is be able to connect to the board and send commands in. There are 3 places that you need to supply options for the serial port to work.

  1. U-boot
  2. Kernel boot logs
  3. Login prompt


Serial port: U-boot

I don't recall if I did anything special to configure U-boot for this. I'll think on it.

Serial port: Kernel

During the boot process, the kernel needs to know where to send log messages. The following kernel command line parameter will tell the kernel to send log messages to the serial port.

console=ttySIF0,115200


Serial port: Login prompt

After being able to access U-boot and the kernel, you'll want to be able to log in with a username and password. Otherwise you'll only see kernel logs. To do this, you'll need to have the following line in your /etc/inittab

s0:12345:respawn:/sbin/agetty -L 115200 ttySIF0 vt100

Client serial port setup

On the client, when you plug in your serial port, you will see 2 devices

  1. /dev/ttyUSB0
  2. /dev/ttyUSB1

/dev/ttyUSB0 is unused.

Use this command to connect to the serial port:

root #minicom -b 115200 -D /dev/ttyUSB1

or screen:

root #screen -L /dev/ttyUSB1 115200

If you get no serial output at all when you start your RISC-V machine, try using this baud rate to get a very early boot error code and refer to the HiFive Software Reference Manual for a list of error codes:

root #screen -L /dev/ttyUSB1 89856

U-Boot commands for a proper boot flow

Below is a successful boot prompt. To drop into a shell, with a serial connection open, hit space within the first few seconds of booting. This will halt the automatic bootflow and open a shell.

U-Boot 2021.01 (Apr 07 2021 - 17:59:15 +0000)

CPU:   rv64imafdc
Model: SiFive HiFive Unmatched A00
DRAM:  16 GiB
MMC:   spi@10050000:mmc@0: 0
EEPROM: SiFive PCB EEPROM format v1
Serial number: SF105SZ233800206
PCB revision: 4
Ethernet MAC address: 70:b3:d5:92:fc:42
CRC: 946d66d2
EEPROM dump: (0x25 bytes)
00: F1 5E 50 45 01 02 00 04 42 00 53 46 31 30 35 53 
10: 5A 32 33 33 38 30 30 32 30 36 01 70 B3 D5 92 FC 
20: 42 D2 66 6D 94 
found SiFive v1
In:    serial@10010000
Out:   serial@10010000
Err:   serial@10010000
Model: SiFive HiFive Unmatched A00
Net:   eth0: ethernet@10090000
Hit any key to stop autoboot:  0 
=> env set bootargs root=/dev/mmcblk0p4 rootfstype=ext4 rootwait console=ttySIF0,115200
=> mmc rescan
=> load mmc 0:4 0x82000000 boot/Image.gz
7247925 bytes read in 4725 ms (1.5 MiB/s)
=> load mmc 0:3 0x88000000 hifive-unmatched-a00.dtb
10473 bytes read in 12 ms (851.6 KiB/s)

=> booti 0x82000000 - 0x88000000
   Uncompressing Kernel Image
Moving Image from 0x82000000 to 0x80200000, end=810b2000
## Flattened Device Tree blob at 88000000
   Booting using the fdt blob at 0x88000000
   Using Device Tree in place at 0000000088000000, end 00000000880058e8

Starting kernel ...
<kernel messages follow>

Explanation of commands

Set kernel command line options

In U-Boot, you load the kernel command line arguments as an environment variable.

env set bootargs root=/dev/mmcblk0p4 rootfstype=ext4 rootwait console=ttySIF0,115200

Why I set each kernel command line option

  1. root=/dev/mmcblk0p4 - This declares the block device of the root filesystem
  2. rootfstype=ext4 - I don't think this is necessary, but tells the kernel what filesystem it is.
  3. rootwait - SD cards tend to load in the kernel slower than other storage devices, this prevents mounting root before the SD card is available.
  4. console=ttySIF0,115200 - Output logs to the serial port ttySIF0 with a baud rate of 115200.


Rescan block devices

mmc rescan will just reload the disk. I'm unsure if this is necessary.

mmc rescan


Load kernel into memory

Load the kernel into memory address 0x82000000. There is nothing special about this memory address other than it isn't reserved for anything useful. If you need to find your kernel file from the u-boot command line, check out the help page for ext4ls in the u-boot command line.

load mmc 0:4 0x82000000 boot/Image.gz

Explanation

  1. mmc - read from an SD card interface
  2. 0:4 - device number 0 with partition number 4
  3. 0x82000000 - nonspecific memory address
  4. boot/Image.gz - path to a kernel


Load device tree into memory

Load from the device tree binary

load mmc 0:3 0x88000000 hifive-unmatched-a00.dtb

Explanation

  1. mmc - read from an SD card interface
  2. 0:3 - read the file from the /boot partition (partition 3)
  3. 0x88000000 - nonspecific memory address that doesn't overlap with the previous address (0x82000000)
  4. hifive-unmatched-a00.dtb - device tree binary file


Boot

Boot from the memory addresses that were loaded.

booti 0x82000000 - 0x88000000
  1. 0x82000000 - memory address we used to load the kernel
  2. dash - the dash indicates that we will not be using an initramfs. If you are using an initramfs, place the memory address of it here.
  3. 0x88000000 - memory address we used to load the device tree binary.

Beyond initial boot

I'd like to be able to load my boot instructions from a file so that I don't have to keep copy/pasting the u-boot commands. Newer versions of U-boot have a "bootflow" file which can set a default and boot once the device is turned on. For that I will need to compile my own, newer version of u-boot.

Moving from a Micro SD card to an NVMe Drive

Lately I've been dissatisfied with the performance and reliability with my micro-sd cards that I'm using to boot off of. I found that my SD cards would get corrupted fairly easily, and that they were quite slow when doing things like compiling kernels. And what I thought would be a simple operation (duplicating the disk to a new NVMe drive and booting) is actually more complicated. This section will go over the problem I faced and how I was able to work around it.

Problem

The kernel version 5.11.10, which is the kernel shipped on the SD card with the Unmatched RISC-V board, does not support using an NVMe drive on the motherboard. The patchset that allows the kernel to do this is in this commit: https://lwn.net/ml/linux-kernel/cover.1614681831.git.greentime.hu@sifive.com/

Which the first commit in that patch set is dated for Tue, 02 Mar 2021 18:59:11 +0800

And according to https://en.wikipedia.org/wiki/Linux_kernel_version_history the commit would not be introduced until a 5.12 kernel version.

I first started by trying to cross-compile the kernel using my chroot environment. Unfortunately, this produced a kernel with a faulty magic-number and was unable to boot on the risc-v machine.

My next thought was to use the risc-v machine to compile a new kernel onto the sd card. This lasted all night and I woke up finding that the micro-sd card was corrupted from too many write operations. (Thankfully I take backups).

My current approach will be to compile a kernel by booting into the sd card, but this time, attaching a different disk and all the writes will go on the new disk. I found that USB external hard drives did not work on the board, so I will now attempt to mount an NFS and compile the kernel on there (using qemu-nbd and a block-device file on the NFS because NFS doesn't preserve file permissions).


Creating a dtb file

dtb files are device tree binaries and contain necessary information about how the hardware interacts with the kernel. When compiling the linux kernel with genkernel, you are likely generating a bunch of dts files for different boards, and each of these dts files can be converted to a dtb file which can be used at boot in the u-boot prompt. The following is how to compile the dtb from a c++ source file.

cpp -nostdinc -I include -undef -x assembler-with-cpp ./arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts > hifive-unmatched-a00.tmp.dts

dtc -O dtb -b 0 -o hifive-unmatched-a00.dtb hifive-unmatched-a00.tmp.dts


Once booted on a kernel with nvme support

At this point, you should be booted into the mmc device, and running fdisk -l should report an NVMe drive. the goal is to now copy the data off the mmc drive onto the nvme drive. thankfully, the Hi-Five FSBL partition and the Hi-Five BBL partitions are only read while used in the u-boot phase of booting, so those can safely be copied.


Recommended packages

Install sys-apps/gptfdisk for sgdisk and sys-fs/dosfstools for mkfs.vfat.

creating the new partitions

Follow the instructions from https://docs.u-boot.org/en/latest/board/sifive/unmatched.html#flashing

root #sgdisk -g --clear -a 1 \
 --new=1:34:2081         --change-name=1:spl --typecode=1:5B193300-FC78-40CD-8002-E86C45580B47 \
 --new=2:2082:10273      --change-name=2:uboot  --typecode=2:2E54B353-1271-4842-806F-E436D6AF6985 \
 --new=3:16384:282623    --change-name=3:boot --typecode=3:0x0700 \
 --new=4:286720:13918207 --change-name=4:root --typecode=4:0x8300 \
/dev/nvme0n1

we will also want to expand the fourth partition to be larger. I used cfdisk for this. theres probably a way to edit the above command to use the rest of the disk space for the fourth partition.

root #dd if=/dev/mmcblk0p1 of=/dev/nvme0n1p1 bs=4M status=progress
root #dd if=/dev/mmcblk0p2 of=/dev/nvme0n1p2 bs=4M status=progress


root #mkfs.vfat /dev/nvme0n1p3
root #mkfs.ext4 /dev/nvme0n1p4

/boot is also not often used much after being loaded during initial boot, so mount the nvme partition 3 and cp the contents of /boot into there.

The more complicated part will be copying the root filesystem. If you took a backup of the root filesystem like I did, then you can mount the nfs drive and copy the backup onto the new root filesystem.


fixing /etc/fstab to the nvme drive

final boot commands in u-boot

env set bootargs root=/dev/nvme0n1p4 rootfstype=ext4 rootwait console=ttySIF0,115200
nvme scan
fatls nvme 0:3 /
load nvme 0:3 0x82000000 vmlinuz-6.9.3-gentoo-riscv64
load nvme 0:3 0x88000000 hifive-unmatched-a00-6.9.3.dtb
booti 0x82000000 - 0x88000000

automating u-boot login

I spent a while debugging why my extlinux/extlinux.conf file wasn't able to be booted from. As it turns out, for GPT partition schemes, u-boot requires the partition with your extlinux/extlinux.conf file to be marked as bootable. cfdisk does not support setting the bootable flag on GPT so you will need to use fdisk to do it.

fdisk
x - enable expert commands
A - toggle the legacy BIOS bootable flag
3 - partition number 3 (the one with /extlinux/extlinux.conf or /boot/extlinux/extlinux.conf

Once I had that, I was able to get a boot to happen on NVMe by explicitly setting

setenv boot_targets nvme
bootmeth order extlinux
bootflow scan

Otherwise, it seems that network booting takes higher priority than NVMe. I'll add more to this section to figure out how to make it boot from NVMe as higher precedence. also I will give my extlinux.conf file as an example, but not tonight.

fixing the time

Unfortunately, the hifive unmatched revb board does not support the RTC module in the kernel yet. From their official software manual

> There is no support for the RTC function on the HiFive Unmatched yet. Time information can be acquired from an Ethernet or WiFi network. If a user isn’t connected to a network where time information is available then some functions that depend on correct time may not work such as ssh.

https://www.sifive.com/boards/hifive-unmatched-revb

However, you can still fix the time by using ntp. I recommend not installing openntpd, because they have a max drift that is hard to force update the clock. so I would instead install net-misc/ntp

Useful links

compiling-device-trees

ac1300 kernel driver

u-boot-sifive-board-specific-docs

hifive-unmatched-board

hifive-unmatched-software-reference-manual

Compiling_with_QEMU_user_chroot


https://youtu.be/INWghYZH3hI?si=ECEsmj0Xu3kFGOGR