VMCS Field Management

Relevant source files

This document covers the Virtual Machine Control Structure (VMCS) field management system within the VMX virtualization engine. The VMCS is Intel's hardware structure that controls virtual machine behavior, and this module provides type-safe access patterns, control field manipulation algorithms, and VM exit information gathering mechanisms.

For Virtual CPU lifecycle management and VM execution flow, see Virtual CPU Management. For the underlying VMX data structures that contain VMCS regions, see VMX Data Structures.

VMCS Field Organization

The VMCS contains hundreds of fields organized into distinct categories based on their purpose and access patterns. The hypervisor provides type-safe enums for each category, ensuring correct field access and preventing runtime errors.

flowchart TD
subgraph subGraph5["Access Implementations"]
    ReadImpl["vmcs_read! macrogenerates .read() methods"]
    WriteImpl["vmcs_write! macrogenerates .write() methods"]
    ROFields["define_vmcs_fields_ro!read-only field traits"]
    RWFields["define_vmcs_fields_rw!read-write field traits"]
end
subgraph subGraph4["VMCS Field Categories"]
    subgraph subGraph3["Read-Only Data Fields"]
        ReadOnly32["VmcsReadOnly32EXIT_REASON, VM_INSTRUCTION_ERROR"]
        ReadOnly64["VmcsReadOnly64GUEST_PHYSICAL_ADDR"]
        ReadOnlyNW["VmcsReadOnlyNWEXIT_QUALIFICATION, GUEST_LINEAR_ADDR"]
    end
    subgraph subGraph2["Host State Fields"]
        Host16["VmcsHost16ES_SELECTOR, TR_SELECTOR"]
        Host32["VmcsHost32IA32_SYSENTER_CS"]
        Host64["VmcsHost64IA32_PAT, IA32_EFER"]
        HostNW["VmcsHostNWCR0, RSP, RIP"]
    end
    subgraph subGraph1["Guest State Fields"]
        Guest16["VmcsGuest16ES_SELECTOR, CS_SELECTOR"]
        Guest32["VmcsGuest32ES_LIMIT, INTERRUPTIBILITY_STATE"]
        Guest64["VmcsGuest64IA32_EFER, IA32_PAT"]
        GuestNW["VmcsGuestNWCR0, RSP, RIP, RFLAGS"]
    end
    subgraph subGraph0["Control Fields"]
        Control16["VmcsControl16VPID, EPTP_INDEX"]
        Control32["VmcsControl32EXEC_CONTROLS, EXCEPTION_BITMAP"]
        Control64["VmcsControl64IO_BITMAP_A_ADDR, MSR_BITMAPS_ADDR"]
        ControlNW["VmcsControlNWCR0_GUEST_HOST_MASK, CR4_READ_SHADOW"]
    end
end

Control16 --> RWFields
Control32 --> RWFields
Control64 --> RWFields
ControlNW --> RWFields
Guest16 --> RWFields
Guest32 --> RWFields
Guest64 --> RWFields
GuestNW --> RWFields
Host16 --> RWFields
Host32 --> RWFields
Host64 --> RWFields
HostNW --> RWFields
ROFields --> ReadImpl
RWFields --> ReadImpl
RWFields --> WriteImpl
ReadOnly32 --> ROFields
ReadOnly64 --> ROFields
ReadOnlyNW --> ROFields

Sources: src/vmx/vmcs.rs(L85 - L486) 

Field Access Patterns

The system uses code generation macros to create consistent, type-safe access patterns for all VMCS fields. These macros handle the underlying vmread and vmwrite instructions while providing error handling and architecture-specific adaptations.

Read/Write Macro Implementation

flowchart TD
subgraph subGraph3["Architecture Handling"]
    Arch64["64-bit: Direct access"]
    Arch32["32-bit: Split high/low"]
end
subgraph subGraph2["Hardware Instructions"]
    VmreadInstr["vmx::vmread()"]
    VmwriteInstr["vmx::vmwrite()"]
end
subgraph subGraph1["Generated Methods"]
    ReadMethod[".read() -> AxResult<T>"]
    WriteMethod[".write(value: T) -> AxResult"]
end
subgraph subGraph0["Field Access Macros"]
    VmcsRead["vmcs_read! macro"]
    VmcsWrite["vmcs_write! macro"]
    DefineRO["define_vmcs_fields_ro!"]
    DefineRW["define_vmcs_fields_rw!"]
end

DefineRO --> ReadMethod
DefineRW --> ReadMethod
DefineRW --> WriteMethod
ReadMethod --> VmreadInstr
VmcsRead --> ReadMethod
VmcsWrite --> WriteMethod
VmreadInstr --> Arch32
VmreadInstr --> Arch64
VmwriteInstr --> Arch32
VmwriteInstr --> Arch64
WriteMethod --> VmwriteInstr

The vmcs_read! and vmcs_write! macros generate implementations that automatically handle 32-bit vs 64-bit architecture differences. On 32-bit systems, 64-bit fields require two separate hardware accesses to read the high and low portions.

Sources: src/vmx/vmcs.rs(L19 - L83) 

VM Exit Information Gathering

When a VM exit occurs, the hypervisor must gather information about why the exit happened and the guest's state. The VMCS provides read-only fields containing this information, which the system abstracts into structured data types.

