kernel/arch/riscv64/instruction/
mod.rs

1use core::{arch::asm, ptr::read_unaligned};
2
3pub mod sbi;
4
5pub fn idle() -> ! {
6    loop {
7        unsafe {
8            asm!("wfi", options(nostack));
9        }
10    }
11}
12
13/// RISC-V environment call (ecall) with proper register preservation
14/// using clobber_abi to handle register preservation automatically
15#[inline(never)]
16#[unsafe(no_mangle)]
17pub fn ecall(a0: usize, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize, a7: usize) -> usize {
18    let ret: usize;
19    
20    unsafe {
21        asm!(
22            "ecall",
23            inout("a0") a0 => ret,
24            inout("a1") a1 => _,
25            inout("a2") a2 => _,
26            inout("a3") a3 => _,
27            inout("a4") a4 => _,
28            inout("a5") a5 => _,
29            inout("a6") a6 => _,
30            inout("a7") a7 => _,
31            clobber_abi("C"),
32            options(nostack),
33        );
34    }
35
36    ret
37}
38
39/// Represents a RISC-V instruction.
40/// This struct is used to encapsulate the raw instruction data
41/// and provides methods to create an instruction from raw bytes or a usize value.
42/// 
43pub struct Instruction {
44    pub raw: u32,
45}
46
47impl Instruction {
48    pub fn new(raw: usize) -> Self {
49        Self { raw: raw as u32 }
50    }
51
52    pub fn fetch(addr: usize) -> Self {
53        Instruction {
54            raw: unsafe { read_unaligned(addr as *const u32) },
55        }
56    }
57
58    pub fn from_bytes(bytes: &[u8]) -> Self {
59        if bytes.len() < 4 {
60            panic!("Instruction bytes must be at least 4 bytes long");
61        }
62        let raw = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
63        Self { raw }
64    }
65
66    pub fn len(&self) -> usize {
67        if (self.raw & 0b11) == 0b11 {
68            4 // 32-bit instruction
69        } else {
70            2 // 16-bit instruction
71        }
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test_case]
80    fn test_instruction_from_bytes() {
81        let bytes = [0x13, 0x00, 0x00, 0x00]; // Example instruction bytes
82        let instruction = Instruction::from_bytes(&bytes);
83        assert_eq!(instruction.raw, 0x00000013);
84        assert_eq!(instruction.len(), 4);
85    }
86
87    #[test_case]
88    fn test_instruction_new() {
89        let instruction = Instruction::new(0x00000013);
90        assert_eq!(instruction.raw, 0x00000013);
91        assert_eq!(instruction.len(), 4);
92    }
93
94    #[test_case]
95    fn test_instruction_len() {
96        let instruction_32 = Instruction::new(0x00000013); // 32-bit instruction
97        assert_eq!(instruction_32.len(), 4);
98
99        let instruction_16 = Instruction::new(0x00000004); // 16-bit instruction
100        assert_eq!(instruction_16.len(), 2);
101    }
102}