SBI Interface and Hypercalls
Relevant source files
This page covers the Supervisor Binary Interface (SBI) implementation and hypercall handling within the RISC-V VCPU system. It details how the hypervisor processes SBI calls from guest virtual machines, including legacy extensions, modern extensions like Hart State Management (HSM), and custom hypercalls. For information about VM exit processing in general, see 2.3. For details about the overall VCPU lifecycle, see 2.1.
SBI Architecture Overview
The SBI interface serves as the critical communication layer between guest operating systems and the hypervisor. The RISC-V VCPU implements a comprehensive SBI handler that supports both legacy and modern SBI extensions while providing a custom hypercall interface.
flowchart TD subgraph subGraph2["Host/Hypervisor Layer"] HostSBI["Host SBI Implementation"] RustSBI["RustSBI Framework"] HostHardware["Host Hardware"] end subgraph subGraph1["RISC-V VCPU SBI Handler"] VMExit["vmexit_handler"] SBIRouter["SBI Call Router"] LegacySBI["Legacy SBI Handler"] ModernSBI["Modern SBI Handler"] HypercallHandler["Hypercall Handler"] ForwardSBI["RISCVVCpuSbi::handle_ecall"] end subgraph subGraph0["Guest Virtual Machine"] GuestOS["Guest OS"] GuestEcall["ecall instruction"] GuestRegs["Guest Registersa0-a7"] end ForwardSBI --> GuestOS ForwardSBI --> RustSBI GuestEcall --> GuestRegs GuestOS --> GuestEcall GuestRegs --> VMExit HostSBI --> HostHardware HypercallHandler --> GuestOS LegacySBI --> GuestOS LegacySBI --> HostSBI ModernSBI --> GuestOS RustSBI --> HostSBI SBIRouter --> ForwardSBI SBIRouter --> HypercallHandler SBIRouter --> LegacySBI SBIRouter --> ModernSBI VMExit --> SBIRouter
Sources: src/vcpu.rs(L184 - L308)
RISCVVCpuSbi Implementation
The RISCVVCpuSbi
struct provides the core SBI handling infrastructure using the RustSBI framework. It implements a forwarding mechanism for standard SBI extensions while allowing custom handling of specific calls.
classDiagram note for RISCVVCpuSbi "Derived using #[derive(RustSBI)]Automatically implements SBI traits" note for RISCVVCpuSbi "Forwards calls to host SBIimplementation" note for Forward "Forwards calls to host SBIimplementation" class RISCVVCpuSbi { +Forward forward +handle_ecall(eid, fid, param) SbiResult } class RISCVVCpu { +VmCpuRegisters regs +RISCVVCpuSbi sbi +vmexit_handler() AxVCpuExitReason } class Forward { +console: ConsoleExtension +pmu: PmuExtension +fence: FenceExtension +reset: ResetExtension +info: InfoExtension +hsm: HsmExtension } RISCVVCpu *-- RISCVVCpuSbi RISCVVCpu *-- Forward
The struct uses the #[derive(RustSBI)]
macro to automatically implement the necessary SBI traits, with the forward
field handling console, PMU, fence, reset, info, and HSM extensions through delegation to the host SBI implementation.
Sources: src/vcpu.rs(L29 - L40)
Legacy SBI Extensions
The hypervisor provides backward compatibility by implementing legacy SBI extensions that were defined in earlier RISC-V SBI specifications. These extensions use function-based calling conventions rather than the modern extension-based approach.
Extension ID | Function | Implementation | Return Behavior |
---|---|---|---|
LEGACY_SET_TIMER | Set timer interrupt | Callssbi_rt::set_timer(), clearsvstip | Setsa0to 0 |
LEGACY_CONSOLE_PUTCHAR | Output character | Forwards to host viasbi_call_legacy_1 | Direct forwarding |
LEGACY_CONSOLE_GETCHAR | Input character | Forwards to host viasbi_call_legacy_0 | Returns char ina0 |
LEGACY_SHUTDOWN | System shutdown | Triggers system shutdown | ReturnsSystemDownexit |
sequenceDiagram participant GuestOS as "Guest OS" participant RISCVVCpu as "RISCVVCpu" participant HostSBI as "Host SBI" GuestOS ->> RISCVVCpu: "ecall with legacy EID" RISCVVCpu ->> RISCVVCpu: "Extract a0-a7 registers" alt LEGACY_SET_TIMER RISCVVCpu ->> HostSBI: "sbi_rt::set_timer(param[0])" RISCVVCpu ->> RISCVVCpu: "hvip::clear_vstip()" RISCVVCpu ->> GuestOS: "Set a0=0, advance PC" else LEGACY_CONSOLE_PUTCHAR RISCVVCpu ->> HostSBI: "sbi_call_legacy_1(EID, char)" RISCVVCpu ->> GuestOS: "Advance PC" else LEGACY_CONSOLE_GETCHAR RISCVVCpu ->> HostSBI: "sbi_call_legacy_0(EID)" HostSBI ->> RISCVVCpu: "Return character" RISCVVCpu ->> GuestOS: "Set a0=char, advance PC" else LEGACY_SHUTDOWN RISCVVCpu ->> RISCVVCpu: "Return SystemDown exit" end
Sources: src/vcpu.rs(L192 - L220) src/vcpu.rs(L312 - L335)
Modern SBI Extensions - HSM
The Hart State Management (HSM) extension provides standardized CPU lifecycle management operations. The hypervisor implements key HSM functions to enable guest operating systems to manage multiple CPU cores.
HSM Function Implementation
flowchart TD subgraph Parameters["Parameters"] StartParams["hartid: target CPUstart_addr: entry pointopaque: argument"] SuspendParams["suspend_type: suspend moderesume_addr: resume pointopaque: context"] end subgraph subGraph1["VCPU Exit Reasons"] CpuUp["AxVCpuExitReason::CpuUp"] CpuDown["AxVCpuExitReason::CpuDown"] Halt["AxVCpuExitReason::Halt"] end subgraph subGraph0["HSM Functions"] HartStart["HART_STARTfid=0x0"] HartStop["HART_STOPfid=0x1"] HartSuspend["HART_SUSPENDfid=0x3"] end HartStart --> CpuUp HartStart --> StartParams HartStop --> CpuDown HartSuspend --> Halt HartSuspend --> SuspendParams
The HSM implementation extracts parameters from guest registers and translates them into appropriate VCPU exit reasons that the hypervisor can handle at a higher level.
Sources: src/vcpu.rs(L222 - L245)
Hypercall Interface
The hypervisor provides a custom hypercall interface using the EID_HVC
extension ID, allowing direct communication between guest software and the hypervisor for performance-critical operations or hypervisor-specific functionality.
Hypercall Processing Flow
flowchart TD subgraph subGraph2["Exit Reason Structure"] HypercallExit["AxVCpuExitReason::Hypercall {nr: function_id,args: [param0..param5]}"] end subgraph subGraph1["VCPU Processing"] CheckEID["Check extension_id == EID_HVC"] ExtractParams["Extract function_id from a6Extract param[0-5] from a0-a5"] CreateExit["Create AxVCpuExitReason::Hypercall"] AdvancePC["Advance PC by 4 bytes"] end subgraph subGraph0["Guest Hypercall"] GuestCall["Guest calls ecall"] SetRegs["Set a7=EID_HVCSet a6=function_idSet a0-a5=parameters"] end AdvancePC --> HypercallExit CheckEID --> ExtractParams CreateExit --> AdvancePC ExtractParams --> CreateExit GuestCall --> SetRegs SetRegs --> CheckEID
The hypercall mechanism provides a standardized way for guests to request hypervisor services while maintaining the SBI calling convention. The hypervisor returns control to the calling hypervisor framework through the Hypercall
exit reason.
Sources: src/vcpu.rs(L246 - L260)
SBI Call Processing Flow
The complete SBI call processing occurs within the vmexit_handler
function when a VirtualSupervisorEnvCall
exception is detected. The handler examines register contents to determine the appropriate processing path.
flowchart TD VMExit["VM Exit: VirtualSupervisorEnvCall"] ExtractRegs["Extract a0-a7 registersextension_id = a[7]function_id = a[6]param = a[0..5]"] Router["Route by extension_id"] LegacyPath["Legacy SBI Processing"] HSMPath["HSM Extension Processing"] HypercallPath["Hypercall Processing"] ForwardPath["Forward to RustSBI"] SetRegs1["Set return values in a0/a1"] ExitReason1["Return VCPU exit reason"] ExitReason2["Return VCPU exit reason"] SBIHandle["sbi.handle_ecall(eid, fid, param)"] CheckError["ret.is_err()?"] LogWarn["Log warning message"] SetRegs2["Set a0=ret.errorSet a1=ret.value"] AdvancePC1["Advance PC by 4"] AdvancePC2["Advance PC by 4"] ReturnNothing1["Return Nothing"] ReturnNothing2["Return Nothing"] HostHandler["Return to host handler"] GuestResume["Resume guest execution"] AdvancePC1 --> ReturnNothing1 AdvancePC2 --> ReturnNothing2 CheckError --> LogWarn CheckError --> SetRegs2 ExitReason1 --> HostHandler ExitReason2 --> HostHandler ExtractRegs --> Router ForwardPath --> SBIHandle HSMPath --> ExitReason1 HypercallPath --> ExitReason2 LegacyPath --> SetRegs1 LogWarn --> SetRegs2 ReturnNothing1 --> GuestResume ReturnNothing2 --> GuestResume Router --> ForwardPath Router --> HSMPath Router --> HypercallPath Router --> LegacyPath SBIHandle --> CheckError SetRegs1 --> AdvancePC1 SetRegs2 --> AdvancePC2 VMExit --> ExtractRegs
The processing flow ensures that all SBI calls either result in immediate guest resumption (for calls handled within the hypervisor) or appropriate exit reasons for calls requiring host-level processing.
Sources: src/vcpu.rs(L184 - L278)
Register Convention and Error Handling
The SBI implementation follows the standard RISC-V calling convention where a7
contains the extension ID, a6
contains the function ID, and a0-a5
contain parameters. Return values are placed in a0
(error code) and a1
(return value).
For forwarded calls that fail, the system logs detailed error information including the extension ID, function ID, parameters, error code, and return value to aid in debugging SBI-related issues.
Sources: src/vcpu.rs(L264 - L273)