
Emulador RISC-V em Rust que executa Linux com JIT em ARM64/x86_64 e memória virtual Sv39
Um emulador RISC-V em Rust. Ele inicializa Linux.
A máquina implementa RV64IMAFDC com níveis de privilégio M/S/U e memória virtual Sv39.
Ela executa um JIT em hosts ARM64 e x86_64, usando um interpretador quando necessário.
Os periféricos são UART 16550, CLINT, PLIC e SBI 1.0. Há uma dependência externa: zstd.
Não é o emulador mais rápido. No modo interpretador, ele roda cerca de três vezes mais devagar que o QEMU. No modo JIT, cerca de vinte e nove vezes mais devagar. O encadeamento de blocos de código ainda não foi implementado; isso ajudará. Dizemos isso claramente para que você saiba o que está obtendo.
O que ele faz bem: é simples de operar, expõe uma API HTTP para controle da máquina, pode executar um ELF bare-metal sem um kernel, e pode salvar e restaurar o estado completo da máquina. Estas são funcionalidades úteis para trabalho com sistemas e para testes.
cargo build --release
O binário é target/release/emuko. Crie um alias.
alias emuko=target/release/emuko
emuko dow
Baixa um kernel e initrd de boot de rede do Debian RISC-V para ~/.emuko/.
SHA256 é verificado. Nenhum kernel próprio é necessário.
emuko start
O emulador roda como um daemon. Você está conectado ao seu console. Você verá o kernel inicializar. Você terá um shell.
| Tecla | Efeito |
|---|---|
| Ctrl+] | Desconectar (o daemon continua) |
| Ctrl+C | Interrupção no convidado |
| Ctrl+D | EOF no convidado |
emuko start # reconectar console
emuko dump # imprimir estado da CPU
emuko stop # pausar execução
emuko con # continuar
emuko step 1000 # executar passo-a-passo N instruções
emuko snap # tirar um snapshot
emuko kill # desligar
O daemon escuta em http://127.0.0.1:7788/v1/api/ e aceita conexões de console WebSocket
em ws://127.0.0.1:7788/v1/ws/uart. Ambos são utilizáveis a partir de scripts.
Às vezes você não quer um sistema operacional. Você quer a máquina, um binário, e nada mais entre eles.
emuko run ./my_program.elf
O daemon redefine a máquina, carrega os segmentos ELF em seus endereços físicos, e inicia a execução. A saída chega pelo console UART. O daemon já deve estar em execução.
Para escrever no console a partir de bare-metal: armazene um byte em 0x1000_0000.
O diretório examples/ contém programas que executam dessa forma.
| Exemplo | O que faz |
|---|---|
bare_printf | Imprime uma mensagem a cada 10 milhões de iterações. Sem libc. Escrita direta na UART. |
É necessário um cross-compilador RISC-V para compilá-los.
No macOS: brew install riscv64-elf-gcc.
No Linux: apt install gcc-riscv64-linux-gnu.
emuko start
cd examples/bare_printf
make run
O estado da máquina — registradores, memória, tudo — pode ser salvo e restaurado.
emuko snap # snapshot agora
emuko snap 5000000 # snapshot automático a cada 5M passos
emuko snap stop # parar snapshots automáticos
emuko ls # listar snapshots
emuko restore <snapshot> # restaurar
A máquina virtual usa um layout MMIO fixo compatível com a plataforma QEMU RISC-V virt.
Com configurações padrão (load_addr=0x80200000, 1 GiB de RAM):
0x8000_0000 ── Base da RAM
(espaço — utilizável por programas bare-metal)
0x8020_0000 ── Imagem do kernel
│ .text / .rodata / .data / .bss
└─ fim do kernel
(livre)
── initrd
── DTB
── Região EFI (128 KiB, apenas kernels PE/UEFI)
0xBFFF_FFFF ── Fim da RAM
DTB, initrd e EFI são colocados para baixo a partir do topo da RAM. O emulador verifica sobreposição com o kernel na inicialização e para com um erro claro se a RAM for muito pequena.
Segmentos PT_LOAD do ELF são colocados em seus endereços p_vaddr.
bare_printf é vinculado em 0x8000_0000:
0x8000_0000 ── .text
── .rodata
── .data
── .bss (zerado por start.S)
── pilha (16 KiB acima de BSS)
Sem kernel. Sem initrd. Sem DTB. Registradores começam em zero exceto sp,
que o emulador define como ram_base + 0x100000 antes de start.S assumir o controle.
Opções podem ser passadas na linha de comando, definidas como variáveis de ambiente ou colocadas em emuko.yml.
Comparação direta com emuladores RISC-V comumente usados.
✅ = suportado e documentado. — = não incorporado.
Fontes: QEMU virt · Spike · Renode
Apache 2.0. Veja LICENSE.
| Região | Base | Tamanho | Notas |
|---|
| CLINT | 0x0200_0000 | 64 KiB | Timer e IRQ de software |
| PLIC | 0x0C00_0000 | 4 MiB | 32 fontes de interrupção |
| UART | 0x1000_0000 | 256 B | NS16550A, IRQ 10 |
| RAM | 0x8000_0000 | 1 GiB | Configurável |
| Opção | Variável de Ambiente | Padrão | Notas |
|---|
--ram-size | RAM_SIZE | 1 GB | RAM em bytes |
--backend | EMUKO_BACKEND | adaptive | adaptive, arm64_jit, amd64_jit, arm64, x86_64 |
--bootargs | BOOTARGS | console serial | Linha de comando do kernel |
| Funcionalidade | emuko | QEMU | Spike | Renode |
|---|
| JIT / tradução dinâmica | ✅ | ✅ | — | — |
| Salvar e restaurar snapshot | ✅ | ✅ | — | ✅ |
| Snapshot automático periódico | ✅ | — | — | ✅ |
| API HTTP para controle da máquina | ✅ | — | — | — |
| Console UART via WebSocket | ✅ | — | — | — |
| Ponte UART scriptável para o host | ✅ | — | — | ✅ |
| Upload de ELF bare-metal (sem SO) | ✅ | — | — | — |
| Download de kernel + SHA256 em um comando | ✅ | — | — | — |
| Verificador diferencial JIT-vs-interpretador | ✅ | — | — | — |
| Depuração com GDB | — | ✅ | ✅ | ✅ |
| Ecossistema de dispositivos grande (PCIe, virtio) | — | ✅ | — | — |
| Simulação multi-nó | — | — | — | ✅ |
| Cobertura ISA ampla (RVV, criptografia, etc.) | — | — | ✅ | — |