mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
riscv: 使用sbi-rt库完成SBI操作 (#510)
未来的其它SBI操作也将使用sbi-rt Signed-off-by: Zhouqi Jiang <luojia@hust.edu.cn>
This commit is contained in:
parent
fccbe87dca
commit
d14e28a8a9
@ -62,6 +62,7 @@ x86_64 = "0.14.10"
|
||||
# target为riscv64时,使用下面的依赖
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
riscv = { version = "0.11.0", features = [ "s-mode" ] }
|
||||
sbi-rt = { git = "https://github.com/rustsbi/rustsbi" }
|
||||
|
||||
|
||||
# 构建时依赖项
|
||||
|
@ -6,5 +6,6 @@ pub fn current_cpu_id() -> u32 {
|
||||
|
||||
/// 重置cpu
|
||||
pub unsafe fn cpu_reset() -> ! {
|
||||
unimplemented!("RiscV64 cpu_reset")
|
||||
sbi_rt::system_reset(sbi_rt::WarmReboot, sbi_rt::NoReason);
|
||||
unimplemented!("RiscV64 reset failed, manual override expected ...")
|
||||
}
|
||||
|
24
kernel/src/arch/riscv64/driver/sbi.rs
Normal file
24
kernel/src/arch/riscv64/driver/sbi.rs
Normal file
@ -0,0 +1,24 @@
|
||||
/// 向控制台打印字符串。
|
||||
///
|
||||
/// 该函数接受一个字节切片 `s` 作为输入,并迭代切片中的每个字节 `c`。
|
||||
/// 然后调用 `sbi_rt::console_write_byte` 函数,将 `c` 的值作为参数传递给它。
|
||||
///
|
||||
/// # 安全性
|
||||
///
|
||||
/// 这个函数是安全的,因为对SBI环境的操作不涉及不安全内存的访问操作。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * `s` - 表示要打印的字符串的字节切片。
|
||||
///
|
||||
/// # 示例
|
||||
///
|
||||
/// ```
|
||||
/// let message = b"Hello, World!";
|
||||
/// console_putstr(message);
|
||||
/// ```
|
||||
pub fn console_putstr(s: &[u8]) {
|
||||
for c in s {
|
||||
sbi_rt::console_write_byte(*c);
|
||||
}
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
use super::SbiError;
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行零参数的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 不接受任何参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
pub unsafe fn ecall0(extension_id: usize, function_id: usize) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
lateout("a0") error,
|
||||
lateout("a1") value,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行单参数的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 接受一个参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
pub unsafe fn ecall1(
|
||||
arg: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg => error,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
lateout("a1") value,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 一个带有给定扩展和函数ID的两参数`ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数ID接受两个参数时,才安全调用此函数。否则,行为将是未定义的,
|
||||
/// 因为将额外的中断寄存器传递给SBI实现时,其内容将是未定义的。
|
||||
#[inline]
|
||||
pub unsafe fn ecall2(
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg0 => error,
|
||||
inlateout("a1") arg1 => value,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行 3参数 的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 接受一个参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
pub unsafe fn ecall3(
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg0 => error,
|
||||
inlateout("a1") arg1 => value,
|
||||
in("a2") arg2,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行 4参数 的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 接受一个参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
pub unsafe fn ecall4(
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
arg3: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg0 => error,
|
||||
inlateout("a1") arg1 => value,
|
||||
in("a2") arg2,
|
||||
in("a3") arg3,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行 5参数 的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 接受一个参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
pub unsafe fn ecall5(
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
arg3: usize,
|
||||
arg4: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg0 => error,
|
||||
inlateout("a1") arg1 => value,
|
||||
in("a2") arg2,
|
||||
in("a3") arg3,
|
||||
in("a4") arg4,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用给定的扩展和函数 ID 进行 6参数 的 `ecall`。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 只有在给定的函数 ID 接受一个参数时,调用此函数才是安全的,否则行为是未定义的,
|
||||
/// 因为当传递给 SBI 实现时,额外的参数寄存器将具有未定义的内容。
|
||||
#[inline]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub unsafe fn ecall6(
|
||||
arg0: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
arg3: usize,
|
||||
arg4: usize,
|
||||
arg5: usize,
|
||||
extension_id: usize,
|
||||
function_id: usize,
|
||||
) -> Result<usize, SbiError> {
|
||||
let error: isize;
|
||||
let value: usize;
|
||||
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
inlateout("a0") arg0 => error,
|
||||
inlateout("a1") arg1 => value,
|
||||
in("a2") arg2,
|
||||
in("a3") arg3,
|
||||
in("a4") arg4,
|
||||
in("a5") arg5,
|
||||
in("a6") function_id,
|
||||
in("a7") extension_id,
|
||||
);
|
||||
|
||||
match error {
|
||||
0 => Result::Ok(value),
|
||||
e => Result::Err(SbiError::new(e)),
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::{arch::driver::sbi::ecall::ecall1, mm::VirtAddr};
|
||||
use core::arch::asm;
|
||||
|
||||
/// `sbi_set_timer` extension ID
|
||||
pub const SET_TIMER_EID: usize = 0x00;
|
||||
/// `sbi_console_putchar` extension ID
|
||||
pub const CONSOLE_PUTCHAR_EID: usize = 0x01;
|
||||
/// `sbi_console_getchar` extension ID
|
||||
pub const CONSOLE_GETCHAR_EID: usize = 0x02;
|
||||
/// `sbi_clear_ipi` extension ID
|
||||
pub const CLEAR_IPI_EID: usize = 0x03;
|
||||
/// `sbi_send_ipi` extension ID
|
||||
pub const SEND_IPI_EID: usize = 0x04;
|
||||
/// `sbi_remote_fence_i` extension ID
|
||||
pub const REMOTE_FENCE_I_EID: usize = 0x05;
|
||||
/// `sbi_remote_sfence_vma` extension ID
|
||||
pub const REMOTE_SFENCE_VMA_EID: usize = 0x06;
|
||||
/// `sbi_remote_sfence_vma_asid` extension ID
|
||||
pub const REMOTE_SFENCE_VMA_ASID_EID: usize = 0x07;
|
||||
/// `sbi_shutdown` extension ID
|
||||
pub const SHUTDOWN_EID: usize = 0x08;
|
||||
|
||||
/// 计划在未来的某个时间触发中断。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `stime`:要触发中断的绝对时间,以滴答为单位。如果`stime`小于当前时间,则不会触发中断。
|
||||
///
|
||||
/// ## 详情
|
||||
///
|
||||
/// 要清除计时器中断而不预约另一个计时器事件,可以将时间设置为无限远(`u64::MAX`)或
|
||||
/// mask `sie` CSR的`STIE` 位。此函数将清除待处理计时器中断位。
|
||||
///
|
||||
/// 注意:`time` 是一个绝对时间,不是从调用时刻开始的偏移量。这意味着如果您想要设置一个未来`n`和tick之后
|
||||
/// 触发的时钟,您需要首先读取 `time` CSR,然后将滴答数添加到该值。关于如何确定每个滴答的时间,
|
||||
/// 这是平台依赖的,而时钟频率应在 CPU 节点的 `timebase-frequency` 属性中表达,如果可用的话。
|
||||
#[inline]
|
||||
pub unsafe fn set_timer(stime: u64) {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
unsafe {
|
||||
ecall1(stime as usize, SET_TIMER_EID, 0).ok();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
inout ("a0") stime as usize => _,
|
||||
inout ("a1") (stime >> 32) as usize => _,
|
||||
in("a7") SET_TIMER_EID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 将字符写入调试控制台。如果仍有待处理的控制台输出,此调用将阻塞。如果不存在控制台,则不会执行任何操作。
|
||||
#[inline]
|
||||
pub unsafe fn console_putchar(c: u8) {
|
||||
unsafe {
|
||||
ecall1(c.into(), CONSOLE_PUTCHAR_EID, 0).ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// 尝试从调试控制台获取一个字符。
|
||||
/// 如果没有任何字符等待阅读,或者没有调试控制台设备,则此函数将返回[`None`]。
|
||||
#[inline]
|
||||
pub unsafe fn console_getchar() -> Option<u8> {
|
||||
let mut ret: i8;
|
||||
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
lateout("a0") ret,
|
||||
in("a7") CONSOLE_GETCHAR_EID,
|
||||
);
|
||||
}
|
||||
|
||||
match ret {
|
||||
-1 => None,
|
||||
_ => Some(ret as u8),
|
||||
}
|
||||
}
|
||||
|
||||
/// 清除current核心的待处理中断(IPIs)。
|
||||
#[inline]
|
||||
#[deprecated = "S模式可以直接清除`sip.SSIP` CSR位,因此无需调用此函数。"]
|
||||
pub unsafe fn clear_ipi() {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
in("a7") CLEAR_IPI_EID,
|
||||
lateout("a0") _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 向所有由`hart_mask`位掩码指定的核心发送中断(IPI)。接收到的中断表示为监视器软件中断。
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `hart_mask`: 一个长度为`n_harts / size_of::<usize>()`的二进制位向量,向上取整到下一个`usize`。
|
||||
#[inline]
|
||||
pub unsafe fn send_ipi(hart_mask: &[usize]) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
inlateout("a0") hart_mask.as_ptr() => _,
|
||||
in("a7") SEND_IPI_EID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 对指定的心脏(hart)执行 `FENCE.I` 指令
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `hart_mask`: 一个长度为 `n_harts / size_of::<usize>()` 的位矢量,
|
||||
/// 向上取整到下一个 `usize」。
|
||||
#[inline]
|
||||
pub unsafe fn remote_fence_i(hart_mask: &[usize]) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
inlateout("a0") hart_mask.as_ptr() => _,
|
||||
in("a7") REMOTE_FENCE_I_EID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 在指定的hart上执行`SFENCE.VMA`指令
|
||||
/// 为指定的虚拟内存范围(由`start`和`size`指定)执行。
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `hart_mask`: 一个长度为`n_harts / size_of::<usize>()`的二进制向量,
|
||||
/// 向上取整到下一个`usize`。
|
||||
/// - `start`: 要执行`SFENCE.VMA`的起始虚拟地址。
|
||||
/// - `size`: 要对`start`执行的`SFENCE.VMA`的字节大小。例如,要失效一个
|
||||
/// 包含2个4-KiB页面的区域,您会为`size`传递`8192`。
|
||||
///
|
||||
/// 如果`start`和`size`都为`0`,或者如果`size`为[`usize::MAX`],则将执行完整的
|
||||
/// `SFENCE.VMA`,而不仅仅是一个或多个页面大小的`SFENCE.VMA`。
|
||||
#[inline]
|
||||
pub unsafe fn remote_sfence_vma(hart_mask: &[usize], start: VirtAddr, size: usize) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
inlateout("a0") hart_mask.as_ptr() => _,
|
||||
in("a1") start.data(),
|
||||
in("a2") size,
|
||||
in("a7") REMOTE_SFENCE_VMA_EID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 在指定的hart上执行SFENCE.VMA指令
|
||||
///
|
||||
/// 仅针对指定的地址空间ID(ASID)执行虚拟内存范围指定的
|
||||
/// start和size的hart_mask位掩码。
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `hart_mask`: 一个长度为`n_harts / size_of::<usize>()`的二进制向量,
|
||||
/// 向上取整到下一个`usize`。
|
||||
/// - `start`: 要执行`SFENCE.VMA`的起始虚拟地址。
|
||||
/// - `size`: 要对`start`执行的`SFENCE.VMA`的字节大小。例如,要失效一个
|
||||
/// 包含2个4-KiB页面的区域,您会为`size`传递`8192`。
|
||||
/// - `asid`: 要执行`SFENCE.VMA`的地址空间ID。
|
||||
///
|
||||
/// 如果start和size都为0,或者如果size为[usize::MAX],则将执行全
|
||||
/// 部SFENCE.VMA,而不是多个页面大小的SFENCE.VMA`。
|
||||
#[inline]
|
||||
pub unsafe fn remote_sfence_vma_asid(hart_mask: &[usize], start: usize, size: usize, asid: usize) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
inlateout("a0") hart_mask.as_ptr() => _,
|
||||
in("a1") start,
|
||||
in("a2") size,
|
||||
in("a3") asid,
|
||||
in("a7") REMOTE_SFENCE_VMA_ASID_EID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 将所有核心置于关闭状态,此时处理器的执行模式比当前监督模式具有更高的特权。此调用不会返回。
|
||||
#[inline]
|
||||
pub unsafe fn shutdown() -> ! {
|
||||
unsafe {
|
||||
asm!(
|
||||
"ecall",
|
||||
in("a7") SHUTDOWN_EID,
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
use self::legacy::console_putchar;
|
||||
|
||||
/// The SBI S-mode driver.
|
||||
///
|
||||
/// Some code takes from `https://github.com/repnop/sbi.git`
|
||||
mod ecall;
|
||||
pub mod legacy;
|
||||
pub mod reset;
|
||||
|
||||
/// Error codes returned by SBI calls
|
||||
///
|
||||
/// note: `SBI_SUCCESS` is not represented here since this is to be used as the
|
||||
/// error type in a `Result`
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum SbiError {
|
||||
/// The SBI call failed
|
||||
Failed,
|
||||
/// The SBI call is not implemented or the functionality is not available
|
||||
NotSupported,
|
||||
/// An invalid parameter was passed
|
||||
InvalidParameter,
|
||||
/// The SBI implementation has denied execution of the call functionality
|
||||
Denied,
|
||||
/// An invalid address was passed
|
||||
InvalidAddress,
|
||||
/// The resource is already available
|
||||
AlreadyAvailable,
|
||||
/// The resource was previously started
|
||||
AlreadyStarted,
|
||||
/// The resource was previously stopped
|
||||
AlreadyStopped,
|
||||
}
|
||||
|
||||
impl SbiError {
|
||||
#[inline]
|
||||
fn new(n: isize) -> Self {
|
||||
match n {
|
||||
-1 => SbiError::Failed,
|
||||
-2 => SbiError::NotSupported,
|
||||
-3 => SbiError::InvalidParameter,
|
||||
-4 => SbiError::Denied,
|
||||
-5 => SbiError::InvalidAddress,
|
||||
-6 => SbiError::AlreadyAvailable,
|
||||
-7 => SbiError::AlreadyStarted,
|
||||
-8 => SbiError::AlreadyStopped,
|
||||
n => unreachable!("bad SBI error return value: {}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for SbiError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
SbiError::AlreadyAvailable => "resource is already available",
|
||||
SbiError::Denied => "SBI implementation denied execution",
|
||||
SbiError::Failed => "call to SBI failed",
|
||||
SbiError::InvalidAddress => "invalid address passed",
|
||||
SbiError::InvalidParameter => "invalid parameter passed",
|
||||
SbiError::NotSupported => "SBI call not implemented or functionality not available",
|
||||
SbiError::AlreadyStarted => "resource was already started",
|
||||
SbiError::AlreadyStopped => "resource was already stopped",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 向控制台打印字符串。
|
||||
///
|
||||
/// 该函数接受一个字节切片 `s` 作为输入,并迭代切片中的每个字节 `c`。
|
||||
/// 然后调用 `console_putchar` 函数,将 `c` 的值作为参数传递给它。
|
||||
///
|
||||
/// # 安全性
|
||||
/// 该函数被标记为 `unsafe`,因为它调用了 `console_putchar` 函数,
|
||||
/// 而假设该函数执行可能有副作用或违反内存安全的底层操作。
|
||||
/// 调用者有责任确保 `s` 切片是有效的并且正确终止的。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * `s` - 表示要打印的字符串的字节切片。
|
||||
///
|
||||
/// # 示例
|
||||
///
|
||||
/// ```
|
||||
/// let message = b"Hello, World!";
|
||||
/// console_putstr(message);
|
||||
/// ```
|
||||
pub unsafe fn console_putstr(s: &[u8]) {
|
||||
for c in s {
|
||||
unsafe { console_putchar(*c) };
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
use super::{ecall::ecall2, SbiError};
|
||||
|
||||
/// System reset extension ID
|
||||
pub const EXTENSION_ID: usize = 0x53525354;
|
||||
|
||||
/// The type of reset to perform
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ResetType {
|
||||
/// Shutdown the system
|
||||
Shutdown,
|
||||
/// Power off all hardware and perform a cold boot
|
||||
ColdReboot,
|
||||
/// Reset processors and some hardware
|
||||
WarmReboot,
|
||||
/// Platform specific reset type. The variant value is a value within the
|
||||
/// range `0x00000000..=0x0FFFFFFF`. A value outside of that range will be
|
||||
/// clamped to the maximum possible valid value for this reset type.
|
||||
PlatformSpecific(u32),
|
||||
}
|
||||
|
||||
impl ResetType {
|
||||
fn to_u32(self) -> u32 {
|
||||
match self {
|
||||
ResetType::Shutdown => 0,
|
||||
ResetType::ColdReboot => 1,
|
||||
ResetType::WarmReboot => 2,
|
||||
ResetType::PlatformSpecific(n) => n.min(0x0FFFFFFF) + 0xF0000000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The reason for performing the reset
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ResetReason {
|
||||
/// No reason for reset
|
||||
NoReason,
|
||||
/// System failure
|
||||
SystemFailure,
|
||||
/// SBI implementation specific reset reason. The variant value is a value
|
||||
/// within the range `0x00000000..=0x0FFFFFFF`. A value outside of that
|
||||
/// range will be clamped to the maximum possible valid value for this reset
|
||||
/// reason type.
|
||||
SbiSpecific(u32),
|
||||
/// Platform specific reset reason. The variant value is a value within the
|
||||
/// range `0x00000000..=0x0FFFFFFF`. A value outside of that range will be
|
||||
/// clamped to the maximum possible valid value for this reset reason type.
|
||||
PlatformSpecific(u32),
|
||||
}
|
||||
|
||||
impl ResetReason {
|
||||
fn to_u32(self) -> u32 {
|
||||
match self {
|
||||
ResetReason::NoReason => 0,
|
||||
ResetReason::SystemFailure => 1,
|
||||
ResetReason::SbiSpecific(n) => n.min(0x0FFFFFFF) + 0xE0000000,
|
||||
ResetReason::PlatformSpecific(n) => n.min(0x0FFFFFFF) + 0xF0000000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to reset the system in the provided method, with a reason for the
|
||||
/// reset.
|
||||
///
|
||||
/// ### Possible errors
|
||||
///
|
||||
/// [`SbiError::NotSupported`]: The [`ResetType`] is valid but not implemented.
|
||||
///
|
||||
/// [`SbiError::Failed`]: The system reset request failed for an unknown reason.
|
||||
pub fn system_reset(
|
||||
kind: ResetType,
|
||||
reason: ResetReason,
|
||||
) -> Result<core::convert::Infallible, SbiError> {
|
||||
match unsafe {
|
||||
ecall2(
|
||||
kind.to_u32() as usize,
|
||||
reason.to_u32() as usize,
|
||||
EXTENSION_ID,
|
||||
0,
|
||||
)
|
||||
} {
|
||||
Ok(_) => unreachable!("SBI returned `Ok` after a system reset call"),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
@ -564,7 +564,7 @@ pub fn send_to_default_serial8250_port(s: &[u8]) {
|
||||
if unsafe { INITIALIZED } {
|
||||
todo!("riscv64: send_to_default_serial8250_port")
|
||||
} else {
|
||||
unsafe { crate::arch::driver::sbi::console_putstr(s) };
|
||||
crate::arch::driver::sbi::console_putstr(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user