RISC-V program development using QEMU

RISC-V

In a nutshell

RISC-V (pronounced “risk-five”) is an open source instruction set architecture (ISA) based on established reduced instruction set computing (RISC) principles.

The project began in 2010 at the University of California, Berkeley, but many contributors are volunteers not affiliated with the university.

In contrast to most ISAs, RISC-V is freely available for all types of use, permitting anyone to design, manufacture and sell RISC-V chips and software. While not the first open ISA, it is significant because it is designed to be useful in modern computerized devices such as warehouse-scale cloud computers, high-end mobile phones and the smallest embedded systems. Such uses demand that the designers consider both performance and power efficiency. The instruction set also has a substantial body of supporting software, which fixes the usual weakness of new instruction sets.

RISC-V ISA modularity

Hardware baseline and ABI choice

There are different versions of the instruction set for 32, 64 and 128 bits; operating as little-endian by default.

  • RV32I, most is microcontroller unit (MCU) class RV32IMC
  • RV32E, for embedded systems
  • RV64I, most Linux distro use RV64GC as the hardware baseline and the lp64d ABI (little-endian, the default ABI for RV64G systems).
  • RV128I, simply not realistic at this time.

The base set of RISC-V is the Base Integer Instruction Set “RV32/64/128I” or “RV32E” (a reduced version of RV32I that supports only 16 registers designed for embedded systems).

A computer with the instruction sets “IMAFD”, is said to be “general-purpose”, summarized as “G”, so it an “RV64IMAFDC” can also be described as an “RV64GC”. Together with the “privileged” instruction set extension an “RVGC” defines all instructions needed to conveniently support a Unix-style operating system.

Extension Description Version Frozen?
M Standard Extension for Integer Multiplication and Division 2.0 Yes
A Standard Extension for Atomic Instructions 2.0 Yes
F Standard Extension for Single-Precision Floating-Point 2.0 Yes
D Standard Extension for Double-Precision Floating-Point 2.0 Yes
Q Standard Extension for Quad-Precision Floating-Point 2.0 Yes
C Standard Extension for Compressed Instructions 2.0 Yes
L Standard Extension for Decimal Floating-Point 0.0 No
B Standard Extension for Bit Manipulation 0.0 No
J Standard Extension for Dynamically Translated Languages 0.0 No
T Standard Extension for Transactional Memory 0.0 No
P Standard Extension for Packed-SIMD Instructions 0.1 No
V Standard Extension for Vector Operations 0.2 No
N Standard Extension for User-Level Interrupts 1.1 No

Qemu setup

install packages

sudo apt install qemu-system-misc qemu-user-static binfmt-support u-boot-qemu opensbi libc6-riscv64-cross gcc-riscv64-linux-gnu

sudo ln -s /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1 /lib

sudo sh -c "cat >/etc/ld.so.conf.d/riscv64-linux-gnu.conf << EOF
/usr/riscv64-linux-gnu/lib/
EOF
"

LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib qemu-riscv64-static a.out

/usr/bin/qemu-system-riscv64
/usr/lib/riscv64-linux-gnu/opensbi/qemu/virt/fw_dynamic.elf
/usr/lib/riscv64-linux-gnu/opensbi/qemu/virt/fw_jump.elf
/usr/lib/u-boot/qemu-riscv64_smode/u-boot.bin

register riscv64 interpreter

sudo update-binfmts --import << EOF
package qemu-user-static
interpreter /usr/bin/qemu-riscv64-static
type magic
offset 0
magic \x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00
mask  \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
EOF

Setting up a riscv64 virtual machine

debootstrap of riscv64

sudo apt-get install debootstrap qemu-user-static binfmt-support debian-ports-archive-keyring
sudo debootstrap --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg \
    --include=curl,jq,wget,locales,debian-ports-archive-keyring --merged-usr --foreign \
    unstable /tmp/riscv64-chroot http://deb.debian.org/debian-ports

sudo chroot /tmp/riscv64-chroot

cat > /debootstrap/mirror << EOF
http://deb.debian.org/debian-ports
EOF

