VM Exit Processing

Relevant source files

Purpose and Scope

This document covers the VM exit processing mechanism in the RISC-V VCPU hypervisor system. VM exits occur when guest execution needs to be interrupted and control transferred back to the hypervisor for handling specific events such as privileged instructions, interrupts, or memory access violations.

The VM exit processing is primarily implemented in the vmexit_handler function and encompasses the detection of exit reasons, processing of different exit types, and the coordination of return mechanisms back to guest execution. For information about the overall VCPU lifecycle, see VCPU Lifecycle and Management. For details about SBI interface implementation, see SBI Interface and Hypercalls.

VM Exit Flow Overview

The VM exit processing follows a structured flow from guest execution interruption through exit reason determination to appropriate handling and guest resumption.

High-Level Exit Processing Flow

flowchart TD
GuestRun["Guest Execution_run_guest()"]
VMExit["VM Exit Occurs"]
CSRRead["Read Exit Informationscause, stval, htval, htinst"]
ExitDecode["Decode Exit Reasonvmexit_handler()"]
SBICall["scause == VirtualSupervisorEnvCall"]
TimerInt["scause == SupervisorTimer"]
ExtInt["scause == SupervisorExternal"]
PageFault["Load/Store GuestPageFault"]
UnhandledTrap["Unhandled Trappanic!"]
ProcessSBI["Process SBI CallExtension/Function ID"]
HandleTimer["Handle Timer InterruptSet VSTIP"]
HandleExternal["Handle External Interrupt"]
HandlePageFault["Handle Nested Page Fault"]
ReturnNothing["Return Nothing"]
ReturnCpuUp["Return CpuUp"]
ReturnCpuDown["Return CpuDown"]
ReturnHalt["Return Halt"]
ReturnHypercall["Return Hypercall"]
ReturnSystemDown["Return SystemDown"]
ReturnExtInt["Return ExternalInterrupt"]
ReturnPageFault["Return NestedPageFault"]
ResumeGuest["Resume Guest Execution"]
HostAction["Host Action Required"]
EventualResume["Eventually Resume Guest"]

CSRRead --> ExitDecode
EventualResume --> GuestRun
ExitDecode --> ExtInt
ExitDecode --> PageFault
ExitDecode --> SBICall
ExitDecode --> TimerInt
ExitDecode --> UnhandledTrap
ExtInt --> HandleExternal
GuestRun --> VMExit
HandleExternal --> ReturnExtInt
HandlePageFault --> ReturnPageFault
HandleTimer --> ReturnNothing
HostAction --> EventualResume
PageFault --> HandlePageFault
ProcessSBI --> ReturnCpuDown
ProcessSBI --> ReturnCpuUp
ProcessSBI --> ReturnHalt
ProcessSBI --> ReturnHypercall
ProcessSBI --> ReturnNothing
ProcessSBI --> ReturnSystemDown
ResumeGuest --> GuestRun
ReturnCpuDown --> HostAction
ReturnCpuUp --> HostAction
ReturnExtInt --> HostAction
ReturnHalt --> HostAction
ReturnHypercall --> HostAction
ReturnNothing --> ResumeGuest
ReturnPageFault --> HostAction
ReturnSystemDown --> HostAction
SBICall --> ProcessSBI
TimerInt --> HandleTimer
VMExit --> CSRRead

Sources: src/vcpu.rs(L92 - L111)  src/vcpu.rs(L167 - L308) 

Exit Reason Detection and CSR Reading

The VM exit processing begins by capturing the CPU state and trap information from various Control and Status Registers (CSRs) to determine the cause and context of the exit.

CSR State Capture Process

flowchart TD
VMExit["VM Exit Event"]
ReadCSRs["Read Trap CSRs"]
SCAUSE["scauseTrap Cause"]
STVAL["stvalTrap Value"]
HTVAL["htvalHypervisor Trap Value"]
HTINST["htinstHypervisor Trap Instruction"]
DecodeType["Decode Trap TypeException vs Interrupt"]
FaultAddr["Calculate Fault Address"]
GuestPageAddr["Guest Page Information"]
InstInfo["Instruction Information"]
ProcessExit["Route to Specific Handler"]

DecodeType --> ProcessExit
FaultAddr --> ProcessExit
GuestPageAddr --> ProcessExit
HTINST --> InstInfo
HTVAL --> GuestPageAddr
InstInfo --> ProcessExit
ReadCSRs --> HTINST
ReadCSRs --> HTVAL
ReadCSRs --> SCAUSE
ReadCSRs --> STVAL
SCAUSE --> DecodeType
STVAL --> FaultAddr
VMExit --> ReadCSRs

