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