
Émulateur RISC-V en Rust qui démarre Linux avec JIT sur ARM64/x86_64 et mémoire virtuelle Sv39
Un émulateur RISC-V en Rust. Il démarre Linux.
La machine implémente RV64IMAFDC avec les niveaux de privilège M/S/U et la mémoire virtuelle Sv39.
Elle exécute un JIT sur les hôtes ARM64 et x86_64, avec un interpréteur en secours si nécessaire.
Les périphériques sont UART 16550, CLINT, PLIC et SBI 1.0. Une seule dépendance externe : zstd.
Ce n'est pas l'émulateur le plus rapide. En mode interpréteur, il est environ trois fois plus lent que QEMU. En mode JIT, environ vingt-neuf fois plus lent. Le chaînage de blocs de code n'est pas encore implémenté ; cela améliora les performances. Nous disons cela clairement pour que vous sachiez ce que vous obtenez.
Ce qu'il fait bien : il est simple à utiliser, expose une API HTTP pour le contrôle de la machine, peut exécuter un ELF bare-metal sans noyau, et peut sauvegarder et restaurer l'état complet de la machine. Ce sont des fonctionnalités utiles pour le travail système et les tests.
cargo build --release
Le binaire est target/release/emuko. Créez un alias.
alias emuko=target/release/emuko
emuko dow
Télécharge un noyau et un initrd Debian RISC-V netboot dans ~/.emuko/.
Le SHA256 est vérifié. Aucun noyau propre n'est nécessaire.
emuko start
L'émulateur s'exécute en tant que démon. Vous êtes attaché à sa console. Vous verrez le noyau démarrer. Vous obtiendrez un shell.
| Touche | Effet |
|---|---|
| Ctrl+] | Détachement (le démon continue) |
| Ctrl+C | Interruption dans l'invité |
| Ctrl+D | EOF dans l'invité |
emuko start # rattacher la console
emuko dump # afficher l'état du CPU
emuko stop # suspendre l'exécution
emuko con # continuer
emuko step 1000 # exécuter pas à pas N instructions
emuko snap # prendre un instantané
emuko kill # arrêter
Le démon écoute sur http://127.0.0.1:7788/v1/api/ et accepte les connexions console WebSocket
sur ws://127.0.0.1:7788/v1/ws/uart. Les deux sont utilisables depuis des scripts.
Parfois, vous ne voulez pas de système d'exploitation. Vous voulez la machine, un binaire, et rien d'autre entre eux.
emuko run ./my_program.elf
Le démon réinitialise la machine, charge les segments ELF à leurs adresses physiques, et commence l'exécution. La sortie arrive sur la console UART. Le démon doit déjà être en cours d'exécution.
Pour écrire sur la console depuis le bare-metal : stockez un octet à 0x1000_0000.
Le répertoire examples/ contient des programmes qui s'exécutent de cette façon.
| Exemple | Ce qu'il fait |
|---|---|
bare_printf | Affiche un message toutes les 10 millions d'itérations. Pas de libc. Écriture UART directe. |
Un compilateur croisé RISC-V est nécessaire pour les compiler.
Sur macOS : brew install riscv64-elf-gcc.
Sur Linux : apt install gcc-riscv64-linux-gnu.
emuko start
cd examples/bare_printf
make run
L'état de la machine — registres, mémoire, tout — peut être sauvegardé et restauré.
emuko snap # instantané maintenant
emuko snap 5000000 # instantané automatique toutes les 5M étapes
emuko snap stop # arrêter les instantanés automatiques
emuko ls # lister les instantanés
emuko restore <snapshot> # restaurer
La machine virtuelle utilise une disposition MMIO fixe compatible avec la plateforme virt QEMU RISC-V.
| Région | Base | Taille | Remarques |
|---|---|---|---|
| CLINT | 0x0200_0000 | 64 Kio | Temporisateur et IRQ logicielle |
| PLIC | 0x0C00_0000 | 4 Mio | 32 sources d'interruption |
| UART | 0x1000_0000 | 256 o | NS16550A, IRQ 10 |
| RAM | 0x8000_0000 | 1 Gio | Configurable |
Avec les paramètres par défaut (load_addr=0x80200000, 1 Gio de RAM) :
0x8000_0000 ── Base RAM
(espace — utilisable par les programmes bare-metal)
0x8020_0000 ── Image du noyau
│ .text / .rodata / .data / .bss
└─ fin du noyau
(libre)
── initrd
── DTB
── Region EFI (128 Kio, noyaux PE/UEFI uniquement)
0xBFFF_FFFF ── Fin RAM
Le DTB, l'initrd et l'EFI sont placés vers le bas à partir du sommet de la RAM. L'émulateur vérifie les chevauchements avec le noyau au démarrage et s'arrête avec une erreur claire si la RAM est trop petite.
Les segments PT_LOAD de l'ELF sont placés à leurs adresses p_vaddr.
bare_printf est lié à 0x8000_0000 :
0x8000_0000 ── .text
── .rodata
── .data
── .bss (mis à zéro par start.S)
── pile (16 Kio au-dessus de BSS)
Pas de noyau. Pas d'initrd. Pas de DTB. Les registres démarrent à zéro sauf sp,
que l'émulateur initialise à ram_base + 0x100000 avant que start.S ne prenne le relais.
Les options peuvent être passées en ligne de commande, définies comme variables d'environnement ou placées dans emuko.yml.
| Option | Variable d'env | Défaut | Remarques |
|---|---|---|---|
--ram-size | RAM_SIZE | 1 Go | RAM en octets |
--backend | EMUKO_BACKEND | adaptive | adaptive, arm64_jit, amd64_jit, arm64, x86_64 |
--bootargs | BOOTARGS | console série | Ligne de commande du noyau |
Comparaison directe avec les émulateurs RISC-V couramment utilisés.
✅ = supporté et documenté. — = non intégré.
| Fonctionnalité | emuko | QEMU | Spike | Renode |
|---|---|---|---|---|
| Traduction JIT/dynamique | ✅ | ✅ | — | — |
| Sauvegarde et restauration d'instantané | ✅ | ✅ | — | ✅ |
| Instantané automatique périodique | ✅ | — | — | ✅ |
| API HTTP pour le contrôle machine | ✅ | — | — | — |
| Console UART WebSocket | ✅ | — | — | — |
| Pont UART hôte scriptable | ✅ | — | — | ✅ |
| Téléchargement d'ELF bare-metal (sans OS) | ✅ | — | — | — |
| Téléchargement du noyau en une commande + SHA256 | ✅ | — | — | — |
| Vérificateur différentiel JIT vs interpréteur | ✅ | — | — | — |
| Débogage GDB | — | ✅ | ✅ | ✅ |
| Grand écosystème de périphériques (PCIe, virtio) | — | ✅ | — | — |
| Simulation multi-nœuds | — | — | — | ✅ |
| Large couverture ISA (RVV, crypto, etc.) | — | — | ✅ | — |
Sources : QEMU virt · Spike · Renode
Apache 2.0. Voir LICENSE.