susp.rs 3.3 KB

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