Core Architecture

Relevant source files

This document provides a detailed examination of axvm's fundamental architecture, focusing on the core components that enable virtual machine creation, management, and execution. It covers the main AxVM struct, its internal organization, lifecycle management, and integration with hardware abstraction layers.

For information about specific vCPU architecture implementations, see Virtual CPU Architecture. For details about hardware abstraction interfaces, see Hardware Abstraction Layer. For VM configuration mechanisms, see Configuration System.

Architecture Overview

The axvm hypervisor is built around a central AxVM struct that coordinates virtual machine execution through a clean separation of concerns. The architecture employs generic type parameters to abstract hardware and vCPU implementations while maintaining compile-time optimization.

flowchart TD
subgraph subGraph4["Generic Type Parameters"]
    HAL["H: AxVMHal"]
    VCPUHAL["U: AxVCpuHal"]
end
subgraph subGraph3["VM Lifecycle Flags"]
    Running["running: AtomicBool"]
    ShuttingDown["shutting_down: AtomicBool"]
end
subgraph subGraph2["Mutable VM State"]
    AddrSpace["address_space: Mutex<AddrSpace<H::PagingHandler>>"]
    PhantomData["_marker: PhantomData<H>"]
end
subgraph subGraph1["Immutable VM State"]
    VMId["id: usize"]
    VMConfig["config: AxVMConfig"]
    VCpuList["vcpu_list: Box[AxVCpuRef<U>]"]
    VMDevices["devices: AxVmDevices"]
end
subgraph subGraph0["Core VM Structure"]
    AxVM["AxVM<H, U>"]
    AxVMInnerConst["AxVMInnerConst<U>"]
    AxVMInnerMut["AxVMInnerMut<H>"]
end

AxVM --> AxVMInnerConst
AxVM --> AxVMInnerMut
AxVM --> HAL
AxVM --> Running
AxVM --> ShuttingDown
AxVM --> VCPUHAL
AxVMInnerConst --> VCpuList
AxVMInnerConst --> VMConfig
AxVMInnerConst --> VMDevices
AxVMInnerConst --> VMId
AxVMInnerMut --> AddrSpace
AxVMInnerMut --> PhantomData

Sources: src/vm.rs(L47 - L53)  src/vm.rs(L31 - L39)  src/vm.rs(L41 - L45) 

Core VM Structure

The AxVM struct is organized into distinct sections that separate immutable configuration data from mutable runtime state. This design ensures thread safety while minimizing lock contention during VM execution.

Data Organization

ComponentTypePurposeThread Safety
runningAtomicBoolVM execution stateLock-free atomic operations
shutting_downAtomicBoolVM shutdown stateLock-free atomic operations
inner_constAxVMInnerConstImmutable VM configurationUnsafe Send/Sync implementation
inner_mutAxVMInnerMutMutable runtime stateMutex-protected access

The immutable section (AxVMInnerConst) contains the VM identifier, configuration, vCPU list, and device registry. The mutable section (AxVMInnerMut) contains the address space with its associated page table handler.

Sources: src/vm.rs(L47 - L53)  src/vm.rs(L31 - L39)  src/vm.rs(L41 - L45) 

VM Creation and Initialization

VM creation follows a multi-stage initialization process that sets up vCPUs, memory regions, and devices before the VM can be executed.

sequenceDiagram
    participant AxVMnew as "AxVM::new()"
    participant vCPUCreation as "vCPU Creation"
    participant MemorySetup as "Memory Setup"
    participant DeviceSetup as "Device Setup"
    participant AddrSpace as "AddrSpace"

    AxVMnew ->> vCPUCreation: "Create VCpus from config"
    Note over vCPUCreation: "Architecture-specific AxVCpuCreateConfig"
    vCPUCreation ->> vCPUCreation: "Arc::new(VCpu::new())"
    AxVMnew ->> MemorySetup: "Process memory_regions()"
    MemorySetup ->> AddrSpace: "AddrSpace::new_empty()"
    loop "For each memory region"
        MemorySetup ->> MemorySetup: "Validate MappingFlags"
    alt "VmMemMappingType::MapIentical"
        MemorySetup ->> AddrSpace: "map_linear()"
    else "VmMemMappingType::MapAlloc"
        MemorySetup ->> AddrSpace: "map_alloc()"
    end
    end
    loop "For each pass_through_device"
        MemorySetup ->> AddrSpace: "map_linear() with DEVICE flags"
    end
    AxVMnew ->> DeviceSetup: "AxVmDevices::new()"
    DeviceSetup ->> DeviceSetup: "Initialize from emu_configs"
    AxVMnew ->> AxVMnew: "Create AxVM struct"
    loop "For each vCPU"
        AxVMnew ->> vCPUCreation: "vcpu.setup(entry, ept_root, config)"
    end

Sources: src/vm.rs(L59 - L219)  src/vm.rs(L95 - L163)  src/vm.rs(L182 - L184)  src/vm.rs(L204 - L217) 

Memory Region Setup