sequenceDiagram
    participant GuestVM as "Guest VM"
    participant VMXHardware as "VMX Hardware"
    participant VMCSFields as "VMCS Fields"
    participant exit_info as "exit_info()"
    participant ExitHandler as "Exit Handler"

    GuestVM ->> VMXHardware: "Instruction causes VM exit"
    VMXHardware ->> VMCSFields: "Populate exit fields"
    Note over VMCSFields: EXIT_REASON<br>EXIT_QUALIFICATION<br>VMEXIT_INSTRUCTION_LEN<br>Guest RIP
    ExitHandler ->> exit_info: "Call exit_info()"
    exit_info ->> VMCSFields: "VmcsReadOnly32::EXIT_REASON.read()"
    exit_info ->> VMCSFields: "VmcsReadOnly32::VMEXIT_INSTRUCTION_LEN.read()"
    exit_info ->> VMCSFields: "VmcsGuestNW::RIP.read()"
    exit_info ->> ExitHandler: "VmxExitInfo struct"
    ExitHandler ->> ExitHandler: "Process exit reason"

Exit Information Structures

The system defines several structured types for different categories of VM exit information:

StructurePurposeKey Fields
VmxExitInfoGeneral exit informationexit_reason,entry_failure,guest_rip
VmxInterruptInfoInterrupt/exception detailsvector,int_type,err_code
VmxIoExitInfoI/O instruction exitsport,access_size,is_in
CrAccessInfoControl register accesscr_number,access_type,gpr

Sources: src/vmx/vmcs.rs(L488 - L582)  src/vmx/vmcs.rs(L645 - L774) 

Control Field Management

Control fields determine VM behavior and require careful management to ensure compatibility with the underlying hardware. The set_control() function implements the Intel-specified algorithm for safely setting control bits while respecting hardware capabilities.

flowchart TD
subgraph subGraph1["Capability Check"]
    MSRRead["capability_msr.read()"]
    Allowed0["allowed0 = cap[31:0](must be 1)"]
    Allowed1["allowed1 = cap[63:32](may be 1)"]
    Flexible["flexible = !allowed0 & allowed1"]
end
subgraph subGraph0["Control Setting Algorithm"]
    Input["set_control(control, msr, old, set, clear)"]
    ReadMSR["Read capability MSR"]
    ExtractBits["Extract allowed0/allowed1"]
    ValidateConflict["Validate set & clear don't conflict"]
    ValidateAllowed1["Validate set bits allowed in allowed1"]
    ValidateAllowed0["Validate clear bits allowed in allowed0"]
    CalculateValue["Calculate final value:fixed1 | default | set"]
    WriteVMCS["Write to VMCS field"]
end

Allowed0 --> Flexible
Allowed1 --> Flexible
CalculateValue --> WriteVMCS
ExtractBits --> Allowed0
ExtractBits --> Allowed1
ExtractBits --> ValidateConflict
Flexible --> CalculateValue
Input --> ReadMSR
MSRRead --> ExtractBits
ReadMSR --> MSRRead
ValidateAllowed0 --> CalculateValue
ValidateAllowed1 --> ValidateAllowed0
ValidateConflict --> ValidateAllowed1

The algorithm follows Intel SDM Volume 3C, Section 31.5.1, Algorithm 3, ensuring that control bits are set correctly based on processor capabilities.

Sources: src/vmx/vmcs.rs(L589 - L631) 

Event Injection

The hypervisor can inject interrupts and exceptions into the guest using VMCS entry control fields. The inject_event() function handles the complex logic of setting up proper event injection based on the event type.

Event Injection Flow

flowchart TD
subgraph subGraph1["VMCS Fields Updated"]
    EntryErrCode["VMENTRY_EXCEPTION_ERR_CODE"]
    EntryInstrLen["VMENTRY_INSTRUCTION_LEN"]
    EntryIntInfo["VMENTRY_INTERRUPTION_INFO_FIELD"]
end
subgraph subGraph0["Event Injection Process"]
    InjectCall["inject_event(vector, err_code)"]
    DetermineType["Determine VmxInterruptionType from vector"]
    HandleError["Handle error code:- Required by vector type?- Use provided or exit code"]
    CreateInfo["Create VmxInterruptInfo"]
    WriteErrorCode["Write VMENTRY_EXCEPTION_ERR_CODE"]
    HandleSoft["For soft interrupts:Set VMENTRY_INSTRUCTION_LEN"]
    WriteIntInfo["Write VMENTRY_INTERRUPTION_INFO_FIELD"]
end

CreateInfo --> WriteErrorCode
DetermineType --> HandleError
HandleError --> CreateInfo
HandleSoft --> EntryInstrLen
HandleSoft --> WriteIntInfo
InjectCall --> DetermineType
WriteErrorCode --> EntryErrCode
WriteErrorCode --> HandleSoft
WriteIntInfo --> EntryIntInfo

The VmxInterruptInfo structure encodes the interrupt information according to Intel specifications, with specific bit fields for vector, interruption type, error code validity, and overall validity.

Sources: src/vmx/vmcs.rs(L677 - L694)  src/vmx/vmcs.rs(L515 - L534) 

Specialized Information Extraction

The system provides specialized functions for extracting detailed information from different types of VM exits:

I/O Exit Information

  • Function: io_exit_info()
  • Purpose: Extract port number, access size, direction for I/O instruction exits
  • Fields: Port number, access size (1-4 bytes), IN/OUT direction, string/repeat flags

EPT Violation Information

  • Function: ept_violation_info()
  • Purpose: Extract guest physical address and access type for memory violations
  • Returns: NestedPageFaultInfo with fault address and access flags

Control Register Access

  • Function: cr_access_info()
  • Purpose: Decode control register access attempts (MOV, CLTS, LMSW)
  • Fields: CR number, access type, GPR involved, LMSW source data

EFER Management

  • Function: update_efer()
  • Purpose: Handle guest IA32_EFER updates, particularly long mode transitions
  • Actions: Set LONG_MODE_ACTIVE bit, update VM-entry controls

Sources: src/vmx/vmcs.rs(L696 - L774)