Per-CPU State Management

Relevant source files

This document covers the per-CPU state management system in the arm_vcpu hypervisor, which handles virtualization control and interrupt management on a per-processor basis. The system is responsible for enabling/disabling hardware virtualization features, managing exception vectors, and coordinating interrupt handling between the hypervisor and host OS.

For information about the overall VCPU lifecycle and operations, see 2.1. For details about context switching and register state management, see 3.

Per-CPU Data Structure

The core of per-CPU state management is the Aarch64PerCpu structure, which implements the AxArchPerCpu trait to provide processor-specific virtualization control.

Aarch64PerCpu Structure

classDiagram
note for Aarch64PerCpu "4096-byte alignedRepresents per-CPU statefor virtualization control"
class Aarch64PerCpu {
    +cpu_id: usize
    -_phantom: PhantomData~H~
    +new(cpu_id: usize) AxResult~Self~
    +is_enabled() bool
    +hardware_enable() AxResult
    +hardware_disable() AxResult
}

class AxArchPerCpu {
    <<trait>>
    
    +new(cpu_id: usize) AxResult~Self~
    +is_enabled() bool
    +hardware_enable() AxResult
    +hardware_disable() AxResult
}

class AxVCpuHal {
    <<trait>>
    
    +irq_hanlder()
}

Aarch64PerCpu  ..|>  AxArchPerCpu : implements
Aarch64PerCpu  -->  AxVCpuHal : uses H generic

Sources: src/pcpu.rs(L10 - L16) 

The structure is aligned to 4096 bytes and contains minimal data, serving primarily as a coordination point for per-CPU virtualization operations. The generic parameter H provides hardware abstraction through the AxVCpuHal trait.

Per-CPU Variables

The system uses two key per-CPU variables to manage state across processor cores:

VariableTypePurpose
ORI_EXCEPTION_VECTOR_BASEusizeStores originalVBAR_EL2value before virtualization
IRQ_HANDLEROnceCell<&(dyn Fn() + Send + Sync)>Host OS IRQ handler for this CPU

Exception Vector Management

stateDiagram-v2
state HostVectors {
    [*] --> OriginalVBAR
    OriginalVBAR : "VBAR_EL2 = host exception vectors"
    OriginalVBAR : "Stored in ORI_EXCEPTION_VECTOR_BASE"
}
state VCpuVectors {
    [*] --> VCpuVBAR
    VCpuVBAR : "VBAR_EL2 = exception_vector_base_vcpu"
    VCpuVBAR : "Handles VM exits and traps"
}
[*] --> HostVectors : "Initial state"
HostVectors --> VCpuVectors : "hardware_enable()"
VCpuVectors --> HostVectors : "hardware_disable()"
note left of VCpuVectors : ['exception_vector_base_vcpu()<br>defined in assembly']

Sources: src/pcpu.rs(L18 - L19)  src/pcpu.rs(L28 - L30)  src/pcpu.rs(L53 - L57)  src/pcpu.rs(L74 - L77) 

Hardware Virtualization Control

The per-CPU system manages the AArch64 virtualization extensions through the Hypervisor Configuration Register (HCR_EL2).

Virtualization State Management

flowchart TD
subgraph subGraph0["HCR_EL2 Configuration"]
    G1["HCR_EL2::VM::Enable"]
    G2["HCR_EL2::RW::EL1IsAarch64"]
    G3["HCR_EL2::IMO::EnableVirtualIRQ"]
    G4["HCR_EL2::FMO::EnableVirtualFIQ"]
    G5["HCR_EL2::TSC::EnableTrapEl1SmcToEl2"]
end
A["new(cpu_id)"]
B["Register IRQ handler"]
C["Per-CPU instance ready"]
D["hardware_enable()"]
E["Save original VBAR_EL2"]
F["Set VCPU exception vectors"]
G["Configure HCR_EL2"]
H["Virtualization enabled"]
I["is_enabled() returns true"]
J["hardware_disable()"]
K["Restore original VBAR_EL2"]
L["Clear HCR_EL2.VM"]
M["Virtualization disabled"]

