kernel/arch/riscv64/instruction/
mod.rs1use 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#[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
39pub 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 } else {
70 2 }
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]; 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); assert_eq!(instruction_32.len(), 4);
98
99 let instruction_16 = Instruction::new(0x00000004); assert_eq!(instruction_16.len(), 2);
101 }
102}