The vmexit_handler function captures the following CSR state immediately upon entry:

CSRPurposeUsage in Exit Processing
scauseTrap cause identificationDetermines if exit was due to exception or interrupt
stvalTrap value/addressContains faulting address for memory exceptions
htvalHypervisor trap valueGuest physical page number for guest page faults
htinstHypervisor trap instructionInstruction bits for trapped instruction

Sources: src/vcpu.rs(L167 - L181) 

SBI Call Processing

Virtual Supervisor Environment Calls represent the largest category of VM exits, handling communication between the guest operating system and the hypervisor through the Supervisor Binary Interface.

SBI Call Processing Flow

flowchart TD
VSEnvCall["VirtualSupervisorEnvCallException"]
ExtractArgs["Extract Argumentsa0-a7 registers"]
ExtID["extension_id = a[7]"]
FuncID["function_id = a[6]"]
Params["param[0-5] = a[0-5]"]
CheckLegacy["Legacy SBI?LEGACY_SET_TIMER..LEGACY_SHUTDOWN"]
CheckHSM["HSM Extension?EID_HSM"]
CheckHVC["Hypercall?EID_HVC"]
ForwardSBI["Forward to RustSBI"]
ProcessLegacy["Process Legacy SBITimer/Console/Shutdown"]
ProcessHSM["Process HSMHart Management"]
ProcessHVC["Process Hypercall"]
SetTimer["LEGACY_SET_TIMERsbi_rt::set_timer()"]
ConsolePut["LEGACY_CONSOLE_PUTCHAR"]
ConsoleGet["LEGACY_CONSOLE_GETCHAR"]
Shutdown["LEGACY_SHUTDOWNReturn SystemDown"]
HartStart["HART_STARTReturn CpuUp"]
HartStop["HART_STOPReturn CpuDown"]
HartSuspend["HART_SUSPENDReturn Halt"]
ReturnHypercall["Return Hypercallwith nr and args"]
RustSBIHandle["sbi.handle_ecall()Forward to RustSBI"]
AdvancePC["Advance PC by 4"]
ReturnResult["Return Appropriate Result"]

AdvancePC --> ReturnResult
CheckHSM --> ProcessHSM
CheckHVC --> ProcessHVC
CheckLegacy --> ProcessLegacy
ConsoleGet --> AdvancePC
ConsolePut --> AdvancePC
ExtID --> CheckHSM
ExtID --> CheckHVC
ExtID --> CheckLegacy
ExtID --> ForwardSBI
ExtractArgs --> ExtID
ExtractArgs --> FuncID
ExtractArgs --> Params
ForwardSBI --> RustSBIHandle
HartStart --> AdvancePC
ProcessHSM --> HartStart
ProcessHSM --> HartStop
ProcessHSM --> HartSuspend
ProcessHVC --> AdvancePC
ProcessHVC --> ReturnHypercall
ProcessLegacy --> ConsoleGet
ProcessLegacy --> ConsolePut
ProcessLegacy --> SetTimer
ProcessLegacy --> Shutdown
RustSBIHandle --> AdvancePC
SetTimer --> AdvancePC
VSEnvCall --> ExtractArgs

SBI Extension Categories

The system processes SBI calls in several categories:

Extension TypeExtension ID RangeProcessing MethodReturn Behavior
Legacy SBI0x00-0x08Direct implementationContinue guest execution
HSM Extension0x48534DReturn to host for CPU managementHost handles CPU lifecycle
HypercallsEID_HVCReturn to host with call detailsHost processes hypercall
Standard ExtensionsOther valuesForward to RustSBI implementationContinue guest execution

Sources: src/vcpu.rs(L184 - L278)  src/vcpu.rs(L311 - L335) 

Interrupt Handling

The hypervisor handles two primary categories of interrupts that cause VM exits: timer interrupts and external interrupts.

Interrupt Processing Mechanisms

flowchart TD
IntTrap["Interrupt Trap"]
CheckType["Interrupt Type"]
TimerInt["SupervisorTimerInterrupt"]
ExtInt["SupervisorExternalInterrupt"]
EnableVSTIP["Enable Guest Timerhvip::set_vstip()"]
EnableSTimer["Enable S-mode Timersie::set_stimer()"]
ReturnNothing1["Return NothingResume Guest"]
ReturnExternal["Return ExternalInterruptvector: 0"]
GuestResume1["Guest Continueswith Timer Available"]
HostHandle["Host HandlesExternal Interrupt"]