The VM initialization process handles two distinct memory mapping types:

  • VmMemMappingType::MapIentical: Creates identity mappings where guest physical addresses map directly to host physical addresses
  • VmMemMappingType::MapAlloc: Allocates new physical memory pages that may be non-contiguous in host physical memory

The address space spans from VM_ASPACE_BASE (0x0) to VM_ASPACE_SIZE (0x7fff_ffff_f000), providing a large virtual address space for guest execution.

Sources: src/vm.rs(L18 - L19)  src/vm.rs(L122 - L162) 

VM Lifecycle Management

The VM lifecycle is controlled through atomic boolean flags that coordinate state transitions across multiple threads without requiring locks.


State Validation

VM operations include state validation to prevent invalid transitions:

  • boot() checks hardware virtualization support and prevents double-booting
  • shutdown() prevents multiple shutdown attempts
  • run_vcpu() validates vCPU existence before execution

Sources: src/vm.rs(L277 - L288)  src/vm.rs(L299 - L310)  src/vm.rs(L328 - L376) 

vCPU Execution Loop

The core VM execution occurs in the run_vcpu() method, which implements a continuous loop that handles various exit reasons from hardware virtualization.

flowchart TD
Start["run_vcpu(vcpu_id)"]
ValidateVCpu["vcpu(vcpu_id)?"]
BindVCpu["vcpu.bind()"]
RunLoop["vcpu.run()"]
ExitReason["Match exit_reason"]
MmioRead["MmioRead"]
MmioWrite["MmioWrite"]
PageFault["NestedPageFault"]
IoOps["IoRead/IoWrite"]
Other["Other reasons"]
DeviceRead["devices.handle_mmio_read()"]
SetGPR["vcpu.set_gpr()"]
Continue["Continue loop"]
DeviceWrite["devices.handle_mmio_write()"]
HandleFault["address_space.handle_page_fault()"]
Unbind["vcpu.unbind()"]
Return["Return exit_reason"]

BindVCpu --> RunLoop
Continue --> RunLoop
DeviceRead --> SetGPR
DeviceWrite --> Continue
ExitReason --> IoOps
ExitReason --> MmioRead
ExitReason --> MmioWrite
ExitReason --> Other
ExitReason --> PageFault
HandleFault --> Continue
IoOps --> Continue
MmioRead --> DeviceRead
MmioWrite --> DeviceWrite
Other --> Unbind
PageFault --> HandleFault
RunLoop --> ExitReason
SetGPR --> Continue
Start --> ValidateVCpu
Unbind --> Return
ValidateVCpu --> BindVCpu

The execution loop handles several categories of VM exits:

  • MMIO Operations: Delegated to the device emulation layer via AxVmDevices
  • Page Faults: Handled by the address space's page fault handler
  • I/O Operations: Currently handled as no-ops
  • Unhandled Exits: Return control to the caller

Sources: src/vm.rs(L328 - L376)  src/vm.rs(L335 - L372) 

Component Integration

The AxVM struct integrates with several key subsystems through well-defined interfaces:

Address Space Integration

flowchart TD
AxVM["AxVM"]
AddrSpaceMutex["Mutex<AddrSpace<H::PagingHandler>>"]
AddrSpace["AddrSpace"]
PageTableRoot["page_table_root()"]
HandlePageFault["handle_page_fault()"]
TranslateBuffer["translated_byte_buffer()"]
EPTRoot["ept_root() for vCPU setup"]
ImageLoad["get_image_load_region()"]

AddrSpace --> HandlePageFault
AddrSpace --> PageTableRoot
AddrSpace --> TranslateBuffer
AddrSpaceMutex --> AddrSpace
AxVM --> AddrSpaceMutex
PageTableRoot --> EPTRoot
TranslateBuffer --> ImageLoad

Device Integration

flowchart TD
AxVM["AxVM"]
AxVmDevices["AxVmDevices"]
MmioRead["handle_mmio_read()"]
MmioWrite["handle_mmio_write()"]
DeviceConfig["AxVmDeviceConfig"]
EmuConfigs["emu_configs: Vec"]

AxVM --> AxVmDevices
AxVmDevices --> DeviceConfig
AxVmDevices --> MmioRead
AxVmDevices --> MmioWrite
DeviceConfig --> EmuConfigs

vCPU Management

The VM maintains references to vCPUs through Arc<VCpu<AxArchVCpuImpl<U>>> allowing shared ownership across threads while providing architecture-independent access through the AxArchVCpu trait.

Sources: src/vm.rs(L21 - L26)  src/vm.rs(L242 - L250)  src/vm.rs(L260 - L270)  src/vm.rs(L315 - L318) 

Type System and Generics

The architecture leverages Rust's type system to provide compile-time guarantees about hardware compatibility and vCPU implementations:

  • H: AxVMHal: Hardware abstraction layer interface
  • U: AxVCpuHal: vCPU hardware abstraction layer interface
  • Type Aliases: AxVMRef<H, U> and AxVCpuRef<U> provide ergonomic reference types

This design enables architecture-specific optimizations while maintaining a unified API across different hardware platforms.

Sources: src/vm.rs(L21 - L29)  src/lib.rs(L21 - L27)