franzflasch / riscv_em

Simple risc-v emulator, able to run linux, written in C.
GNU General Public License v3.0
136 stars 24 forks source link
c embedded-c embedded-systems emulator linux risc-v risc-v-emulator risc-v64 riscv riscv-em riscv-emulator riscv-linux riscv32 riscv64 rv32 rv64 uclinux

riscv_em

This is a risc-v emulator written in plain C. It started as a fun project a while ago and is now capable of doing a few things (but still just a hobby, won't be big and professional like qemu ;)

Ever wanted to know what the absolute minimum requirements are to run linux?

riscv_em is the answer. Yes, the emulator is capable of running Linux.

One goal of this project is to be easily able to understand its source code and thus also the risc-v isa. You can also see this project as an attempt to directly translate the RISC-V ISA specs (Currently Unprivileged Spec v.20191213 and Privileged Spec v.20190608) into plain C. Implementation focus is simplicity NOT efficiency! Altough I always try to improve it's performance whenever possible, as long as the code does not suffer losses in readability!

Currently the emulator supports RV32IMA and RV64IMA instructions. Furthermore it implements a CLINT (Core-Local Interrupt Controller) and also a PLIC (Platform Level Interrupt Controller), as well as a simple UART.

UPDATE 2021: Now the emulator also fully implements PMP and MMU.

Please see https://github.com/franzflasch/linux_for_riscv_em for a how-to-build appropriate linux images.

How-To build RV64-nommu:

mkdir build && cd build
cmake -DRV_ARCH=64 ..
make

How-To build RV32-mmu:

mkdir build && cd build
cmake -DRV_ARCH=32 ..
make

Build the device tree binaries for RV64-nommu and RV32-mmu (device-tree-compiler needed):

cd dts
./build_dtb.sh

Build a linux image for this emulator:

Please see https://github.com/franzflasch/linux_for_riscv_em

Start the emulator and load (uc)linux (RV64-nommu):

./build/riscv_em -f <linux_for_riscv_em-path>/output/linux/loader_64.bin -d dts/riscv_em.dtb

Start the emulator and load a full blown linux with opensbi (RV32-mmu):

./build/riscv_em -f <linux_for_riscv_em-path>/output_mmu_rv32/opensbi/build/platform/generic/firmware/fw_payload.bin -d dts/riscv_em32_linux.dtb

RAM disk

Make a filesystem image using the normal filesystem tools (e.g. mkfs.ext3, mksquashfs etc) with a maximum size of 200Mb. Then run

./build/riscv_em -f <linux_for_riscv_em-path>/output/linux/loader_64.bin -d dts/riscv_em.dtb -i mydiskimage.ext3

The filesystem will be available as /dev/pmem0, which can be either mounted from userspace, or specified as the root filesystem. Note that this does not use the initrd or initramdisk functionality, as that has severe size limitations (tries to unpack/copy the whole filesystem at boot).