Hardware Detection
Relevant source files
This page documents the trap-based hardware feature detection system used to identify RISC-V H-extension support at runtime. The detection mechanism safely probes for hypervisor extension availability by attempting to access hypervisor-specific Control Status Registers (CSRs) and catching any resulting illegal instruction exceptions.
For information about per-CPU management and CSR initialization, see Per-CPU Management. For details about trap handling in the main VCPU system, see VM Exit Processing.
Purpose and Scope
The hardware detection system provides runtime identification of RISC-V hypervisor extension support through a controlled trap-and-return procedure. The system disables interrupts, attempts to access hypervisor CSRs, and uses exception handling to determine whether the hardware supports the required extensions.
Sources: src/detect.rs(L1 - L6)
Detection Process Overview
The hardware detection system uses a trap-based approach to safely probe for hardware features. The process attempts to read the hgatp
(Hypervisor Guest Address Translation and Protection) register, which is only available when the H-extension is present.
Detection Flow Diagram
flowchart TD Start["detect_h_extension()"] Setup["with_detect_trap()"] DisableInt["Disable S-level interrupts"] SetTrap["Set custom trap handler"] AttemptCSR["Attempt to read hgatp CSR (0x680)"] Success["CSR read successful"] IllegalInst["Illegal instruction exception"] RestoreOrig["Restore original state"] TrapHandler["on_detect_trap assembly handler"] RustHandler["rust_detect_trap()"] SkipInst["Skip illegal instruction"] RestoreAfterTrap["Restore original state"] ReturnTrue["Return true (H-extension present)"] ReturnFalse["Return false (H-extension absent)"] End["Hardware support confirmed"] AttemptCSR --> IllegalInst AttemptCSR --> Success DisableInt --> SetTrap IllegalInst --> TrapHandler RestoreAfterTrap --> ReturnFalse RestoreOrig --> ReturnTrue ReturnFalse --> End ReturnTrue --> End RustHandler --> SkipInst SetTrap --> AttemptCSR Setup --> DisableInt SkipInst --> RestoreAfterTrap Start --> Setup Success --> RestoreOrig TrapHandler --> RustHandler
Sources: src/detect.rs(L18 - L25) src/detect.rs(L32 - L39)
Implementation Architecture
The detection system consists of several interconnected components that work together to safely probe hardware features and handle any resulting exceptions.
Component Relationships
flowchart TD subgraph subGraph3["Hardware Interface"] CSRAccess["CSR Access (hgatp)"] InsnDecoding["riscv_illegal_insn_bits()"] end subgraph subGraph2["Trap Handling System"] AsmHandler["on_detect_trap() (naked asm)"] RustHandler["rust_detect_trap()"] TrapFrameStruct["TrapFrame struct"] end subgraph subGraph1["Core Detection Logic"] WithTrap["with_detect_trap()"] InitTrap["init_detect_trap()"] RestoreTrap["restore_detect_trap()"] end subgraph subGraph0["Public Interface"] DetectFunc["detect_h_extension()"] PublicAPI["has_hardware_support (lib.rs)"] end AsmHandler --> RustHandler CSRAccess --> AsmHandler DetectFunc --> WithTrap InitTrap --> AsmHandler PublicAPI --> DetectFunc RestoreTrap --> WithTrap RustHandler --> InsnDecoding RustHandler --> TrapFrameStruct WithTrap --> CSRAccess WithTrap --> InitTrap WithTrap --> RestoreTrap
Sources: src/lib.rs(L20) src/detect.rs(L18 - L25) src/detect.rs(L32 - L39) src/detect.rs(L155 - L217)
Detection Process Implementation
The detect_h_extension()
function serves as the primary entry point for hardware detection. It uses a controlled environment to attempt accessing hypervisor-specific CSRs.
Core Detection Function
The detection process attempts to read the hgatp
CSR (register 0x680
) within a controlled trap environment:
// From detect.rs lines 18-25
pub fn detect_h_extension() -> bool {
let ans = with_detect_trap(0, || unsafe {
asm!("csrr {}, 0x680", out(reg) _, options(nomem, nostack)); // 0x680 => hgatp
});
ans != 2 // 0 => success, 2 => failed (illegal instruction)
}
The function returns true
if the CSR access succeeds (indicating H-extension presence) or false
if an illegal instruction exception occurs (indicating absence).
Sources: src/detect.rs(L18 - L25)
Trap Environment Setup
The with_detect_trap()
function creates a controlled environment for safe hardware probing:
Phase | Function | Purpose |
---|---|---|
Setup | init_detect_trap() | Disable interrupts, set custom trap handler |
Execution | Closure parameter | Execute the probing instruction |
Cleanup | restore_detect_trap() | Restore original state, return result |
The setup process preserves the original system state while creating a minimal trap handling environment.
Sources: src/detect.rs(L32 - L39) src/detect.rs(L81 - L101) src/detect.rs(L105 - L118)
Trap Handling Mechanism
When an illegal instruction exception occurs during hardware probing, the system uses a specialized trap handling mechanism to safely recover and continue execution.
Trap Handler Flow
sequenceDiagram participant CPUCore as "CPU Core" participant on_detect_trapasm as "on_detect_trap() (asm)" participant rust_detect_trap as "rust_detect_trap()" participant TrapFrame as "TrapFrame" CPUCore ->> on_detect_trapasm: "Illegal instruction exception" on_detect_trapasm ->> TrapFrame: "Save all registers to TrapFrame" on_detect_trapasm ->> rust_detect_trap: "Call with TrapFrame pointer" rust_detect_trap ->> TrapFrame: "Read scause, stval, sepc" rust_detect_trap ->> rust_detect_trap: "Decode instruction length" rust_detect_trap ->> TrapFrame: "Update sepc to skip instruction" rust_detect_trap ->> TrapFrame: "Set tp register with exception code" rust_detect_trap ->> on_detect_trapasm: "Return to assembly handler" on_detect_trapasm ->> TrapFrame: "Restore all registers" on_detect_trapasm ->> CPUCore: "sret (return from trap)"
Sources: src/detect.rs(L155 - L217) src/detect.rs(L42 - L60)
TrapFrame Structure
The trap handler uses a specialized TrapFrame
structure to preserve processor state during exception handling:
// Key fields from TrapFrame (lines 122-144)
struct TrapFrame {
ra: usize, // Return address
tp: usize, // Thread pointer (used for return value)
a0-a7: usize, // Argument registers
t0-t6: usize, // Temporary registers
sstatus: usize, // Supervisor status
sepc: usize, // Exception program counter
scause: Scause,// Exception cause
stval: usize, // Trap value
}
The tp
register serves dual purposes: passing parameters into the detection routine and returning the exception code.
Sources: src/detect.rs(L121 - L144)
Exception Processing and Recovery
The trap handler analyzes exceptions and implements appropriate recovery mechanisms based on the exception type.
Exception Analysis Process
flowchart TD TrapEntry["rust_detect_trap() entry"] ReadCause["Read scause register"] CheckType["Exception type?"] ProcessIllegal["Process illegal instruction"] Unreachable1["unreachable!()"] Unreachable2["unreachable!() (filtered)"] ReadStval["Read stval for instruction bits"] CheckStval["stval[0..16] == 0?"] ReadMemory["Read instruction from sepc"] DecodeStval["Decode from stval"] DecodeLength["riscv_illegal_insn_bits()"] UpdateSepc["sepc += instruction_length"] SetReturnCode["tp = scause.bits()"] Return["Return to assembly handler"] CheckStval --> DecodeStval CheckStval --> ReadMemory CheckType --> ProcessIllegal CheckType --> Unreachable1 CheckType --> Unreachable2 DecodeLength --> UpdateSepc DecodeStval --> DecodeLength ProcessIllegal --> ReadStval ReadCause --> CheckType ReadMemory --> DecodeLength ReadStval --> CheckStval SetReturnCode --> Return TrapEntry --> ReadCause UpdateSepc --> SetReturnCode
Sources: src/detect.rs(L42 - L60) src/detect.rs(L64 - L77)
Instruction Length Decoding
The system includes logic to determine RISC-V instruction lengths for proper exception recovery:
Instruction Pattern | Length | Encoding |
---|---|---|
xxxxxxxxxxxxxxxx11(bits [1:0] != 11) | 16-bit | Compressed |
xxxxxxxxxxxxxxxnnn11(bits [4:2] != 111) | 32-bit | Standard |
xxxxxxxxxxxxxxx11111(bits [4:2] == 111) | ≥48-bit | Extended |
The riscv_illegal_insn_bits()
function implements this decoding logic to ensure the exception handler skips the correct number of bytes.
Sources: src/detect.rs(L64 - L77)
Integration with System Architecture
The hardware detection system integrates with the broader RISC-V VCPU architecture through the public API and initialization processes.
Public Interface Integration
The detection functionality is exposed through the main library interface:
// From lib.rs line 20
pub use detect::detect_h_extension as has_hardware_support;
This allows other system components to query hardware capabilities before attempting to use hypervisor features.
Sources: src/lib.rs(L20)
Error Handling Strategy
The detection system uses a fail-safe approach where:
- Successful CSR access indicates H-extension support
- Any exception (particularly illegal instruction) indicates lack of support
- The system gracefully recovers from all exception scenarios
- No system state is permanently modified during detection
This approach ensures that hardware detection can safely run on any RISC-V system, regardless of hypervisor extension availability.