
Emulatore RISC-V in Rust che avvia Linux con JIT su ARM64/x86_64 e memoria virtuale Sv39
Un emulatore RISC-V in Rust. Avvia Linux.
La macchina implementa RV64IMAFDC con livelli di privilegio M/S/U e memoria virtuale Sv39.
Esegue un JIT su host ARM64 e x86_64, ricadendo su un interprete quando necessario.
Le periferiche sono UART 16550, CLINT, PLIC e SBI 1.0. C'è una dipendenza esterna: zstd.
Non è l'emulatore più veloce. In modalità interprete è circa tre volte più lento di QEMU. In modalità JIT, circa ventinove volte più lento. Il concatenamento dei blocchi di codice non è ancora implementato; aiuterà. Lo diciamo chiaramente perché dovreste sapere cosa state ottenendo.
Ciò che fa bene: è semplice da usare, espone un'API HTTP per il controllo della macchina, può eseguire un ELF bare-metal senza kernel e può salvare e ripristinare l'intero stato della macchina. Queste sono cose utili per il lavoro sui sistemi e per i test.
cargo build --release
Il binario è target/release/emuko. Crea un alias.
alias emuko=target/release/emuko
emuko dow
Scarica il kernel netboot Debian RISC-V e initrd in ~/.emuko/.
SHA256 è verificato. Non è richiesto un kernel personale.
emuko start
L'emulatore viene eseguito come demone. Sei collegato alla sua console. Vedrai l'avvio del kernel. Otterrai una shell.
| Tasto | Effetto |
|---|---|
| Ctrl+] | Scollega (il demone continua) |
| Ctrl+C | Interrompi nell'ospite |
| Ctrl+D | EOF nell'ospite |
emuko start # riattacca console
emuko dump # stampa stato CPU
emuko stop # interrompi esecuzione
emuko con # continua
emuko step 1000 # esegui passo-passo N istruzioni
emuko snap # crea un'istantanea
emuko kill # arresta
Il demone è in ascolto su http://127.0.0.1:7788/v1/api/ e accetta connessioni console WebSocket
a ws://127.0.0.1:7788/v1/ws/uart. Entrambi sono utilizzabili da script.
A volte non vuoi un sistema operativo. Vuoi la macchina, un binario e nient'altro tra di loro.
emuko run ./my_program.elf
Il demone resetta la macchina, carica i segmenti ELF ai loro indirizzi fisici e inizia l'esecuzione. L'output arriva tramite la console UART. Il demone deve già essere in esecuzione.
Per scrivere sulla console da bare-metal: memorizza un byte a 0x1000_0000.
La directory examples/ contiene programmi che funzionano in questo modo.
| Esempio | Cosa fa |
|---|---|
bare_printf | Stampa un messaggio ogni 10 milioni di iterazioni. Nessuna libc. Scrittura diretta UART. |
È richiesto un cross-compilatore RISC-V per compilarli.
Su macOS: brew install riscv64-elf-gcc.
Su Linux: apt install gcc-riscv64-linux-gnu.
emuko start
cd examples/bare_printf
make run
Lo stato della macchina — registri, memoria, tutto — può essere salvato e ripristinato.
emuko snap # istantanea ora
emuko snap 5000000 # istantanea automatica ogni 5M passi
emuko snap stop # ferma istantanee automatiche
emuko ls # elenco istantanee
emuko restore <snapshot> # ripristina
La macchina virtuale utilizza un layout MMIO fisso compatibile con la piattaforma QEMU RISC-V virt.
Con impostazioni predefinite (load_addr=0x80200000, 1 GiB RAM):
0x8000_0000 ── Base RAM
(gap — utilizzabile da programmi bare-metal)
0x8020_0000 ── Immagine kernel
│ .text / .rodata / .data / .bss
└─ fine kernel
(libero)
── initrd
── DTB
── Regione EFI (128 KiB, solo kernel PE/UEFI)
0xBFFF_FFFF ── Fine RAM
DTB, initrd e EFI sono posizionati verso il basso dall'alto della RAM. L'emulatore verifica la sovrapposizione con il kernel all'avvio e si ferma con un errore chiaro se la RAM è troppo piccola.
I segmenti ELF PT_LOAD sono posizionati ai loro indirizzi p_vaddr.
bare_printf si collega a 0x8000_0000:
0x8000_0000 ── .text
── .rodata
── .data
── .bss (azzerato da start.S)
── stack (16 KiB sopra BSS)
Nessun kernel. Nessun initrd. Nessun DTB. I registri partono da zero tranne sp,
che l'emulatore imposta a ram_base + 0x100000 prima che start.S prenda il controllo.
Le opzioni possono essere passate tramite riga di comando, impostate come variabili d'ambiente
o inserite in emuko.yml.
Confronto diretto con emulatori RISC-V comunemente usati.
✅ = supportato e documentato. — = non integrato.
Fonti: QEMU virt · Spike · Renode
Apache 2.0. Vedi LICENSE.
| Regione | Base | Dimensione | Note |
|---|
| CLINT | 0x0200_0000 | 64 KiB | Timer e IRQ software |
| PLIC | 0x0C00_0000 | 4 MiB | 32 sorgenti di interrupt |
| UART | 0x1000_0000 | 256 B | NS16550A, IRQ 10 |
| RAM | 0x8000_0000 | 1 GiB | Configurabile |
| Opzione | Var. Ambiente | Predefinito | Note |
|---|
--ram-size | RAM_SIZE | 1 GB | RAM in byte |
--backend | EMUKO_BACKEND | adaptive | adaptive, arm64_jit, amd64_jit, arm64, x86_64 |
--bootargs | BOOTARGS | console seriale | Riga di comando del kernel |
| Funzionalità | emuko | QEMU | Spike | Renode |
|---|
| JIT / traduzione dinamica | ✅ | ✅ | — | — |
| Salvataggio e ripristino istantanee | ✅ | ✅ | — | ✅ |
| Istantanea automatica periodica | ✅ | — | — | ✅ |
| API HTTP per controllo macchina | ✅ | — | — | — |
| Console UART WebSocket | ✅ | — | — | — |
| Bridge host UART scriptabile | ✅ | — | — | ✅ |
| Caricamento ELF bare-metal (nessun OS) | ✅ | — | — | — |
| Download kernel con un comando + SHA256 | ✅ | — | — | — |
| Controllo differenziale JIT vs interprete | ✅ | — | — | — |
| Debugging GDB | — | ✅ | ✅ | ✅ |
| Ampio ecosistema di dispositivi (PCIe, virtio) | — | ✅ | — | — |
| Simulazione multi-nodo | — | — | — | ✅ |
| Ampia copertura ISA (RVV, crypto, ecc.) | — | — | ✅ | — |