VMM Builder

src/vmm/src/builder.rs — orchestrates microVM creation from configuration

build_microvm() — sequential steps builder.rs:563

1
choose_payload()
builder.rs:532
Selects how the guest will boot. Three options exist depending on what the caller configured.
krunfw bundle
external kernel
firmware

The default path. libkrunfw ships a pre-built kernel + initrd. krunfw_get_kernel() returns a slice of bytes already mapped into the process. Fastest to get started.

source: krunfw crate → kernel bytes embedded in shared library

Caller provides a vmlinux ELF or bzImage path via krun_set_kernel(). The builder opens and maps the file, then loads it into guest RAM using the kernel module.

source: caller-supplied file path in KernelConfig

A UEFI or custom firmware binary. The builder maps it into the top of the guest physical address space (0xFFFFF000 on x86-64). Used for secure VM / TEE boots.

source: VmResources.firmware_path
2
create_guest_memory()
builder.rs:1513
Allocates guest RAM as anonymous mmap regions and bundles them into a GuestMemoryMmap.
  • Low RAM: 0x00000000 → min(mem_size, 3 GiB hole start)
  • High RAM (x86-64): 4 GiB → mem_size if guest RAM > 3 GiB
  • Firmware slot (x86-64): fixed address at top of 32-bit space
  • Initrd: loaded into high memory via read_initrd_image()
  • Kernel / cmdline: written into low memory
3
setup_vm() — register memory with hypervisor
builder.rs:1690
Opens the hypervisor handle and maps every GuestMemoryMmap region into the VM's physical address space.
// Linux path KvmContext::new() // open /dev/kvm Vm::new(kvm_fd) // KVM_CREATE_VM ioctl vstate.rs:489 vm.memory_init(guest_mem) // KVM_SET_USER_MEMORY_REGION per region // macOS path HvfContext::new() // Hypervisor.framework vm.memory_init(guest_mem) // hv_vm_map() per region vstate.rs:94
4
setup_boot_loader() — arch tables
src/arch/
Writes architecture-specific boot structures into guest memory before vCPU threads start.
  • x86-64: zero page (boot_params), GDT, IDT, BIOS/SMBIOS tables, E820 map
  • ARM: device tree blob (DTB) at fixed guest PA
  • RISC-V: device tree blob + SBI firmware setup
5
Create MMIO bus + register virtio devices
bus.rs:114
Constructs each enabled virtio device, wraps it in MmioTransport, and registers it on the MMIO bus. Device addresses are written into the guest's device tree / ACPI tables.
// For each configured device: let device = Block::new(config)?; // or Net, Vsock, Gpu… let transport = MmioTransport::new(device); // virtio MMIO wrapper mmio.rs:61 mmio_bus.insert(transport, base_addr, len); // register address range bus.rs:114
  • Block: one device per disk image; uses worker thread for async I/O
  • Net: TAP fd (Linux) or unix socket; RX/TX queues
  • Vsock: muxer thread + TSI port map device.rs:38
  • GPU (optional): virgl context + SHM regions
  • Console: virtio-console with port multiplexing
  • Entropy: /dev/urandom passthrough
6
Create vCPU threads
vstate.rs:923
One OS thread is spawned per vCPU. Each thread configures CPU registers and then enters the hypervisor execution loop.
for id in 0..vcpu_count { let vcpu = vm.create_vcpu(id)?; vcpu.configure_regs(entry_point, ...)?; // RIP/PC, stack, flags vcpu.configure_msr()?; // x86-64 MSRs vcpu.configure_cpuid(kvm, vm)?; // feature mask thread::spawn(move || vcpu.run()); // → KVM_RUN / hv_vcpu_run vstate.rs:1571 }
7
EventManager.run()
src/polly/event_manager.rs
The main thread enters an epoll loop. All EventFds (virtio queue kicks, interrupts, signals) are registered here. The loop exits only on VM shutdown or fatal error.
  • Queue notify EventFds → wake device worker threads
  • Interrupt EventFds → inject IRQ into vCPU
  • SIGTERM / SIGINT → graceful VM shutdown

Platform backends

Linux · KVM vstate.rs:489

  • Open /dev/kvm
  • KVM_CREATE_VM ioctl
  • KVM_SET_USER_MEMORY_REGION
  • KVM_CREATE_VCPU per thread
  • KVM_RUN in tight loop
  • KVM_EXIT_MMIO for device I/O
  • irqfd / ioeventfd (optional)

macOS · HVF vstate.rs:94

  • hv_vm_create()
  • hv_vm_map() per region
  • hv_vcpu_create() per thread
  • hv_vcpu_run() in loop
  • HV_EXIT_REASON_VTIMER exits
  • MMIO exits via exception bitmap
  • No irqfd — poll-based interrupts
flows into → vCPU Runtime