Trying to Boot Arch Linux RISC-V on QEMU
Attempt to run the RISC-V port of Arch Linux on QEMU using the rootfs provided by https://archriscv.felixc.at/
Note: This is a personal experiment log by the author. It may contain errors or omissions and does not represent the best practice. Please refer with caution.
Preparation
Create a working directory and enter it:
mkdir -p archriscv && cd archriscv
Install QEMU RISC-V emulator and cross-compilation toolchain:
sudo pacman -S qemu-system-riscv riscv64-linux-gnu-gcc
Get the Arch Linux RISC-V image file and Linux source code:
wget https://mirrors.pku.edu.cn/archriscv/images/archriscv-latest.tar.zst
git clone https://github.com/torvalds/linux.git --depth=1
Begin Installation
Create Empty Disk Image
qemu-img create -f raw archriscv.img -o nocow=on 10G
Enable
nocowfor btrfs file system.
Compile the Kernel
The rootfs of Arch Linux RISC-V does not include a kernel, so we use the generic riscv config to compile the Linux kernel and boot with it, then install the kernel via pacman.
cd linux
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make -j$(nproc) ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- \
Image
The compiled file will be located at arch/riscv/boot/Image.
Create GPT Partition Table and Root Partition
cd ..
parted --script archriscv.img mklabel gpt \
mkpart primary ext4 1MiB 100% \
set 1 boot on
Create Loop Device, Format and Mount
LOOP=$(sudo losetup -fP --show archriscv.img)
sudo mkfs.ext4 ${LOOP}p1 -L rootfs
sudo mkdir -p /mnt/riscv-root
sudo mount ${LOOP}p1 /mnt/riscv-root
Extract Rootfs to Mount Point
sudo bsdtar -xpf archriscv-latest.tar.zst -C /mnt/riscv-root
umount -R /mnt/riscv-root
Configure Arch Linux
Boot QEMU
Create start.sh script to boot with the previously compiled kernel and connect via NAT:
#!/bin/bash
KERNEL_IMAGE="linux/arch/riscv/boot/Image"
ROOTFS_IMAGE="archriscv.img"
sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 up
sudo ip link set tap0 master virbr0
sudo qemu-system-riscv64 \
-nographic \
-machine virt \
-m 12g \
-smp 8 \
-kernel "$KERNEL_IMAGE" \
-append "root=/dev/vda1 rw console=ttyS0 init=/lib/systemd/systemd" \
-drive file="$ROOTFS_IMAGE",format=raw,if=none,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
Then:
chmod +x start.sh
./start.sh
Configure Network
After entering the system, configure the network as follows:
mkdir -p /etc/systemd/network
cat > /etc/systemd/network/20-eth0.network <<EOF
[Match]
Name=eth0
[Network]
DHCP=yes
EOF
systemctl enable systemd-networkd --now
systemctl enable systemd-resolved --now
ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
systemctl restart systemd-networkd
Install Linux Package
pacman -Syu linux mkinitcpio
mkinitcpio -P
Exit QEMU, remount the loop device and copy files from /mnt/riscv-root/boot:
sudo mount ${LOOP}p1 /mnt/riscv-root
cp /mnt/riscv-root/boot/* ./
Decompress vmlinuz-linux:
zcat vmlinuz-linux > vmlinuz-linux.uncompressed
mv vmlinuz-linux.uncompressed vmlinuz-linux
Modify the startup script as follows:
diff start.sh.old start.sh
3c3
< KERNEL_IMAGE="linux/arch/riscv/boot/Image"
---
> KERNEL_IMAGE="vmlinuz-linux"
15a16
> -initrd ./initramfs-linux.img \
Now you can boot using the distribution kernel.