CheckType --> ExtInt
CheckType --> TimerInt
EnableSTimer --> ReturnNothing1
EnableVSTIP --> ReturnNothing1
ExtInt --> ReturnExternal
IntTrap --> CheckType
ReturnExternal --> HostHandle
ReturnNothing1 --> GuestResume1
TimerInt --> EnableSTimer
TimerInt --> EnableVSTIP

Timer Interrupt Processing

Timer interrupts are handled by enabling the virtual supervisor timer interrupt (VSTIP) for the guest and allowing it to continue execution. This delegation allows the guest to handle its own timer events while maintaining hypervisor control.

External Interrupt Processing

External interrupts are returned to the host system for processing, as they typically require hypervisor-level handling and may affect multiple guests or system-wide state.

Sources: src/vcpu.rs(L279 - L290) 

Page Fault Processing

Guest page faults represent memory access violations that require hypervisor intervention, typically for memory management, protection, or virtualization purposes.

Guest Page Fault Analysis

flowchart TD
PageFaultTrap["Guest Page Fault"]
FaultType["Fault Type"]
LoadFault["LoadGuestPageFaultException"]
StoreFault["StoreGuestPageFaultException"]
CalcAddr["Calculate Fault Address"]
AddrCalc["fault_addr = htval << 2 | stval & 0x3"]
CreateResult["Create NestedPageFault Result"]
ReturnFault["Return NestedPageFaultaddr: GuestPhysAddraccess_flags: empty"]
HostEPT["Host HandlesExtended Page Tables"]

AddrCalc --> CreateResult
CalcAddr --> AddrCalc
CreateResult --> ReturnFault
FaultType --> LoadFault
FaultType --> StoreFault
LoadFault --> CalcAddr
PageFaultTrap --> FaultType
ReturnFault --> HostEPT
StoreFault --> CalcAddr

Fault Address Calculation

The system calculates the precise fault address by combining information from two CSRs:

  • htval: Contains the guest physical page number (shifted left by 2)
  • stval: Contains the page offset (lower 2 bits)

The combination htval << 2 | stval & 0x3 provides the complete fault address for the host to resolve through extended page table management.

Sources: src/vcpu.rs(L291 - L298) 

Return Mechanisms and Exit Reasons

The VM exit processing concludes by returning specific exit reasons that inform the host system about the required action and whether guest execution should resume immediately or requires host intervention.

Exit Reason Categories

flowchart TD
ExitReasons["AxVCpuExitReason"]
ImmediateResume["Immediate Resume"]
HostAction["Host Action Required"]
Nothing["NothingContinue guest execution"]
CpuMgmt["CPU Management"]
SystemMgmt["System Management"]
MemoryMgmt["Memory Management"]
CallMgmt["Call Management"]
CpuUp["CpuUpStart additional CPU"]
CpuDown["CpuDownStop current CPU"]
Halt["HaltSuspend CPU"]
SystemDown["SystemDownShutdown system"]
ExternalInterrupt["ExternalInterruptHandle interrupt"]
NestedPageFault["NestedPageFaultResolve memory fault"]
Hypercall["HypercallProcess hypercall"]

CallMgmt --> Hypercall
CpuMgmt --> CpuDown
CpuMgmt --> CpuUp
CpuMgmt --> Halt
ExitReasons --> HostAction
ExitReasons --> ImmediateResume
HostAction --> CallMgmt
HostAction --> CpuMgmt
HostAction --> MemoryMgmt
HostAction --> SystemMgmt
ImmediateResume --> Nothing
MemoryMgmt --> NestedPageFault
SystemMgmt --> ExternalInterrupt
SystemMgmt --> SystemDown

Exit Reason Impact on Execution Flow

Exit ReasonHost ActionGuest StateExecution Resumption
NothingNonePC advancedImmediate
CpuUpStart target CPUPC advancedAfter CPU start
CpuDownHandle CPU stopUnchangedNever (CPU stopped)
HaltSuspend handlingUnchangedOn resume event
SystemDownShutdown sequenceUnchangedNever (system down)
ExternalInterruptProcess interruptUnchangedAfter interrupt handling
NestedPageFaultResolve page faultUnchangedAfter page table update
HypercallProcess hypercallPC advancedAfter hypercall completion

Sources: src/vcpu.rs(L212)  src/vcpu.rs(L228 - L232)  src/vcpu.rs(L235)  src/vcpu.rs(L242)  src/vcpu.rs(L249 - L259)  src/vcpu.rs(L277)  src/vcpu.rs(L286)  src/vcpu.rs(L289)  src/vcpu.rs(L294 - L297)