Nesthost logo

Rust · type-1 hypervisor, from scratch

Watch a hypervisor
keep guests apart.

Nesthost is a deterministic type-1 hypervisor simulator in pure Rust std, with zero dependencies. It runs several guest VMs on one emulated CPU and models the three jobs a real virtual machine monitor does: time slicing vCPUs with a bounded round robin, translating each guest's memory through its own second level page table, and trapping privileged instructions to emulate them. Step through it in the browser and watch guests stay isolated, a rogue guest fault while leaking nothing, and the VM exit log fill in.

Open the simulator View on GitHub
How to use this playground
  1. Step runs exactly one guest instruction. Watch the active guest card, its registers, and the exit log. When a guest hits Out, a device IO exit appears and one character lands on that guest's console.
  2. Run plays steps automatically. Pause stops the playback where it is, and Step still works while paused.
  3. Reset rebuilds the machine from scratch. Because everything is deterministic, a fresh Reset then Run reproduces the identical schedule, exits, and output every time.
  4. In the Memory map, notice each host frame is owned by exactly one guest, and the page tables never overlap. That disjointness is what keeps guests isolated.
  5. Watch the rogue guest. It writes safely inside its own page, then reads guest address 9999, which it has no mapping for. That produces a fault exit in red and stops the guest. It never sees another guest's data.

A two minute guided tour

  1. Press Reset, then Step a few times. The first guest sets a register, then traps on Out, and a letter appears on its console.
  2. Keep stepping. After the quantum the timeline shows the slice ending and the next guest gets the CPU. This is the round robin.
  3. When the rogue guest runs, its out of bounds read turns into a red fault in the exit log and its state badge flips to faulted.
  4. Press Run to finish. Compare the two printing guests' consoles. They built their strings independently, in isolated memory, while sharing one CPU.
  5. Press Reset and Run again. Identical result. That is the determinism gate in action.

Live machine one physical CPU, three guest VMs, quantum of 3 instructions

Press Step to advance one guest instruction at a time, or Run to let it play out. The whole run is deterministic, so Reset then Run always produces the same schedule, the same exits, and the same output.

3guest VMs
1physical CPU
3instr quantum
0dependencies

the machine the playground builds: three guest vCPUs time sliced across one CPU, the same shape the Rust core runs. the status line above updates live as you step.

Guest VMs each with its own vCPU, address space, and console

The highlighted card is the guest currently holding the physical CPU. Two guests print a short string. The third, "rogue", tries to read outside its mapped memory.

Memory map guest physical (GPA) to host physical (HPA)

Host physical memory is a shared pool of frames. Each guest's page table maps its own guest pages to a disjoint set of host frames, so no guest can name another guest's memory. An access to an unmapped guest page faults instead of reaching some other frame.

Host physical frames (who owns each)

Per guest page tables

vCPU schedule timeline deterministic round robin

Each block is one time slice: the hypervisor entered a guest and let it run until the quantum, a halt, or a fault. Blocks appear in the order the scheduler ran them.

No slices yet. Press Step or Run.

VM exit log trap and emulate

Every privileged instruction traps here. A console write is a device IO exit, a control register write is a SetCr exit, and reaching unmapped memory is a fault exit. The hypervisor emulates each one, then resumes the guest.

No exits yet.

One command, the whole machine on screen

The demo boots four guests on one CPU, prints the memory map and the round robin schedule, then the VM exit log where every privileged instruction traps. A rogue guest reaches an unmapped address and faults, leaking nothing. This is a real, trimmed run.

$ cargo run --release == Nesthost: deterministic type-1 hypervisor simulator == Booting 4 guests on 1 physical CPU. VM exit log (trap and emulate): tick 1 guest 2 "rogue" pc 4 MemFault { gpa: 9999, access: Read, kind: Unmapped } tick 2 guest 0 "hello" pc 18 DeviceIo { port: 0, value: 72 } tick 3 guest 3 "ringer" pc 19 DeviceIo { port: 208, value: 0 } tick 4 guest 3 "ringer" pc 20 Halt tick 16 guest 1 "world" pc 24 Halt Per guest console output (isolated buffers): guest 0 "hello" state Halted io_exits 5 faults 0 output: "Hello" guest 1 "world" state Halted io_exits 6 faults 0 output: "world!" guest 2 "rogue" state Faulted io_exits 0 faults 1 output: "" guest 3 "ringer" state Halted io_exits 1 faults 0 output: "" Shared ring device (guest to host, via doorbell trap): guest 3 drained 5 entries, host received: "ring!" Totals: 12 scheduler rounds, 29 VM entries, 16 VM exits. Isolation holds: guest "rogue" faulted reaching an unmapped GPA and leaked nothing.

How it relates to a real hypervisor

Nesthost is a teaching accurate model, not a production VMM. There is no hardware, no VT-x or AMD-V, no host kernel. What it keeps is the shape of the three jobs a real monitor does, small enough to read in an afternoon.

KVM, Xen, VMware ESXi

Real type-1 hypervisors. They run guests on real CPUs with hardware assisted virtualization, and their core ideas are buried under hardware interfaces, drivers, and performance work.

Small CPU emulators

Usually model one CPU running one program. They do not nest many guests under one monitor, so the parts that make virtualization interesting are absent.

Nesthost

The readable middle. Every mechanism is a plain Rust data structure: second level address translation, VM exits and entries on privileged instructions, per guest isolation, and deterministic time slicing. You can run every claim as a test.

The mechanisms it models

The parts that make a hypervisor a hypervisor

scheduler vCPU scheduling

One physical CPU is time sliced across guest vCPUs with a deterministic round robin, bounded by a round budget so a guest that never halts cannot hang the host.

memory Second level translation

Each guest has its own guest physical address space. A per guest page table maps GPA to HPA, so a guest can only reach host frames mapped into its own space.

trap Trap and emulate

A privileged instruction does not run in guest context. It takes a VM exit to the hypervisor, which emulates the effect and resumes the guest with a VM entry.

exit VM exits and entries

Device IO, control register writes, halts, and memory faults each surface as a typed exit reason the host handles, then the guest is re-entered.

device Shared ring device

A virtio style shared memory ring lets one guest hand payloads to the host through a single explicitly shared frame, drained only on a doorbell trap.

gate The correctness gates

Isolation, trap and emulate, determinism, and the shared ring are each proven in tests/gates.rs, backed by a stress harness that feeds tens of thousands of malformed programs.

It really keeps guests apart

The playground is a teaching model, but the Rust core proves the same claims for real. The gates live in tests/gates.rs, each proving one property, backed by a bounded stress harness in tests/stress.rs that feeds tens of thousands of malformed programs and asserts no panic, no hang, and that isolation still holds.

# the randomized gates and the stress harness are bounded and controllable
NESTHOST_FUZZ_OPS=50000 NESTHOST_SEED=1 cargo test
     Running tests/gates.rs
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Use it

Nesthost is a library plus a small binary, pure Rust std with zero dependencies. Drive it from your own code or run the demo.

Library

Build a Hypervisor, add guests with disjoint frames, opt in to a shared frame or a ring, then run(). PageTable::translate is the only path a guest has to host memory.

CLI binary

cargo run --release boots the demo; --help prints usage. The whole run is deterministic, so it reproduces bit for bit.

Gates and stress

cargo test runs the correctness gates in tests/gates.rs and the bounded fuzz stress in tests/stress.rs, tunable through NESTHOST_FUZZ_OPS and NESTHOST_SEED.

# run the demo: four guests, the memory map, the schedule, the exit log
cargo run --release

# usage, and the full test suite plus the correctness gates
cargo run --release -- --help
cargo test