QEMU: Cómo emular RISC-V en Linux
A diferencia de un software de virtualización como VirtualBox, que emplea la propia arquitectura de la máquina anfitriona, con QEMU podrás ir más allá de eso, y emular procesadores diferentes arquitecturas de la máquina anfitrión en el huésped.
En este tutorial te explicaré cómo hacerlo para el caso de RISC-V paso a paso. Así podrás usar binarios nativos para estas arquitectura y probarlos sobre tu máquina, sea la que sea…
¿Qué es QEMU?
QEMU es un emulador de procesadores de código abierto, libre, y multiplataforma. Para su funcionamiento, emplea traducción dinámica de binarios para que se puedan ejecutar los binarios nativos de la arquitectura huésped por la arquitectura anfitriona.
Además, QEMU también tiene capacidades de virtualización, permitiendo virtualizar otros sistemas operativos para realizar las pruebas que necesites. En el caso de RISC-V, serán aquellos sistemas operativos que soporten esta arquitectura (por el momento Linux, aunque existen algunos proyectos más, como xv6).
A diferencia de otras ISA, RISC-V incluye soporte de virtualización integral desde la base del diseño de la ISA para un respaldo más eficiente. Esto se debe a que se ha diseñado más recientemente, mientras otras ISA fueron diseñadas hace décadas.
Entre las arquitecturas que puede soportar QEMU están RISC-V, IA-32/AMD64, PowerPC/POWER, MIPS, SPARC, ARM, etc.
Pasos para emular RISC-V en QEMU:
Para comenzar con el tutorial, lo primero que debes hacer es satisfacer una serie de dependencias o requisitos necesarios para que funcione todo adecuadamente.
Usaré como base RISC-V de 64-bit, y la distro Ubuntu, ya que es la más popular. En cambio, puede servir para Debian y derivados. Y para otras distros solo habría que cambiar algunas cosas, pero los pasos son similares…
sudo apt-get update sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev libusb-1.0-0-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev device-tree-compiler pkg-config libexpat-dev libncurses5-dev libncursesw5-dev ninja-build libglib2.0-dev libpixman-1-dev
Una vez hecho eso, crea un directorio de trabajo que lo puedes llamar como tú prefieras, por ejemplo:
cd ~ mkdir riscv cd riscv
Ahora deberás descargar, compilar e instalar QEMU:
git clone https://github.com/qemu/qemu cd qemu git checkout v5.2.0 ./configure --target-list=riscv64-softmmu,riscv64-linux-user --prefix=$RISCV make -j $(nproc) sudo make install
Una vez hecho eso, tienes varias opciones. Una de ellas es descargar el kernel Linux y hacer compilación cruzada para RISC-V, y así poderlo usar en QEMU:
git clone https://github.com/torvalds/linux cd linux git checkout v5.10 make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j $(nproc)
Esto compilará el kernel Linux con la configuración por defecto. Además, tendrás un kernel comprimido y booteable en linux/arch/riscv/boot/Image al finalizar la compilación.
Para tener un surtido básico de herramientas y no hacer el sistema demasiado pesado, puedes usar por ejemplo BusyBox (¡Ojo! Nuevamente con compilación cruzada, ya que no son para tu Linux anfitrión, sino para el huésped):
git clone https://git.busybox.net/busybox cd busybox git checkout 1_32_1 CROSS_COMPILE=riscv64-unknown-linux-gnu- make defconfig CROSS_COMPILE=riscv64-unknown-linux-gnu- make menuconfig #En la configuración puedes elegir "Build Static Binary (no shared lib)" para facilitar la preparación del rootFS CROSS_COMPILE=riscv64-unknown-linux-gnu- make -j $(nproc)
Lo siguiente es crear disco para el rootFS con formato NULL y allí disponer los ficheros mínimos necesarios:
dd if=/dev/zero of=root.bin bs=1M count=64 mkfs.ext2 -F root.bin mkdir mnt sudo mount -o loop root.bin mnt cd mnt sudo mkdir -p bin etc dev lib proc sbin tmp usr usr/bin usr/lib usr/sbin sudo cp ~/busybox/busybox bin sudo ln -s ../bin/busybox sbin/init sudo ln -s ../bin/busybox bin/sh cd .. sudo umount mnt
Una vez ya tienes todo el entorno listo, lo siguiente será poner a funcionar tu Linux sobre RISC-V con QEMU:
sudo qemu-system-riscv64 -nographic -machine virt -kernel linux/arch/riscv/boot/Image -append "root=/dev/vda rw console=ttyS0" -drive file=root.bin,format=raw,id=hd0 -device virtio-blk-device,drive=hd0
Y debería iniciarse el sistema, con el prompt para poder ejecutar las órdenes que necesites…El primer comando, para que Busybox funcione adecuadamente debería ser:
/bin/busybox --install -s
Para salir, puedes usar Ctrl+A y luego X.
RISC-V toolchain
También puedes instalar el toolchain de RISC-V para comenzar a compilar aplicaciones para esta arquitectura (cross-compiling o compilación cruzada). La encontrarás en dos sabores diferentes:
-
riscv64-unknown-elf-gcc: usa newlib para pequeños programas independientes enlazados estáticamente y destinos integrados.
- riscv64-unknown-linux-gnu-gcc: usa glibc y puede construir programas que se enlazan dinámicamente.
Para la compilación, puedes usar:
git clone https://github.com/riscv/riscv-gnu-toolchain cd riscv-gnu-toolchain ./configure --prefix=$RISCV #También puedes usar --enable-multilib para construir el paquete con soporte de 32 y 64-bit make -j $(nproc) linux
También puedes usar el simulador de la ISA RISC-V Spike o el RISC-V Proxy Kernel, que es un entorno ligero para ejecución de aplicaciones. Para la construcción de estos otros puedes seguir estos pasos:
#Spike mkdir build ../configure --prefix=$RISCV make -j $(nproc) make install #RISC-V PK mkdir build cd build ../configure --prefix=$RISCV --host=riscv64-unknown-elf make -j $(nproc) make install
Espero que te haya servido de ayuda…