kernel/arch/riscv64/instruction/
sbi.rs

1use core::arch::asm;
2
3pub enum Extension {
4    Base = 0x10,
5    SetTimer = 0x00,
6    ConsolePutChar = 0x01,
7    ConsoleGetChar = 0x02,
8    Timer = 0x54494d45,
9    Ipi = 0x735049,
10    Rfence = 0x52464e43,
11    Hsm = 0x48534d,
12    Srst = 0x53525354,
13    Pmu = 0x504d55,
14}
15
16pub struct SbiRet {
17    pub error: usize,
18    pub value: usize,
19}
20
21pub enum SbiError {
22    Failed = -1,
23    NotSupported = -2,
24    InvalidParam = -3,
25    Denied = -4,
26    InvalidAddress = -5,
27    AlreadyAvailable = -6,
28    AlreadyStarted = -7,
29    AlreadyStopped = -8,
30}
31
32impl SbiError {
33    pub fn from_error(error: usize) -> SbiError {
34        let error = error as isize;
35        match error {
36            -1 => SbiError::Failed,
37            -2 => SbiError::NotSupported,
38            -3 => SbiError::InvalidParam,
39            -4 => SbiError::Denied,
40            -5 => SbiError::InvalidAddress,
41            -6 => SbiError::AlreadyAvailable,
42            -7 => SbiError::AlreadyStarted,
43            -8 => SbiError::AlreadyStopped,
44            _ => panic!("Invalid SBI error code"),
45        }
46    }
47}
48
49/// More robust SBI call implementation with additional safety measures
50#[inline(never)]
51#[unsafe(no_mangle)]
52pub fn sbi_call(extension: Extension, function: usize, arg0: usize, arg1: usize) -> Result<usize, SbiError> {
53    let error: usize;
54    let ret: usize;
55
56    unsafe {
57        asm!(
58            "ecall",
59            inout("a0") arg0 => error,
60            inout("a1") arg1 => ret,
61            inout("a2") 0 => _,
62            inout("a3") 0 => _,
63            inout("a4") 0 => _,
64            inout("a5") 0 => _,
65            inout("a6") function => _,
66            inout("a7") extension as usize => _,
67            clobber_abi("C"),
68            options(nostack),
69        );
70    }
71
72    match error {
73        0 => Ok(ret),
74        error_code if error_code <= 8 => Err(SbiError::from_error(error_code)),
75        _ => {
76            Err(SbiError::Failed)
77        }
78    }
79}
80
81pub fn sbi_console_putchar(c: char) {
82    let _ = sbi_call(Extension::ConsolePutChar, 0, c as usize, 0);
83}
84
85pub fn sbi_console_getchar() -> char {
86    let ret = sbi_call(Extension::ConsoleGetChar, 0, 0, 0);
87    match ret {
88        Ok(c) => c as u8 as char,
89        Err(_) => '\0',
90    }
91}
92
93pub fn sbi_set_timer(stime_value: u64) {
94    let _ = sbi_call(Extension::Timer, 0, stime_value as usize, 0);
95}
96
97pub fn sbi_system_reset(reset_type: u32, reset_reason: u32) -> ! {
98    let _ = sbi_call(Extension::Srst, 0, reset_type as usize, reset_reason as usize);
99    loop {}
100}