RISC-V Implementation
Relevant source files
This document details the RISC-V architecture-specific implementation of signal handling in the axsignal crate. It covers the signal trampoline mechanism, context saving/restoring operations, and the data structures specific to RISC-V processors. For information about other architectures, see the corresponding implementation pages: x86_64 Implementation, ARM64 Implementation, and LoongArch64 Implementation.
RISC-V Signal Handling Architecture
The RISC-V signal handling implementation provides the architecture-specific components needed to save CPU state before executing a signal handler and to restore that state afterward. It consists of two main components:
- A signal trampoline implementation in assembly language
- Data structures for storing CPU context
The implementation supports both 32-bit (riscv32) and 64-bit (riscv64) RISC-V architectures through a unified module.
flowchart TD
subgraph subGraph1["Integration Points"]
TSM["ThreadSignalManager"]
TF["TrapFrame"]
end
subgraph subGraph0["Signal Handling System"]
ARCH["arch/mod.rs"]
RISCV["arch/riscv.rs"]
TRAMP["signal_trampoline"]
MCTX["MContext"]
UCTX["UContext"]
end
ARCH --> RISCV
MCTX --> TF
MCTX --> UCTX
RISCV --> MCTX
RISCV --> TRAMP
RISCV --> UCTX
TF --> MCTX
TSM --> TRAMP
TSM --> UCTX
Sources: src/arch/mod.rs(L1 - L26) src/arch/riscv.rs(L1 - L64)
Signal Trampoline Implementation
The signal trampoline is a small piece of assembly code that serves as the bridge between signal handler execution and returning to normal execution. In RISC-V, it's implemented as a simple syscall wrapper that invokes syscall number 139 (sigreturn).
flowchart TD
subgraph subGraph0["Signal Trampoline Flow"]
SH["Signal Handler"]
ST["signal_trampoline"]
SC["Syscall 139 (sigreturn)"]
KR["Kernel Return Processing"]
RT["Return to Normal Execution"]
end
KR --> RT
SC --> KR
SH --> ST
ST --> SC
The trampoline is defined in assembly and aligned to a 4096-byte page boundary:
flowchart TD ASM["Assembly Code"] TRAM["signal_trampoline"] ECALL["syscall 139 (sigreturn)"] ASM --> TRAM TRAM --> ECALL
Sources: src/arch/riscv.rs(L5 - L16) src/arch/mod.rs(L19 - L25)
Context Data Structures
The RISC-V implementation defines two key structures for context management:
MContext Structure
MContext stores the essential machine context that needs to be saved and restored during signal handling.
classDiagram
class MContext {
+usize pc
-GeneralRegisters regs
-usize[66] fpstate
+new(TrapFrame) MContext
+restore(TrapFrame) void
}
class TrapFrame {
+usize sepc
+GeneralRegisters regs
}
MContext --> TrapFrame : converts from/to
The structure contains:
pc: Program counter (stored assepcin the trap frame)regs: General-purpose registers from theGeneralRegistersstructurefpstate: Floating-point state (66 words of storage)
UContext Structure
UContext is a higher-level structure that encapsulates MContext along with additional signal-related information.
The structure contains:
flags: Context flags (not currently used, set to 0)link: Link to another context (not currently used, set to 0)stack: Signal stack information (typeSignalStack)sigmask: Signal mask (typeSignalSet)__unused: Padding to ensure proper structure alignmentmcontext: The machine context described above
Sources: src/arch/riscv.rs(L18 - L63)
Context Operations
The RISC-V implementation provides two primary operations on context:
- Context Creation: Converting from a trap frame to an
MContext/UContext - Context Restoration: Restoring a trap frame from an
MContext
Context Creation
When a signal is delivered, the current CPU state (represented by a TrapFrame) is saved into an MContext and then into a UContext.
sequenceDiagram
participant ThreadSignalManager as ThreadSignalManager
participant TrapFrame as TrapFrame
participant MContext as MContext
participant UContext as UContext
ThreadSignalManager ->> UContext: new(tf, sigmask)
UContext ->> MContext: new(tf)
MContext ->> TrapFrame: read sepc to pc
MContext ->> TrapFrame: copy regs
MContext ->> MContext: initialize fpstate to zeros
UContext ->> UContext: initialize other fields
Context Restoration
After signal handler execution, the saved context is restored to continue normal execution.
sequenceDiagram
participant ThreadSignalManager as ThreadSignalManager
participant TrapFrame as TrapFrame
participant MContext as MContext
ThreadSignalManager ->> MContext: restore(tf)
MContext ->> TrapFrame: write pc to sepc
MContext ->> TrapFrame: copy regs
Sources: src/arch/riscv.rs(L27 - L38) src/arch/riscv.rs(L53 - L62)
Integration with Signal Handling System
The RISC-V implementation integrates with the rest of the signal handling system through the architecture abstraction layer defined in arch/mod.rs. This layer selects the appropriate architecture-specific implementation at compile time based on the target architecture.
flowchart TD
subgraph subGraph1["Signal Processing"]
TSM["ThreadSignalManager"]
TADDR["signal_trampoline_address()"]
TRAMP["signal_trampoline"]
SH["Signal Handler"]
ARCH["arch/mod.rs"]
X86["x86_64.rs"]
RISCV["riscv.rs"]
ARM["aarch64.rs"]
end
subgraph subGraph0["Architecture Selection"]
TSM["ThreadSignalManager"]
TADDR["signal_trampoline_address()"]
SH["Signal Handler"]
ARCH["arch/mod.rs"]
X86["x86_64.rs"]
RISCV["riscv.rs"]
ARM["aarch64.rs"]
LOONG["loongarch64.rs"]
end
ARCH --> ARM
ARCH --> LOONG
ARCH --> RISCV
ARCH --> X86
SH --> TRAMP
TADDR --> TRAMP
TSM --> SH
TSM --> TADDR
Key integration points:
- The
signal_trampoline_address()function provides the address of the architecture-specific trampoline implementation ThreadSignalManageruses the context structures to save and restore CPU state
Sources: src/arch/mod.rs(L1 - L26)
Technical Details
Signal Trampoline Memory Layout
The signal trampoline is carefully aligned to a 4096-byte page boundary and padded to fill an entire page. This is important for security and memory protection:
.section .text
.balign 4096
.global signal_trampoline
signal_trampoline:
li a7, 139 # Load syscall number 139 (sigreturn) into a7
ecall # Execute syscall
.fill 4096 - (. - signal_trampoline), 1, 0 # Fill remainder of page with zeros
The trampoline simply loads the sigreturn syscall number (139) into register a7 and executes the syscall instruction.
RISC-V Register Handling
The MContext structure saves the program counter (PC) separately from the general registers. During restoration:
- The program counter is restored to the
sepc(Supervisor Exception Program Counter) field of the trap frame - The general registers are copied directly between the trap frame and
MContext
The floating-point state (fpstate) is currently initialized to zeros but provides space for future implementations to save floating-point registers.
Sources: src/arch/riscv.rs(L5 - L16) src/arch/riscv.rs(L27 - L38)
Summary
The RISC-V implementation in the axsignal crate provides the architecture-specific components needed for signal handling on RISC-V processors. It defines the data structures for saving and restoring CPU context (MContext and UContext) and implements the signal trampoline needed to return from signal handlers. The implementation supports both 32-bit and 64-bit RISC-V architectures through a single module.
The architecture-specific implementation is selected at compile time based on the target architecture, ensuring that the appropriate code is used without runtime overhead.
Sources: src/arch/mod.rs(L1 - L26) src/arch/riscv.rs(L1 - L64)