/rvemu

RISC-V emulator for CLI and Web written in Rust with WebAssembly. It supports xv6 and Linux (ongoing).

Primary LanguageRustMIT LicenseMIT

rvemu: RISC-V Emulataor

Build Status Actions Status docs.rs crate.io License

RISC-V online/CLI emulator in Rust.

The online emulator is available here:

The emulator supports RV64GC ISA (RV64IMAFD, Zicsr, Zifencei, RV64C), privileged ISA, CSRs, virtual memory system (Sv39), peripheral devices (UART, CLINT, PLIC, Virtio), and device tree. See the "Features List" section for the details of features.

These features are compliant with "The RISC-V Instruction Set Manual Volume I: Unprivileged ISA Document Version 20191214-draft" and "The RISC-V Instruction Set Manual Volume II: Privileged Architecture Document Version 1.12-draft" in the RISC-V specifications.

Usage

The emulator can run both in your browser and in your terminal. Also, the emulator can be embedded in your project by the crate registry.

On Browser

You can run xv6, a simple Unix-like operating system, in rvemu.app/xv6.

Demo

You also be able to run an arbitrary RISC-V binary in rvemu.app. The online emulator supports the following commands:

  • upload: Upload local RISC-V binaries for the execution on the emulator.
  • ls: List the files you uploaded.
  • run [file]: Execute a file which you uploaded or some files are already embedded.
  • help: Print all commands you can use.

See the "Build RISC-V binary" section for more information to build RISC-V binary.

On Terminal

The option --kernel or -k specifies a kernel image, and --file or -f specifies a root filesystem image.

Linux

$ ./target/release/rvemu-cli -k bin/linux/bbl.bin -f bin/linux/busybear.bin

xv6

$ ./target/release/rvemu-cli -k bin/xv6/kernel.bin -f bin/xv6/fs.img

Bare-metal binary

You can use an arbitrary RISC-V binary and you can skip the -f option. An ELF binary should have no headers.

$ ./target/release/rvemu-cli -k <your-binary>

Build

For Web Application

The wasm-pack build command generates a pkg directory and makes Rust source code into .wasm binary. It also generates the JavaScript API for using our Rust-generated WebAssembly. The toolchain's supported target is wasm32-unknown-unknown. You need to execute this command whenever you change your Rust code.

// This is the alias of
// `wasm-pack build lib/rvemu-wasm --out-dir <path-to-rvemu>/public/pkg --target web --no-typescript`.
$ make rvemu-wasm

This command installs dependencies in the node_modules directory. Need npm install --save in the public directory at the first time and whenever you change dependencies in package.json.

$ npm install --save // at the public directory

You can see the website via http://localhost:8000. npm start is the alias of python3 -m http.server so you need Python3 in your environment.

$ npm start // at the public directory

For CLI Tool

Build the emulator as a CLI tool.

$ make rvemu-cli

Build RISC-V Binary

You might need to build RISC-V toolchain.

$ git clone --recursive git@github.com:riscv/riscv-gnu-toolchain.git
$ cd riscv-gnu-toolchain
$ ./configure --prefix=/opt/riscv --with-arch=rv64gc
$ make
$ make linux

Bare-metal C Program

You need to make an ELF file without headers, which starts at the address 0x8000_0000 by the following instructions:

// Make an assembly file from a C file.
$ riscv64-unknown-elf-gcc -S -nostdlib foo.c

// Make a binary file from an assembly file with start position 0x8000_0000.
$ riscv64-unknown-elf-gcc -Wl,-Ttext=0x80000000 -nostdlib -o foo foo.s

// Remove headers from a binary file.
$ riscv64-unknown-elf-objcopy -O binary foo foo.text

Linux

For build:

// Linux
$ git clone https://github.com/torvalds/linux/
$ git checkout tags/v4.19-rc3 -b v4.19-rc3
$ make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig
$ make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j $(nproc)

// riscv-pk
$ git clone https://github.com/riscv/riscv-pk
$ cd riscv-pk
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV --host=riscv64-unknown-elf \
  --with-payload=../../linux/vmlinux --enable-logo
$ make
$ make install

// busybear-linux
$ git clone https://github.com/michaeljclark/busybear-linux
$ cd busybear-linux
$ ./scripts/build.sh

If a compile error happens, you may need to:

  • update CC := gcc to CC := riscv64-unknown-elf-gcc in riscv-pk/build/Makefile
  • comment out the "build bbl" part in busybear-linux/scripts/build.sh

because the build script for cross compiling in riscv-pk is broken. See https://github.com/riscv/riscv-pk/blob/master/configure#L1146-L1148

Testing

You can see the binaries for unit testings in riscv/riscv-tests.

$ make test

Analyzing with Perf

$ perf record -F99 --call-graph dwarf ./target/release/rvemu-cli -k bin/xv6/kernel.bin -f bin/xv6/fs.img
$ perf report

Publish

The site is hosted by a firebase.

$ firebase deploy

Features List

The emulator supports the following features:

  • RV64G ISA
    • RV64I (v2.1): supports 52/52 instructions (fence does nothing for now)
    • RV64M (v2.0): supports 13/13 instructions
    • RV64A (v2.1): supports 22/22 instructions (No atomicity for now)
    • RV64F (v2.2): supports 30/30 instructions
    • RV64D (v2.2): supports 32/32 instructions
    • Zifencei (v2.0): supports 1/1 instructions (fence.i does nothing for now)
    • Zicsr (v2.0): supports 6/6 instructions (No atomicity for now)
  • RV64C ISA (v2.0): support 36/36 instructions
  • Privileged ISA: supports 7/7 instructions (sfence.vma, hfence.bvma, and hfence.gvma do nothing for now)
  • Control and status registers (CSRs)
    • Machine-level CSRs
    • Supervisor-level CSRs
    • User-level CSRs
  • Virtual memory system (Sv39)
  • Devices
    • UART: universal asynchronous receiver-transmitter
    • CLINT: core local interruptor
    • PLIC: platform level interrupt controller
    • Virtio: virtual I/O
  • Device tree

Dependencies

dtc can be installed by apt install device-tree-compiler on Ubuntu.

Resources

Helpful Tools

Articles about This Project