susp.rs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. pub fn system_suspend<T>(sleep_type: T, resume_addr: usize, opaque: usize) -> SbiRet
  43. where
  44. T: SleepType,
  45. {
  46. sbi_call_3(
  47. EID_SUSP,
  48. SUSPEND,
  49. sleep_type.raw() as _,
  50. resume_addr,
  51. opaque,
  52. )
  53. }
  54. /// A valid sleep type for system suspend.
  55. pub trait SleepType {
  56. /// Get a raw value to pass to SBI environment.
  57. fn raw(&self) -> u32;
  58. }
  59. #[cfg(feature = "integer-impls")]
  60. impl SleepType for u32 {
  61. #[inline]
  62. fn raw(&self) -> u32 {
  63. *self
  64. }
  65. }
  66. #[cfg(feature = "integer-impls")]
  67. impl SleepType for i32 {
  68. #[inline]
  69. fn raw(&self) -> u32 {
  70. u32::from_ne_bytes(i32::to_ne_bytes(*self))
  71. }
  72. }
  73. /// Suspend to RAM as sleep type.
  74. #[derive(Clone, Copy, Debug)]
  75. pub struct SuspendToRam;
  76. impl SleepType for SuspendToRam {
  77. #[inline]
  78. fn raw(&self) -> u32 {
  79. 0
  80. }
  81. }