sbi_rt/susp.rs
1//! Chapter 13. System Suspend Extension (EID #0x53555350 "SUSP")
2
3use crate::binary::sbi_call_3;
4use sbi_spec::{
5 binary::SbiRet,
6 susp::{EID_SUSP, SUSPEND},
7};
8
9/// Suspend the system based on provided `sleep_type`.
10///
11/// # Parameters
12///
13/// The `sleep_type` parameter specifies the sleep type.
14///
15/// | Type | Name | Description
16/// |:------------------------|:---------------|:----------------------------------------------
17/// | 0 | SUSPEND_TO_RAM | This is a "suspend to RAM" sleep type, similar to ACPI's S2 or S3. Entry requires all but the calling hart be in the HSM `STOPPED` state and all hart registers and CSRs saved to RAM.
18/// | 0x00000001 - 0x7fffffff | | Reserved for future use
19/// | 0x80000000 - 0xffffffff | | Platform-specific system sleep types
20///
21/// The `resume_addr` parameter points to a runtime-specified physical address,
22/// where the hart can resume execution in supervisor-mode after a system suspend.
23///
24/// The `opaque` parameter is an XLEN-bit value that will be set in the `a1`
25/// register when the hart resumes execution at `resume_addr` after a system
26/// suspend.
27///
28/// # Return value
29///
30/// The possible return error codes returned in `SbiRet.error` are shown in
31/// the table below:
32///
33/// | Return code | Description
34/// |:--------------------------|:----------------------------------------------
35/// | `SbiRet::success()` | The suspend request is accepted, and the system is suspended. The system will resume execution at `resume_addr` after the sleep period.
36/// | `SbiRet::invalid_param()` | `sleep_type` is reserved or is platform-specific and unimplemented.
37/// | `SbiRet::not_supported()` | `sleep_type` is not reserved and is implemented, but the platform does not support it due to one or more missing dependencies.
38/// | `SbiRet::invalid_address()` | `resume_addr` is not valid, possibly due to the following reasons: + * It is not a valid physical address. + * Executable access to the address is prohibited by a physical memory protection mechanism or H-extension G-stage for supervisor mode.
39/// | `SbiRet::denied()` | The suspend request failed due to unsatisfied entry criteria.
40/// | `SbiRet::failed()` | The suspend request failed for unspecified or unknown other reasons.
41///
42/// This function is defined in RISC-V SBI Specification chapter 13.1.
43#[inline]
44pub fn system_suspend<T>(sleep_type: T, resume_addr: usize, opaque: usize) -> SbiRet
45where
46 T: SleepType,
47{
48 sbi_call_3(
49 EID_SUSP,
50 SUSPEND,
51 sleep_type.raw() as _,
52 resume_addr,
53 opaque,
54 )
55}
56
57/// A valid sleep type for system suspend.
58pub trait SleepType {
59 /// Get a raw value to pass to SBI environment.
60 fn raw(&self) -> u32;
61}
62
63#[cfg(feature = "integer-impls")]
64impl SleepType for u32 {
65 #[inline]
66 fn raw(&self) -> u32 {
67 *self
68 }
69}
70
71#[cfg(feature = "integer-impls")]
72impl SleepType for i32 {
73 #[inline]
74 fn raw(&self) -> u32 {
75 u32::from_ne_bytes(i32::to_ne_bytes(*self))
76 }
77}
78
79/// Suspend to RAM as sleep type.
80#[derive(Clone, Copy, Debug)]
81pub struct SuspendToRam;
82
83impl SleepType for SuspendToRam {
84 #[inline]
85 fn raw(&self) -> u32 {
86 0
87 }
88}