Skip to content

markkurossi/riscv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

343 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RISC-V in Go

RV64GC RISC-V emulator written in Go capable of booting Linux, NetBSD, and FreeBSD with OpenSBI, U-Boot, SV39 virtual memory, and VirtIO devices.
OpenSBI → U-Boot → {BuildRoot,Ubuntu,NetBSD,FreeBSD}

Features

  • RV64GC instruction set support
  • Machine, Supervisor, and User privilege modes
  • SV39 virtual memory and page tables
  • OpenSBI support
  • VirtIO block storage support
  • Operating Systems:
    • OpenSBI
    • U-Boot
    • EFI Boot
    • Buildroot Linux
    • Ubuntu 24.04
    • NetBSD 11.99
    • FreeBSD 15.1
  • Linux syscall emulation mode
  • Device emulation:
    • NS16550A UART
    • PLIC interrupt controller
    • ACLINT MSWI and MTIMER devices
    • Syscon poweroff device
  • Symbol-aware traces and debugging support
  • Instruction-level execution tracing
  • Compressed instruction support

The project is intended as a readable and hackable implementation of a modern RISC-V platform, suitable for learning emulator internals, operating systems, and the RISC-V privileged architecture.

Current status

The emulator successfully boots and runs:

OS Status
Buildroot Linux Shell login
Ubuntu 24.04 Multi-user userspace
NetBSD 11.99 Multi-user userspace, package build, clean shutdown
FreeBSD 15.1 Multi-user userspace

Recent milestones:

  • OpenSBI 1.6 support
  • U-Boot 2026.04 support
  • EFI boot support
  • SV39 virtual memory
  • User/Supervisor/Machine modes
  • VirtIO block devices
  • NetBSD userspace and C compiler
  • FreeBSD userspace
  • Clean OS shutdown via SBI

Linux Boot

Userspace emulation

  • Standalone binaries
  • Statically linked binaries
  • Dynamically linked binaries
  • Basic Go binaries
  • Full Linux userspace compatibility

Linux system emulation

  • OpenSBI boot
  • Device Tree support
  • Machine/Supervisor/User privilege modes
  • SV39 MMU
  • Interrupt handling
  • ACLINT timer/IPI support
  • PLIC interrupt controller
  • Parse kernel PE32+ header: load address, symbols
  • VirtIO
    • virtio-blk
  • Initramfs loading
  • Buildroot shell login
  • System shutdown support
  • SMP support
  • riscv-arch-test

Quick start

Clone and run:

$ git clone https://github.com/markkurossi/riscv
$ cd riscv/cmd/goemu
$ go build
$ ./goemu buildroot.goemu

Expected output:

OpenSBI v1.6

[    0.000000] Booting Linux on hartid 0
[    0.000000] Linux version 7.0.11 (root@5c73f8dabee1) (riscv64-linux-gnu-gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0, GNU ld (GNU Binutils for Ubuntu) 2.42) #9 SMP PREEMPT Wed Jun  3 08:23:43 UTC 2026
[    0.000000] Machine model: goemu,riscv-emulator
...
[   12.291753] Freeing initrd memory: 9468K
[   18.570200] clk: Disabling unused clocks
[   18.570327] PM: genpd: Disabling unused power domains
[   18.570487] ALSA device list:
[   18.570595]   No soundcards found.
[   18.582016] Freeing unused kernel image (initmem) memory: 2428K
[   18.582810] Run /init as init process
...
Welcome to GoEMU RISC-V Linux

Kernel: 7.0.11
Machine: riscv64

buildroot login: root
login[79]: root login on 'console'
# ls -la
total 4
drwx------    2 root     root            60 Apr 19 05:25 .
drwxr-xr-x   18 root     root           420 May 18 05:41 ..
-rw-------    1 root     root           192 Apr 19 05:25 .ash_history
# uname -a
Linux goemu 7.0.11 #9 SMP PREEMPT Wed Jun  3 08:23:43 UTC 2026 riscv64 GNU/Linux
# date
Mon Jun  8 04:55:00 UTC 2026
# halt
...
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system halt
[   22.943205] reboot: System halted

The buildroot.goemu file defines the emulator BIOS, kernel, and rootfs arguments. Those arguments can also be specified (and overwritten) with corresponding command line arguments:

$ ./goemu -bios opensbi/fw_jump.bin \
          -kernel linux-7.0.11/Image \
          -symbols linux-7.0.11/System.map \
          -drive id=hd0,format=raw,file=linux-2026-04-08/rootfs.ext2 \
          -device virtio-blk-device,drive=hd0 \
          -append "earlycon=sbi console=ttyS0,115200 root=/dev/vda ro rootwait"

Emulator Example

The goemu provides also a primitive Linux userspace emulation:

$ cd cmd/goemu/
$ file examples/hello
examples/hello: ELF 64-bit LSB executable, UCB RISC-V, soft-float ABI, version 1 (SYSV), statically linked, not stripped
$ ./goemu -ktrace examples/hello
    0     0 CALL write(1,10050,15)
Hello, RISC-V!
    0     0 RET  write 15
    0     0 CALL exit(0)

Architecture

+--------------------+
| Linux / NetBSD /   |
| FreeBSD Userspace  |
+--------------------+
| Linux / NetBSD /   |
| FreeBSD Kernel     |
+--------------------+
| U-Boot / EFI       |
+--------------------+
| OpenSBI            |
+--------------------+
| RV64GC CPU         |
| SV39 MMU           |
| CSR subsystem      |
| Interrupts         |
+--------------------+
| VirtIO Block       |
| UART               |
| PLIC               |
| ACLINT             |
| Goldfish RTC       |
| Syscon Poweroff    |
+--------------------+

