sbi/system_suspend.rs
1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2023 repnop
3//
4// This Source Code Form is subject to the terms of the Mozilla Public License,
5// v. 2.0. If a copy of the MPL was not distributed with this file, You can
6// obtain one at https://mozilla.org/MPL/2.0/.
7
8use crate::{ecall3, PhysicalAddress, RestrictedRange, SbiError};
9use core::convert::Infallible;
10
11/// System suspend extension ID
12pub const EXTENSION_ID: usize = 0x53555350;
13
14/// A set of values describing possible sleep states to enter
15#[derive(Debug, Clone, Copy)]
16#[non_exhaustive]
17pub enum SleepType {
18 /// Sleep type similar to ACPI S2 or S3 modes. This mode requires all harts
19 /// except for the calling hart to be in the [`HartState::Stopped`][0] state
20 /// and all hart registers and CSR values must be saved to RAM.
21 ///
22 /// [0]: crate::hart_state_management::HartState::Stopped
23 SuspendToRam,
24 /// Platform specific sleep type value
25 PlatformSpecific(RestrictedRange<0x80000000, 0xFFFFFFFF>),
26}
27
28impl From<SleepType> for u32 {
29 fn from(value: SleepType) -> Self {
30 match value {
31 SleepType::SuspendToRam => 0,
32 SleepType::PlatformSpecific(n) => n.0,
33 }
34 }
35}
36
37/// Attempt to suspend the system in a way specified by the given [`SleepType`].
38/// After a successful suspension, the calling hart will be resumed in S-mode
39/// with `satp` and `sstatus.SIE` both initialized to `0` (thus, no memory
40/// protection is enabled and interrupts are disabled) at the given
41/// `resume_addr` with the hart ID in register `a0` and the `opaque` value in
42/// register `a1`.
43///
44/// ### Safety
45///
46/// This function is marked as unsafe as it relies on resuming to a valid
47/// physical address that is properly set up to handle execution with no memory
48/// protection and an undefined register state (except `a0` and `a1`)
49///
50/// ### Possible errors
51///
52/// [`SbiError::INVALID_PARAMETER`]: The provided [`SleepType`] is reserved or
53/// is platform-specific and unimplemented.
54///
55/// [`SbiError::NOT_SUPPORTED`]: The provided [`SleepType`] is implemented and
56/// not reserved, but the platform does not support it due to one or more
57/// missing dependencies.
58///
59/// [`SbiError::INVALID_ADDRESS`]: The provided `resume_addr` is not valid for
60/// one or more reasons, potentially relating to memory protection or the
61/// validity of the physical address.
62///
63/// [`SbiError::DENIED`]: The request failed due to unsatisfied entry criteria.
64///
65/// [`SbiError::FAILED`]: The request failed for unspecified or unknown reasons.
66#[doc(alias = "sbi_system_suspend")]
67pub unsafe fn system_suspend(
68 sleep_type: SleepType,
69 resume_addr: PhysicalAddress<()>,
70 opaque: usize,
71) -> Result<Infallible, SbiError> {
72 let ret = unsafe {
73 ecall3(
74 usize::try_from(u32::from(sleep_type)).unwrap(),
75 resume_addr.0 as usize,
76 opaque,
77 EXTENSION_ID,
78 0,
79 )
80 };
81
82 match ret {
83 Ok(_) => unreachable!(),
84 Err(e) => Err(e),
85 }
86}