Virtual Machines
Complete guide to VM lifecycle management, vCPU topology and register-level control, PCI device assignment and passthrough, snapshots, cloning, guest agent integration, and resource limits. For initial VM creation walkthrough, see Getting Started.
VM Lifecycle #
A VM progresses through a defined set of states. State transitions are triggered by CLI commands, API calls, or internal events (e.g., guest-initiated shutdown via ACPI).
| Transition | CLI Command | What Happens Internally |
|---|---|---|
| → CREATED | vm create --config | Parse JSON, allocate VMCS/VMCB per vCPU, build EPT/NPT, initialize devices, allocate guest RAM |
| CREATED → RUNNING | vm start | Load guest firmware (OVMF/SeaBIOS) at reset vector, execute VMLAUNCH/VMRUN on all vCPUs |
| RUNNING → PAUSED | vm pause | Send IPI to all vCPUs, each executes VM-exit, mark vCPUs as de-scheduled |
| PAUSED → RUNNING | vm resume | Re-schedule vCPUs, VMRESUME on next scheduler tick |
| RUNNING → STOPPED | vm stop | Inject ACPI power button (graceful) or force VM-exit and teardown (--force) |
| RUNNING → MIGRATING | vm migrate | PQC key exchange with target, begin dirty page tracking, iterative memory transfer |
| * → DESTROYED | vm destroy | Release VMCS/VMCB, free EPT/NPT, release RAM pages, tear down device emulation |
VM Management API (C) #
The hypervisor kernel exposes C functions for VM lifecycle management in hypervisor/core/vm/vm.h:
/* VM lifecycle */
struct vm *vm_create(const char *name, uint32_t max_vcpus, uint64_t ram_size);
void vm_destroy(struct vm *vm);
int vm_start(struct vm *vm);
int vm_stop(struct vm *vm);
int vm_pause(struct vm *vm);
int vm_resume(struct vm *vm);
int vm_reset(struct vm *vm);
/* vCPU management */
int vm_add_vcpu(struct vm *vm, uint32_t vcpu_id);
struct vcpu *vm_get_vcpu(struct vm *vm, uint32_t vcpu_id);
/* Memory management */
int vm_add_memory_region(struct vm *vm, uint64_t gpa_base, uint64_t size, uint32_t flags);
void *vm_gpa_to_hva(struct vm *vm, uint64_t gpa);
int vm_read_memory(struct vm *vm, uint64_t gpa, void *buf, size_t len);
int vm_write_memory(struct vm *vm, uint64_t gpa, const void *buf, size_t len);
vCPU Management #
vCPU Topology
QuantaVirt presents configurable CPU topology to the guest through CPUID leaves and ACPI SRAT/SLIT tables. The guest sees the specified socket/core/thread topology, enabling proper NUMA-aware workload placement inside the VM.
| Topology Element | Config Field | Guest Visibility |
|---|---|---|
| Sockets | cpu.topology.sockets | CPUID leaf 0x1F / ACPI SRAT |
| Cores per socket | cpu.topology.cores | CPUID leaf 0x1F level 1 |
| Threads per core | cpu.topology.threads | CPUID leaf 0x1F level 0 (SMT) |
| NUMA nodes | cpu.numa_node | ACPI SRAT proximity domains |
CPU Pinning
# Pin vCPU 0 to physical CPU 4, vCPU 1 to physical CPU 5
quantavirt vm set myvm --cpu-pin 0:4,1:5
# Show current pinning
quantavirt vm show myvm --cpu-pin
# vCPU 0 → pCPU 4 (NUMA node 0)
# vCPU 1 → pCPU 5 (NUMA node 0)
# Clear pinning (return to scheduler-managed)
quantavirt vm set myvm --cpu-pin auto
vCPU API (C) #
Register-level vCPU control from hypervisor/core/vm/vcpu.h:
/* vCPU lifecycle */
struct vcpu *vcpu_create(struct vm *vm, uint32_t vcpu_id);
void vcpu_destroy(struct vcpu *vcpu);
int vcpu_reset(struct vcpu *vcpu, uint64_t boot_ip);
int vcpu_run(struct vcpu *vcpu); /* Enter VM, returns on VM-exit */
void vcpu_kick(struct vcpu *vcpu); /* Force VM-exit via IPI */
int vcpu_step(struct vcpu *vcpu); /* Single-step one instruction */
/* Register access — general purpose (RAX through R15, RIP, RFLAGS, RSP) */
int vcpu_get_regs(struct vcpu *vcpu, struct vcpu_regs *regs);
int vcpu_set_regs(struct vcpu *vcpu, const struct vcpu_regs *regs);
uint64_t vcpu_get_reg(struct vcpu *vcpu, enum vcpu_reg reg);
void vcpu_set_reg(struct vcpu *vcpu, enum vcpu_reg reg, uint64_t value);
/* Interrupt/exception injection */
int vcpu_queue_interrupt(struct vcpu *vcpu, uint8_t vector);
int vcpu_queue_exception(struct vcpu *vcpu, uint8_t vector, uint32_t error_code);
int vcpu_queue_nmi(struct vcpu *vcpu);
/* Convenience: inject common exceptions */
int vcpu_inject_gp(struct vcpu *vcpu, uint32_t error_code); /* #GP */
int vcpu_inject_ud(struct vcpu *vcpu); /* #UD */
int vcpu_inject_pf(struct vcpu *vcpu, uint64_t fault_addr, uint32_t error_code); /* #PF */
PCI Device Assignment #
QuantaVirt supports PCIe device passthrough via IOMMU (VT-d/AMD-Vi), allowing a physical PCIe device to be assigned directly to a VM with near-native performance. The IOMMU provides DMA isolation, ensuring the passthrough device can only access the assigned VM's memory.
# List available PCI devices for passthrough
quantavirt system pci-list --available
# BDF Vendor Device Class IOMMU Group
# 0000:04:00.0 10DE 2684 3D Controller 5
# 0000:05:00.0 8086 1572 Ethernet 7
# Assign GPU to VM
quantavirt vm set gpu-vm --pci-add 0000:04:00.0
# Or in configuration JSON:
"devices": {
"pci_passthrough": [
{ "bdf": "0000:04:00.0", "type": "gpu" },
{ "bdf": "0000:05:00.0", "type": "nic" }
]
}
iommu=on in the hypervisor boot parameters. All devices in the same IOMMU group must be assigned to the same VM.Snapshots & Cloning #
# Create snapshot (disk + memory state if running)
quantavirt vm snapshot create myvm --name before-update
# List snapshots
quantavirt vm snapshot list myvm
# NAME CREATED SIZE STATE
# before-update 2026-01-15 14:30:00 1.2 GiB running
# Restore snapshot
quantavirt vm snapshot restore myvm --name before-update
# Delete snapshot
quantavirt vm snapshot delete myvm --name before-update
# Clone a VM (creates independent copy)
quantavirt vm clone myvm --name myvm-clone
# New disk image created via qcow2 copy-on-write
# New MAC address auto-generated
# New UUID auto-generated
Guest Agent #
The QuantaVirt Guest Agent runs inside the VM and enables enhanced management capabilities: graceful shutdown, filesystem freeze/thaw for consistent snapshots, network information reporting, and PQC attestation from within the guest.
| Feature | Without Agent | With Agent |
|---|---|---|
| Shutdown | ACPI power button only | Clean OS shutdown with service stop |
| Snapshots | Crash-consistent (disk only) | Application-consistent (fs freeze + disk) |
| IP Reporting | DHCP lease parsing | Real-time from guest network stack |
| Time Sync | PV clock only | NTP + PV clock + agent sync |
| PQC Attestation | Hypervisor-side only | Guest-initiated attestation with guest measurements |
# Install guest agent inside the VM
# Ubuntu/Debian:
sudo apt install quantavirt-guest-agent
sudo systemctl enable --now quantavirt-guest-agent
# RHEL/Fedora:
sudo dnf install quantavirt-guest-agent
sudo systemctl enable --now quantavirt-guest-agent
Resource Limits #
| Resource | CLI Flag | Range | Description |
|---|---|---|---|
| CPU weight | --cpu-weight | 1 – 65535 | Proportional CPU share (default 256) |
| CPU cap | --cpu-cap | 0 – 100 | Maximum % of one pCPU (0 = unlimited) |
| I/O bandwidth | --io-limit | bytes/sec | Per-disk I/O throughput limit |
| I/O IOPS | --iops-limit | ops/sec | Per-disk IOPS limit |
| Network bandwidth | --net-limit | bits/sec | Per-interface network bandwidth cap |
Hot-Plug Support #
| Resource | Hot-Add | Hot-Remove | Guest Requirements |
|---|---|---|---|
| vCPUs | ✅ | âš ï¸ (guest must support) | ACPI CPU hotplug support in guest kernel |
| Memory | ✅ | âš ï¸ (via balloon) | VirtIO memory balloon driver or ACPI memory hotplug |
| VirtIO-blk disk | ✅ | ✅ | VirtIO PCI device support |
| VirtIO-net NIC | ✅ | ✅ | VirtIO PCI device support |
| USB device | ✅ | ✅ | USB support in guest |
| PCI passthrough | âš ï¸ Beta | âš ï¸ Beta | PCIe native hotplug in guest |
# Hot-add a disk to a running VM
quantavirt vm disk-add myvm --type virtio-blk --path /var/lib/quantavirt/images/data.qcow2
# Hot-add a NIC
quantavirt vm nic-add myvm --type virtio-net --network office-lan
# Hot-add vCPUs (increase from 2 to 4)
quantavirt vm set myvm --vcpus 4