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:
CSR | Purpose | Usage in Exit Processing |
---|---|---|
scause | Trap cause identification | Determines if exit was due to exception or interrupt |
stval | Trap value/address | Contains faulting address for memory exceptions |
htval | Hypervisor trap value | Guest physical page number for guest page faults |
htinst | Hypervisor trap instruction | Instruction 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 Type | Extension ID Range | Processing Method | Return Behavior |
---|---|---|---|
Legacy SBI | 0x00-0x08 | Direct implementation | Continue guest execution |
HSM Extension | 0x48534D | Return to host for CPU management | Host handles CPU lifecycle |
Hypercalls | EID_HVC | Return to host with call details | Host processes hypercall |
Standard Extensions | Other values | Forward to RustSBI implementation | Continue 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 Reason | Host Action | Guest State | Execution Resumption |
---|---|---|---|
Nothing | None | PC advanced | Immediate |
CpuUp | Start target CPU | PC advanced | After CPU start |
CpuDown | Handle CPU stop | Unchanged | Never (CPU stopped) |
Halt | Suspend handling | Unchanged | On resume event |
SystemDown | Shutdown sequence | Unchanged | Never (system down) |
ExternalInterrupt | Process interrupt | Unchanged | After interrupt handling |
NestedPageFault | Resolve page fault | Unchanged | After page table update |
Hypercall | Process hypercall | PC advanced | After 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)