Benchmarks

Real Workloads

NetBSD 11.99:

  • Boot to login prompt
  • Compile Hello World with GCC
  • Run user binaries
  • Multi-minute uptime
  • Clean shutdown

Example:

$ time cc -o hello hello.c
33.57 real
32.15 user
1.30 sys

Fibonacci

Performance improvements are tracked as the emulator evolves. The numbers below show the effect of individual optimizations. They are from running fibo.c on:

cpu: Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
Optimization MIPS
Base 19.75
GC-less decode 32.55
PTE access checks 33.57
MMU Map fastpath 34.70
DecodeCFast 45.78
Cached code page 60.68
Concrete memory 65.29
32-bit decode cache 87.64
Ld/Sd TLB fastpath 101.49
Optimized Instr struct 159.65
Added interrupt handling 147.38

Development roadmap

Near term

  • VirtIO networking
  • VirtIO RNG
  • Process-local page tables in emulator mode
  • Full syscall coverage in emulator mode

Longer term

  • SMP support
  • Additional VirtIO devices
  • Additional ISA extensions
  • JIT experiments
  • Performance optimizations

Appendix

Benchmark history

Optimization fib 30 fib 35 fib 40 MIPS Relative
Base 2.969 32.510 19.75 1.000
GC-less decode 1.803 19.726 32.55 0.607
PTE access checks 1.763 19.128 33.57 0.588
MMU Map fastpath 1.709 18.507 34.70 0.569
DecodeCFast 1.280 13.848 2m33.240s 45.78 0.426
Cached code page 0.977 10.582 1m57.654s 60.68 0.325
Concrete memory 0.915 9.835 1m48.920s 65.29 0.303
32-bit decode cache 0.684 7.327 1m20.509s 87.64 0.225
Ld/Sd TLB fastpath 0.603 6.327 1m10.533s 101.49 0.195
Optimized Instr struct 0.385 4.022 0m44.167s 159.65 0.124
Interrupts 0.416 4.321 0m49.085s 148.61 0.134

Internal roadmap

  • Does Image have a PE header? Does it also contain System.map?

MMU Refactoring

  • Fix page table MMU code to run the existing samples
  • Refactor the entire emulator stack
    • CPU -> Kernel -> Process -> Emulator
    • Kernel creates processes 1-n
    • Virtual memory handled per process
    • CPU has only {Load,Store}Uint{8,16,32,64}()
    • Process has {Put,}Uint{8,16,32,64,String,Data}() functions
    • Syscall can cause page fault on mmap'ed files. Syscall's traps should fill page table.
  • sfence.vma must clear MMU's TLB entries
  • Remove Raw uint32 from Instr?

Step 2 - MMU and Linux syscalls

  • MMU with page tables
    • Move pagetable to processes
  • Refactor emulator source files
  • Rethink FD handling.
  • Run most Linux and Go binaries
  • Proper Linux syscall support

Step 3 - Supervisor mode

  • Supervisor mode
  • Boot Linux kernel

Kernel memory map

+--------------------------------+
| 0xBFFF_FFFF                    |
~                                ~
| 0x8000_0000    System RAM      |
+--------------------------------+
| 0x1000_7FFF                    |
~                                ~
| 0x1000_1000    VirtIO Devices  |
+--------------------------------+
| 0x1000_00FF                    |
~                                ~
| 0x1000_0000    UART (NS16550A) |
+--------------------------------+
| 0x0FFF_FFFF                    |
~                                ~
| 0x0C00_0000    PLIC            |
+--------------------------------+
| 0x0200_FFFF                    |
~                                ~
| 0x0200_0000    CLINT           |
+--------------------------------+
| 0x0000_2FFF                    |
~                                ~
| 0x0000_1000    Boot ROM        |
+--------------------------------+

System RAM

+--------------------------------+
|                                |
~                                ~
| 0x8800_0000    initrd          |
+--------------------------------+
|                                |
~                                ~
| 0x8400_0000    hw.dtb          |
+--------------------------------+
|                                |
~                                ~
| 0x8020_0000    Image           |
+--------------------------------+
|                                |
~                                ~
| 0x8000_0000    fw_boot.bin     |
+--------------------------------+

OpenSBI and Das U-Boot

u-boot

$ apt-get update && apt-get install -y libssl-dev
$ apt-get update && apt-get install -y libgnutls28-dev uuid-dev
$ cd u-boot-2026.04/
$ export CROSS_COMPILE=riscv64-linux-gnu-
$ ls configs/ | grep riscv
openpiton_riscv64_defconfig
openpiton_riscv64_spl_defconfig
qemu-riscv64_defconfig
qemu-riscv64_smode_acpi_defconfig
qemu-riscv64_smode_defconfig
qemu-riscv64_spl_defconfig
$ make qemu-riscv64_smode_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.[ch]
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#
$ make -j$(nproc)

NetBSD

$ ./goemu netbsd.goemu
<RET>
fatload virtio 0:1 0x84000000 /EFI/BOOT/BOOTRISCV64.EFI
setenv bootargs "boot hd0a:netbsd -v -s consdev=com0 speed=115200"
bootefi 0x84000000 0x9eeae220

debugging in u-boot:

=> part list virtio 0

FreeBSD

Press space to enter FreeBSD boot console:

<SPACE>
OK set boot_verbose=1
OK boot

About

RV64GC RISC-V emulator written in Go capable of booting Linux, NetBSD, and FreeBSD with OpenSBI, U-Boot, SV39 virtual memory, and VirtIO devices.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors