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 IDFunctionImplementationReturn Behavior
LEGACY_SET_TIMERSet timer interruptCallssbi_rt::set_timer(), clearsvstipSetsa0to 0
LEGACY_CONSOLE_PUTCHAROutput characterForwards to host viasbi_call_legacy_1Direct forwarding
LEGACY_CONSOLE_GETCHARInput characterForwards to host viasbi_call_legacy_0Returns char ina0
LEGACY_SHUTDOWNSystem shutdownTriggers system shutdownReturnsSystemDownexit
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)