/debootstrap/debootstrap --second-stage

localedef -c -i en_US -f UTF-8 en_US.UTF-8
localedef -c -i zh_CN -f UTF-8 zh_CN.UTF-8
localedef --list-archive

passwd

ln -sf /dev/null /etc/systemd/system/serial-getty@hvc0.service

cat > /etc/resolv.conf << EOF
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF

cat > /etc/apt/apt.conf.d/zz-10-install << EOF
APT::Install-Recommends "0";
APT::Install-Suggests "0";

Acquire::http { Proxy "http://proxy.example.com:8080"; };
EOF

cat > /etc/apt/sources.list << EOF
deb http://ftp.ports.debian.org/debian-ports unstable main
# deb http://ftp.ports.debian.org/debian-ports unreleased main
# deb http://ftp.ports.debian.org/debian-ports experimental main
EOF

apt-get update
apt-get install --no-install-recommends linux-image-riscv64 u-boot-menu openntpd ntpdate
sed -i 's/^DAEMON_OPTS="/DAEMON_OPTS="-s /' /etc/default/openntpd

cat >> /etc/default/u-boot <<EOF
U_BOOT_PARAMETERS="rw noquiet root=/dev/vda1"
EOF

u-boot-update

cat >> /etc/network/interfaces <<EOF
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
EOF

Create rootfs.img

truncate -s 4G rootfs.img
losetup --find rootfs.img
losetup -a

fdisk /dev/loop0
partprobe -s /dev/loop0
mkswap /dev/loop0p2
mkfs.ext4 /dev/loop0p1

mount /dev/loop0p1 riscv64-root/
cp -aP riscv64-chroot/* riscv64-root/

losetup --detach /dev/loop0

Run qemu-system-riscv64

# qemu-system-riscv64 -nographic -machine virt -m 1.9G \
    -kernel /usr/lib/riscv64-linux-gnu/opensbi/qemu/virt/fw_jump.elf \
    -device loader,file=/usr/lib/u-boot/qemu-riscv64_smode/u-boot.bin,addr=0x80200000 \
    -object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-device,rng=rng0 \
    -append "console=ttyS0 rw root=/dev/vda1" \
    -device virtio-blk-device,drive=hd0 -drive file=rootfs.img,format=raw,id=hd0 \
    -device virtio-net-device,netdev=usernet -netdev user,id=usernet,hostfwd=tcp::22222-:22

# qemu-system-riscv64 -nographic -machine virt -m 1.9G \
    -kernel /usr/lib/riscv64-linux-gnu/opensbi/qemu/virt/fw_jump.elf \
    -object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-device,rng=rng0 \
    -append "root=/dev/vda1 ro console=ttyS0" \
    -device virtio-blk-device,drive=hd0 -drive file=rootfs.img,format=raw,id=hd0 \
    -device virtio-net-device,netdev=net0 -netdev type=tap,id=net0,ifname=tap0,script=no,downscript=no

    ip link add br0 type bridge
    ip tuntap add dev tap0 mode tap user $(whoami)
    ip link set dev tap0 master br0
  # ip addr flush dev eth0
  # ip link set dev eth0 master br0
    ip link set dev br0 up
    ip link set dev tap0 up

  # ip address delete $PREFIX dev eth0
  # ip address add $PREFIX dev br0
  # ip route add default via $ROUTE dev br0

qemu-system-riscv64: plic: invalid register write: 000001fc

Platform Name          : QEMU Virt Machine
Platform HART Features : RV64ACDFIMSU
Platform Max HARTs     : 8
Current Hart           : 0
Firmware Base          : 0x80000000
Firmware Size          : 112 KB
Runtime SBI Version    : 0.1

PMP0: 0x0000000080000000-0x000000008001ffff (A)
PMP1: 0x0000000000000000-0xffffffffffffffff (A,R,W,X)

CPU:   rv64imafdcsu
Model: riscv-virtio,qemu
DRAM:  1.9 GiB

date -s -d'2018-05-07T21:28:57'
date -u [MMDDhhmm[[CC]YY][.ss]]
date -u 123109322018