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(
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
48pub 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 } else {
79 2 }
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]; 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); assert_eq!(instruction_32.len(), 4);
107
108 let instruction_16 = Instruction::new(0x00000004); assert_eq!(instruction_16.len(), 2);
110 }
111}