Running 64- and 32-bit RISC-V Linux on QEMU

Prerequisites

Running Linux on the QEMU RISC-V port requires you to install some prerequisites. Find instructions for various Linux distributions as well as macOS below:

Note

This has been tested on Ubuntu 18.04.

sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \
                 gawk build-essential bison flex texinfo gperf libtool patchutils bc \
                 zlib1g-dev libexpat-dev git
sudo yum install autoconf automake libmpc-devel mpfr-devel gmp-devel gawk bison flex \
                 texinfo patchutils gcc gcc-c++ zlib-devel expat-devel git
brew install gawk gnu-sed gmp mpfr libmpc isl zlib expat

Getting the sources

First, create a working directory, where we’ll download and build all the sources.

mkdir riscv64-linux
cd riscv64-linux
mkdir riscv32-linux
cd riscv32-linux

Then download all the required sources, which are:

git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
git clone https://github.com/qemu/qemu
git clone https://github.com/torvalds/linux
git clone https://github.com/riscv/riscv-pk
git clone https://github.com/michaeljclark/busybear-linux

Note

You can also use a prebuilt RISC-V GCC toolchain, which can be found on SiFive’s website.

Note

If you need to build the root filesystem yourself, you will need to compile the Linux cross-compiler yourself, as it isn’t provided in the archive from SiFive’s website.

For 32-bit, apply the following patches to their respective repositories: linux.diff and busybear-linux.diff:

cd <repository_name>
git apply <path_to_diffs>/<repository_name>.diff

Building

If you’re using a prebuilt toolchain, skip this step. If not, build the toolchain:

cd riscv-gnu-toolchain

# pick an install path, e.g. /opt/riscv64
./configure --prefix=/opt/riscv64 
make newlib -j $(nproc)
make linux -j $(nproc)

# export variables
export PATH="$PATH:/opt/riscv64/bin"
export RISCV="/opt/riscv64"
cd riscv-gnu-toolchain

# pick an install path, e.g. /opt/riscv32
./configure --prefix=/opt/riscv32 --with-arch=rv32gc --with-abi=ilp32d
make newlib -j $(nproc)
make linux -j $(nproc)

# export variables
export PATH="$PATH:/opt/riscv32/bin"
export RISCV="/opt/riscv32"

Build QEMU with the RISC-V target:

cd qemu
git checkout v3.0.0
./configure --target-list=riscv64-softmmu
make -j $(nproc)
sudo make install
cd qemu
git checkout v3.0.0
./configure --target-list=riscv32-softmmu
make -j $(nproc)
sudo make install

Build Linux for the RISC-V target. First, checkout to a desired version and copy the default configuration from Busybear:

cd linux
git checkout v4.19-rc3
cp ../busybear-linux/conf/linux.config .config
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- olddefconfig
cd linux
git checkout v4.19-rc3
cp ../busybear-linux/conf/linux.config .config
make ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- olddefconfig

Next, enter the kernel configuration, and make sure that the following options are checked:

  • ARCH_RV64I
  • CMODEL_MEDANY
  • CONFIG_SIFIVE_PLIC
  • ARCH_RV32I
  • CMODEL_MEDLOW
  • CONFIG_SIFIVE_PLIC
# enter kernel configuration
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- nconfig
# enter kernel configuration
make ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- nconfig

After accepting changes in the configuration, compile the kernel:

make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- vmlinux -j $(nproc)
make ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- vmlinux -j $(nproc)

Build BBL:

cd riscv-pk
mkdir build && cd build
../configure --enable-logo --host=riscv64-unknown-elf --with-payload=../../linux/vmlinux
make -j $(nproc)
cd riscv-pk
mkdir build && cd build
../configure --enable-logo --host=riscv32-unknown-elf --with-payload=../../linux/vmlinux
make -j $(nproc)

Build Busybear Linux:

cd busybear-linux
make -j $(nproc)

Running

Go back to your main working directory and run:

sudo qemu-system-riscv64 -nographic -machine virt \
     -kernel riscv-pk/build/bbl -append "root=/dev/vda ro console=ttyS0" \
     -drive file=busybear-linux/busybear.bin,format=raw,id=hd0 \
     -device virtio-blk-device,drive=hd0
sudo qemu-system-riscv32 -nographic -machine virt \
     -kernel riscv-pk/build/bbl -append "root=/dev/vda ro console=ttyS0" \
     -drive file=busybear-linux/busybear.bin,format=raw,id=hd0 \
     -device virtio-blk-device,drive=hd0

The default credentials are:

username
root
password
busybear

A typical run could look as shown in the gif below:

_images/linux64-qemu.gif