A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> G1
G --> G2
G --> G3
G --> G4
G --> G5
G --> H
H --> I
H --> J
J --> K
K --> L
L --> M

Sources: src/pcpu.rs(L32 - L78) 

HCR_EL2 Register Configuration

When enabling virtualization, the system configures several key control bits:

Bit FieldSettingPurpose
VMEnableEnables virtualization extensions
RWEL1IsAarch64Sets EL1 execution state to AArch64
IMOEnableVirtualIRQRoutes IRQs to virtual interrupt controller
FMOEnableVirtualFIQRoutes FIQs to virtual interrupt controller
TSCEnableTrapEl1SmcToEl2Traps SMC instructions from EL1 to EL2

Sources: src/pcpu.rs(L59 - L65) 

IRQ Handler Integration

The per-CPU system coordinates interrupt handling between the hypervisor and host OS through a registered handler mechanism.

IRQ Handler Registration

sequenceDiagram
    participant HostOS as Host OS
    participant Aarch64PerCpunew as Aarch64PerCpu::new()
    participant IRQ_HANDLER as IRQ_HANDLER
    participant AxVCpuHalirq_hanlder as AxVCpuHal::irq_hanlder()

    HostOS ->> Aarch64PerCpunew: Create per-CPU instance
    Aarch64PerCpunew ->> IRQ_HANDLER: Get current CPU's IRQ_HANDLER
    Aarch64PerCpunew ->> AxVCpuHalirq_hanlder: Call H::irq_hanlder()
    AxVCpuHalirq_hanlder -->> Aarch64PerCpunew: Return handler function
    Aarch64PerCpunew ->> IRQ_HANDLER: Set handler in OnceCell
    IRQ_HANDLER -->> Aarch64PerCpunew: Registration complete
    Aarch64PerCpunew -->> HostOS: Per-CPU instance ready
    Note over IRQ_HANDLER: Handler stored as<br>per-CPU variable<br>for current processor

Sources: src/pcpu.rs(L21 - L26)  src/pcpu.rs(L34 - L37) 

The IRQ handler is set once per CPU during initialization and provides a mechanism for the hypervisor's exception handling system to dispatch interrupts back to the host OS when appropriate.

Integration with VCPU System

The per-CPU state management integrates closely with the broader VCPU lifecycle:

Per-CPU and VCPU Relationship

flowchart TD
subgraph subGraph2["Host OS Integration"]
    HostIRQ["Host IRQ Handler"]
    HostVectors["Host Exception Vectors"]
end
subgraph subGraph1["VCPU Operations"]
    VCPUCreate["Aarch64VCpu creation"]
    VCPURun["vcpu.run()"]
    ExceptionVectors["exception_vector_base_vcpu"]
end
subgraph subGraph0["CPU Core N"]
    PerCPU["Aarch64PerCpu<H>"]
    VBAR["VBAR_EL2 Register"]
    HCR["HCR_EL2 Register"]
    IRQVar["IRQ_HANDLER per-CPU var"]
end
note1["hardware_enable() sets upvirtualization for this CPU"]
note2["hardware_disable() restoresoriginal host state"]

ExceptionVectors --> VBAR
IRQVar --> HostIRQ
PerCPU --> HCR
PerCPU --> HostVectors
PerCPU --> IRQVar
PerCPU --> VBAR
PerCPU --> note1
PerCPU --> note2
VCPUCreate --> PerCPU
VCPURun --> PerCPU

Sources: src/pcpu.rs(L45 - L78) 

The per-CPU system provides the foundation for VCPU operations by ensuring that hardware virtualization extensions are properly configured and that interrupt handling is coordinated between the hypervisor and host OS on each processor core.