一个用 Rust 编写的 RISC-V 模拟器。它可以启动 Linux。
该机器实现了 RV64IMAFDC,具有 M/S/U 特权级别和 Sv39 虚拟内存。它在 ARM64 和 x86_64 主机上运行 JIT,必要时回退到解释器。外设包括 UART 16550、CLINT、PLIC 和 SBI 1.0。有一个外部依赖:zstd。
它不是最快的模拟器。在解释器模式下,它比 QEMU 慢约三倍。在 JIT 模式下,慢约二十九倍。代码块链式(Code block chaining)尚未实现;这将有所帮助。我们坦诚地说明这些,因为您应该清楚您得到的是什么。
它的优点:操作简单,提供用于机器控制的 HTTP API,可以在没有内核的情况下执行裸机 ELF,并且可以保存和恢复完整的机器状态。这些对于系统工作和测试非常有用。
cargo build --release
二进制文件位于 target/release/emuko。创建一个别名。
alias emuko=target/release/emuko
emuko dow
下载一个 Debian RISC-V 网络启动内核和 initrd 到 ~/.emuko/。SHA256 已验证。无需您自己的内核。
emuko start
模拟器作为守护进程运行。您将连接到它的控制台。您将看到内核启动。您将获得一个 shell。
| 按键 | 效果 |
|---|---|
| Ctrl+] | 分离(守护进程继续运行) |
| Ctrl+C | 在客户机中中断 |
| Ctrl+D | 在客户机中的 EOF |
emuko start # 重新连接控制台
emuko dump # 打印 CPU 状态
emuko stop # 暂停执行
emuko con # 继续
emuko step 1000 # 单步执行 N 条指令
emuko snap # 拍摄快照
emuko kill # 关闭
守护进程监听 http://127.0.0.1:7788/v1/api/,并在 ws://127.0.0.1:7788/v1/ws/uart 接受 WebSocket 控制台连接。两者都可在脚本中使用。
有时您不需要操作系统。您只需要机器、一个二进制文件,以及它们之间没有其他东西。
emuko run ./my_program.elf
守护进程重置机器,将 ELF 段加载到它们的物理地址,并开始执行。输出通过 UART 控制台到达。守护进程必须已经在运行。
要从裸机写入控制台:在 0x1000_0000 处存储一个字节。
examples/ 目录包含以这种方式运行的程序。
| 示例 | 功能 |
|---|---|
bare_printf | 每 1000 万次迭代打印一条消息。无 libc。直接 UART 写入。 |
构建它们需要 RISC-V 交叉编译器。在 macOS 上:brew install riscv64-elf-gcc。在 Linux 上:apt install gcc-riscv64-linux-gnu。
emuko start
cd examples/bare_printf
make run
机器状态——寄存器、内存,所有内容——都可以保存和恢复。
emuko snap # 立即快照
emuko snap 5000000 # 每 5M 步自动快照
emuko snap stop # 停止自动快照
emuko ls # 列出快照
emuko restore <snapshot> # 恢复
虚拟机使用与 QEMU RISC-V virt 平台兼容的固定 MMIO 布局。
使用默认设置(load_addr=0x80200000,1 GiB RAM):
0x8000_0000 ── RAM 基址
(间隙——裸机程序可用)
0x8020_0000 ── 内核映像
│ .text / .rodata / .data / .bss
└─ 内核结束
(空闲)
── initrd
── DTB
── EFI 区域 (128 KiB,仅限 PE/UEFI 内核)
0xBFFF_FFFF ── RAM 结束
DTB、initrd 和 EFI 从 RAM 顶部向下放置。模拟器在启动时检查与内核的重叠,如果 RAM 太小,会停止并显示明确的错误。
ELF PT_LOAD 段被放置在其 p_vaddr 地址。bare_printf 链接在 0x8000_0000:
0x8000_0000 ── .text
── .rodata
── .data
── .bss (由 start.S 清零)
── 栈 (BSS 上方 16 KiB)
没有内核。没有 initrd。没有 DTB。寄存器从零开始,除了 sp,模拟器在 start.S 接管之前将其设置为 ram_base + 0x100000。
选项可以通过命令行传递、设置为环境变量或放置在 emuko.yml 中。
与常用 RISC-V 模拟器的直接比较。✅ = 支持并已文档化。— = 未内置。
Apache 2.0。参见 LICENSE。
| 区域 | 基址 | 大小 | 备注 |
|---|
| CLINT | 0x0200_0000 | 64 KiB | 定时器和软件 IRQ |
| PLIC | 0x0C00_0000 | 4 MiB | 32 个中断源 |
| UART | 0x1000_0000 | 256 B | NS16550A,IRQ 10 |
| RAM | 0x8000_0000 | 1 GiB | 可配置 |
| 选项 | 环境变量 | 默认值 | 备注 |
|---|
--ram-size | RAM_SIZE | 1 GB | RAM 大小(字节) |
--backend | EMUKO_BACKEND | adaptive | adaptive, arm64_jit, amd64_jit, arm64, x86_64 |
--bootargs | BOOTARGS | serial console | 内核命令行 |
| 特性 | emuko | QEMU | Spike | Renode |
|---|
| JIT / 动态翻译 | ✅ | ✅ | — | — |
| 快照保存与恢复 | ✅ | ✅ | — | ✅ |
| 定期自动快照 | ✅ | — | — | ✅ |
| 用于机器控制的 HTTP API | ✅ | — | — | — |
| WebSocket UART 控制台 | ✅ | — | — | — |
| 可脚本化的 UART 主机桥接 | ✅ | — | — | ✅ |
| 裸机 ELF 上传(无操作系统) | ✅ | — | — | — |
| 一键内核下载 + SHA256 | ✅ | — | — | — |
| JIT 与解释器差异检查器 | ✅ | — | — | — |
| GDB 调试 | — | ✅ | ✅ | ✅ |
| 大型设备生态系统(PCIe、virtio) | — | ✅ | — | — |
| 多节点仿真 | — | — | — | ✅ |
| 广泛 ISA 覆盖(RVV、加密等) | — | — | ✅ | — |