Low-Level Implementation

Relevant source files

This page covers the assembly-level implementations, hardware register definitions, and low-level system constants that form the foundation of the RISC-V VCPU system. This includes the critical assembly trap handlers, Control and Status Register (CSR) bitfield definitions, and system-wide constants for interrupts and exceptions.

For higher-level VCPU management and lifecycle operations, see Core VCPU Implementation. For register state management data structures, see Register Management.

Assembly Trap Handler Implementation

The core of the hypervisor's guest-host transition mechanism is implemented in assembly language through the trap handler system. This provides the critical low-level routines for entering and exiting guest virtual machines.

Guest Entry and Exit Assembly Functions

The system implements two primary assembly functions that handle the critical guest-hypervisor transitions:

Guest Entry Flow (_run_guest)

flowchart TD
start["_run_guest"]
save_hyp["Save Hypervisor GPRs"]
swap_csr["Swap in Guest CSRs"]
set_stvec["Set stvec to _guest_exit"]
save_sscratch["Save sscratch, set to GuestInfo"]
restore_guest["Restore Guest GPRs"]
sret["sret - Enter Guest"]
guest_exec["Guest Execution"]
trap["VM Exit/Trap"]
guest_exit["_guest_exit"]

guest_exec --> trap
restore_guest --> sret
save_hyp --> swap_csr
save_sscratch --> restore_guest
set_stvec --> save_sscratch
sret --> guest_exec
start --> save_hyp
swap_csr --> set_stvec
trap --> guest_exit

Guest Exit Flow (_guest_exit)

flowchart TD
guest_exit["_guest_exit"]
swap_a0["Swap GuestInfo from sscratch"]
save_guest["Save Guest GPRs"]
save_guest_a0["Save Guest a0 from sscratch"]
restore_csr["Swap in Hypervisor CSRs"]
save_sepc["Save Guest EPC"]
restore_hyp["Restore Hypervisor GPRs"]
ret_hyp["ret - Return to Hypervisor"]

guest_exit --> swap_a0
restore_csr --> save_sepc
restore_hyp --> ret_hyp
save_guest --> save_guest_a0
save_guest_a0 --> restore_csr
save_sepc --> restore_hyp
swap_a0 --> save_guest

The assembly implementation uses precise register offset calculations to access the VmCpuRegisters structure fields. The offsets are computed using compile-time constants generated by the hyp_gpr_offset and guest_gpr_offset functions in src/trap.rs(L8 - L19) 

Sources: src/trap.S(L1 - L183)  src/trap.rs(L1 - L103) 

Register Context Switching Mechanism

The trap handler performs comprehensive context switching between hypervisor and guest register states:

flowchart TD
subgraph subGraph1["Memory Layout"]
    VmCpuRegs["VmCpuRegisters"]
    HypState["HypervisorCpuStatehyp_regs"]
    GuestState["GuestCpuStateguest_regs"]
end
subgraph subGraph0["Register Categories"]
    GPRs["General Purpose Registersra, gp, tp, s0-s11, a1-a7, sp"]
    CSRs["Control Status Registerssstatus, hstatus, scounterenstvec, sscratch, sepc"]
    Special["Special Handlinga0 (via sscratch)t0-t6 (guest only)"]
end

CSRs --> GuestState
CSRs --> HypState
GPRs --> GuestState
GPRs --> HypState
VmCpuRegs --> GuestState
VmCpuRegs --> HypState

The offset calculation macros hyp_csr_offset! and guest_csr_offset! at src/trap.rs(L22 - L33)  enable the assembly code to access specific CSR fields within the register structure using compile-time computed offsets.

Sources: src/trap.rs(L35 - L102)  src/trap.S(L32 - L156) 

CSR Register Definitions and Hardware Interfaces

The system provides comprehensive definitions for RISC-V Control and Status Registers using the tock_registers framework, enabling type-safe bitfield manipulation of hardware registers.

Hypervisor Extension CSR Definitions

Key hypervisor-specific CSRs are defined with detailed bitfield structures:

CSR NameAddressPurpose
hstatus0x600Hypervisor status register
hedeleg0x602Hypervisor exception delegation
hideleg0x603Hypervisor interrupt delegation
hie0x604Hypervisor interrupt enable
hcounteren0x606Hypervisor counter enable
hvip0x645Hypervisor virtual interrupt pending

HSTATUS Register Bitfield Layout

The hstatus register contains critical hypervisor state control bits:

flowchart TD
subgraph subGraph0["hstatus Register Fields"]
    VSBE["vsbe[6]Virtual SupervisorBig Endian"]
    GVA["gva[6]Guest VirtualAddress"]
    SPV["spv[7]Supervisor PreviousVirtualization Mode"]
    SPVP["spvp[8]Supervisor PreviousVirtual Privilege"]
    HU["hu[9]Hypervisor inUser Mode"]
    VGEIN["vgein[17:12]Virtual GuestExternal Interrupt"]
    VTVM["vtvm[20]Virtual TLBManagement"]
    VTW["vtw[21]Virtual TimeoutWait"]
    VTSR["vtsr[22]Virtual TimeoutState Reporting"]
    VSXL["vsxl[33:32]Virtual SupervisorXLEN"]
