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