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)