end

The SPV field uses enumerated values for privilege modes:

  • User = 0 - User mode virtualization
  • Supervisor = 1 - Supervisor mode virtualization

Sources: def.rs(L37 - L1284) 

Exception and Interrupt Delegation Registers

The hedeleg register controls which exceptions are delegated to VS-mode:

flowchart TD
subgraph subGraph0["Exception Types (hedeleg)"]
    MISALIGN["instr_misaligned[0]Instruction Address Misaligned"]
    IFAULT["instr_fault[1]Instruction Access Fault"]
    ILLEGAL["illegal_instr[2]Illegal Instruction"]
    BREAK["breakpoint[3]Breakpoint"]
    LMISALIGN["load_misaligned[4]Load Address Misaligned"]
    LFAULT["load_fault[5]Load Access Fault"]
    SMISALIGN["store_misaligned[6]Store Address Misaligned"]
    SFAULT["store_fault[7]Store Access Fault"]
    UECALL["u_ecall[8]User Environment Call"]
    IPFAULT["instr_page_fault[12]Instruction Page Fault"]
    LPFAULT["load_page_fault[13]Load Page Fault"]
    SPFAULT["store_page_fault[15]Store Page Fault"]
end

The hideleg register controls interrupt delegation with fields for:

  • vssoft[2] - VS-mode software interrupt
  • vstimer[6] - VS-mode timer interrupt
  • vsext[10] - VS-mode external interrupt

Sources: def.rs(L55 - L1420) 

System Constants and Trap Definitions

The system defines comprehensive constants for interrupt handling, exception types, and trap processing organized into logical modules.

Interrupt Type Constants

The interrupt constants are organized by interrupt source and privilege level:

flowchart TD
subgraph subGraph0["Interrupt Constants (consts::traps::interrupt)"]
    USER_SOFT["USER_SOFT = 1<<0"]
    SUPERVISOR_SOFT["SUPERVISOR_SOFT = 1<<1"]
    VIRTUAL_SUPERVISOR_SOFT["VIRTUAL_SUPERVISOR_SOFT = 1<<2"]
    MACHINE_SOFT["MACHINE_SOFT = 1<<3"]
    USER_TIMER["USER_TIMER = 1<<4"]
    SUPERVISOR_TIMER["SUPERVISOR_TIMER = 1<<5"]
    VIRTUAL_SUPERVISOR_TIMER["VIRTUAL_SUPERVISOR_TIMER = 1<<6"]
    MACHINE_TIMER["MACHINE_TIMER = 1<<7"]
    USER_EXTERNAL["USER_EXTERNAL = 1<<8"]
    SUPERVISOR_EXTERNAL["SUPERVISOR_EXTERNAL = 1<<9"]
    VIRTUAL_SUPERVISOR_EXTERNAL["VIRTUAL_SUPERVISOR_EXTERNAL = 1<<10"]
    MACHINEL_EXTERNAL["MACHINEL_EXTERNAL = 1<<11"]
    SUPERVISOR_GUEST_EXTERNEL["SUPERVISOR_GUEST_EXTERNEL = 1<<12"]
end

Exception Type Constants

Exception constants define the various fault and trap conditions:

Exception TypeConstant ValueDescription
INST_ADDR_MISALIGN1<<0Instruction address misaligned
INST_ACCESSS_FAULT1<<1Instruction access fault
ILLEGAL_INST1<<2Illegal instruction
BREAKPOINT1<<3Breakpoint
LOAD_ADDR_MISALIGNED1<<4Load address misaligned
LOAD_ACCESS_FAULT1<<5Load access fault
STORE_ADDR_MISALIGNED1<<6Store address misaligned
STORE_ACCESS_FAULT1<<7Store access fault
ENV_CALL_FROM_U_OR_VU1<<8Environment call from U-mode or VU-mode
ENV_CALL_FROM_HS1<<9Environment call from HS-mode
ENV_CALL_FROM_VS1<<10Environment call from VS-mode
ENV_CALL_FROM_M1<<11Environment call from M-mode

IRQ Processing Constants

The IRQ module provides constants for interrupt processing and cause register interpretation:

flowchart TD
subgraph subGraph0["IRQ Constants (consts::traps::irq)"]
    INTC_BASE["INTC_IRQ_BASE1 << (usize::BITS - 1)Interrupt Bit Mask"]
    S_SOFT["S_SOFTINTC_IRQ_BASE + 1Supervisor Software IRQ"]
    S_TIMER["S_TIMERINTC_IRQ_BASE + 5Supervisor Timer IRQ"]
    S_EXT["S_EXTINTC_IRQ_BASE + 9Supervisor External IRQ"]
    MAX_IRQ["MAX_IRQ_COUNT = 1024Maximum IRQ Number"]
    TIMER_IRQ["TIMER_IRQ_NUM = S_TIMERTimer IRQ Identifier"]
end

The INTC_IRQ_BASE constant at src/consts.rs(L79)  provides the base value for distinguishing interrupts from exceptions in the scause register, with interrupts having the most significant bit set.

Sources: src/consts.rs(L1 - L92)