sbi_rt/
hsm.rs

1//! Chapter 9. Hart State Management Extension (EID #0x48534D "HSM")
2
3use crate::binary::{sbi_call_0, sbi_call_1, sbi_call_3};
4
5use sbi_spec::{
6    binary::SbiRet,
7    hsm::{EID_HSM, HART_GET_STATUS, HART_START, HART_STOP, HART_SUSPEND},
8};
9
10/// Start executing the given hart at specified address in supervisor-mode.
11///
12/// This call is asynchronous - more specifically, the `hart_start()` may return before target hart starts
13/// executing as long as the SBI implementation is capable of ensuring the return code is accurate.
14///
15/// It is recommended that if the SBI implementation is a platform runtime firmware executing in
16/// machine-mode (M-mode), then it MUST configure PMP and other the M-mode state before executing
17/// in supervisor-mode.
18///
19/// # Parameters
20///
21/// - The `hartid` parameter specifies the target hart, which is to be started.
22/// - The `start_addr` parameter points to a runtime-specified physical address,
23/// where the hart can start executing in supervisor-mode.
24/// - The `opaque` parameter is a `usize` value that will be set in the `a1`
25/// register when the hart starts executing at `start_addr`.
26///
27/// *NOTE:* A single `usize` parameter is sufficient as `start_addr`,
28/// because the hart will start execution in the supervisor-mode with MMU off,
29/// hence the `start_addr` must be less than XLEN bits wide.
30///
31/// # Behavior
32///
33/// The target hart jumps to supervisor mode at the address specified by `start_addr`
34/// with the following values in specific registers.
35///
36/// | Register Name | Register Value
37/// |:--------------|:--------------
38/// | `satp`        | 0
39/// | `sstatus.SIE` | 0
40/// | a0            | hartid
41/// | a1            | `opaque` parameter
42///
43/// # Return value
44///
45/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
46///
47/// | Return code                   | Description
48/// |:------------------------------|:----------------------------------------------
49/// | `SbiRet::success()`           | Hart was previously in stopped state.
50/// It will start executing from `start_addr`.
51/// | `SbiRet::invalid_address()`   | `start_addr` is not valid, possibly due to the following reasons:
52/// it is not a valid physical address,
53/// or the address is prohibited by PMP or H-extension G-stage to run in supervisor-mode.
54/// | `SbiRet::invalid_param()`     | `hartid`
55/// is not a valid hartid as corresponding hart cannot be started in supervisor mode.
56/// | `SbiRet::already_available()` | The given hartid is already started.
57/// | `SbiRet::failed()`            | The start request failed for unknown reasons.
58///
59/// This function is defined in RISC-V SBI Specification chapter 9.1.
60#[inline]
61pub fn hart_start(hartid: usize, start_addr: usize, opaque: usize) -> SbiRet {
62    sbi_call_3(EID_HSM, HART_START, hartid, start_addr, opaque)
63}
64
65/// Stop executing the calling hart in supervisor-mode.
66///
67/// This function requests the SBI implementation to stop executing the calling hart in
68/// supervisor-mode and return its ownership to the SBI implementation.
69///
70/// This call is not expected to return under normal conditions.
71/// The `sbi_hart_stop()` must be called with the supervisor-mode interrupts disabled.
72///
73/// # Return value
74///
75/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
76///
77/// | Error code  | Description
78/// |:------------|:------------
79/// | `SbiRet::failed()` | Failed to stop execution of the current hart
80///
81/// This function is defined in RISC-V SBI Specification chapter 9.2.
82#[inline]
83pub fn hart_stop() -> SbiRet {
84    sbi_call_0(EID_HSM, HART_STOP)
85}
86
87/// Get the current status (or HSM state id) of the given hart.
88///
89/// The harts may transition HSM states at any time due to any concurrent `hart_start()`
90/// or `hart_stop()` calls, the return value from this function may not represent the actual state
91/// of the hart at the time of return value verification.
92///
93/// # Parameters
94///
95/// The `hartid` parameter specifies the target hart which status is required.
96///
97/// # Return value
98///
99/// The possible status values returned in `SbiRet.value` are shown in the table below:
100///
101/// | Name          | Value | Description
102/// |:--------------|:------|:-------------------------
103/// | STARTED       |   0   | Hart Started
104/// | STOPPED       |   1   | Hart Stopped
105/// | START_PENDING |   2   | Hart start request pending
106/// | STOP_PENDING  |   3   | Hart stop request pending
107///
108/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
109///
110/// | Error code                | Description
111/// |:--------------------------|:------------
112/// | `SbiRet::invalid_param()` | The given `hartid` is not valid
113///
114/// This function is defined in RISC-V SBI Specification chapter 9.3.
115#[inline]
116pub fn hart_get_status(hartid: usize) -> SbiRet {
117    sbi_call_1(EID_HSM, HART_GET_STATUS, hartid)
118}
119
120/// Put the calling hart into suspend or platform specific lower power states.
121///
122/// This function requests the SBI implementation to put the calling hart in a platform specfic suspend
123/// (or low power) state specified by the `suspend_type` parameter.
124///
125/// The hart will automatically come out of suspended state and resume normal execution
126/// when it receives an interrupt or platform specific hardware event.
127///
128/// # Suspend behavior
129///
130/// The platform-specific suspend states for a hart can be either retentive or non-retentive in nature.
131///
132/// A retentive suspend state will preserve hart register and CSR values for all privilege modes,
133/// whereas a non-retentive suspend state will not preserve hart register and CSR values.
134///
135/// # Resuming
136///
137/// Resuming from a retentive suspend state is straight forward, and the supervisor-mode software
138/// will see SBI suspend call return without any failures.
139///
140/// Resuming from a non-retentive suspend state is relatively more involved, and it requires software
141/// to restore various hart registers and CSRs for all privilege modes.
142/// Upon resuming from non-retentive suspend state, the hart will jump to supervisor-mode at address
143/// specified by `resume_addr` with specific registers values described in the table below:
144///
145/// | Register Name | Register Value
146/// |:--------------|:--------------
147/// | `satp`        | 0
148/// | `sstatus.SIE` | 0
149/// | a0            | hartid
150/// | a1            | `opaque` parameter
151///
152/// # Parameters
153///
154/// The `suspend_type` parameter is 32 bits wide, and the possible values are shown in the table below:
155///
156/// | Value                   | Description
157/// |:------------------------|:--------------
158/// | 0x00000000              | Default retentive suspend
159/// | 0x00000001 - 0x0FFFFFFF | _Reserved for future use_
160/// | 0x10000000 - 0x7FFFFFFF | Platform specific retentive suspend
161/// | 0x80000000              | Default non-retentive suspend
162/// | 0x80000001 - 0x8FFFFFFF | _Reserved for future use_
163/// | 0x90000000 - 0xFFFFFFFF | Platform specific non-retentive suspend
164/// | > 0xFFFFFFFF            | _Reserved_
165///
166/// The `resume_addr` parameter points to a runtime-specified physical address,
167/// where the hart can resume execution in supervisor-mode after a non-retentive
168/// suspend.
169///
170/// *NOTE:* A single `usize` parameter is sufficient as `resume_addr`,
171/// because the hart will resume execution in the supervisor-mode with MMU off,
172/// hence the `resume_addr` must be less than XLEN bits wide.
173///
174/// The `opaque` parameter is an XLEN-bit value that will be set in the `a1`
175/// register when the hart resumes execution at `resume_addr` after a
176/// non-retentive suspend.
177///
178/// # Return value
179///
180/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
181///
182/// | Error code                  | Description
183/// |:----------------------------|:------------
184/// | `SbiRet::success()`         | Hart has been suspended and resumed back successfully from a retentive suspend state.
185/// | `SbiRet::invalid_param()`   | `suspend_type` is not valid.
186/// | `SbiRet::not_supported()`   | `suspend_type` is valid but not implemented.
187/// | `SbiRet::invalid_address()` | `resume_addr` is not valid, possibly due to the following reasons: it is not a valid physical address, or the address is prohibited by PMP or H-extension G-stage to run in supervisor-mode.
188/// | `SbiRet::failed()`          | The suspend request failed for unknown reasons.
189///
190/// This function is defined in RISC-V SBI Specification chapter 9.4.
191#[inline]
192pub fn hart_suspend<T>(suspend_type: T, resume_addr: usize, opaque: usize) -> SbiRet
193where
194    T: SuspendType,
195{
196    sbi_call_3(
197        EID_HSM,
198        HART_SUSPEND,
199        suspend_type.raw() as _,
200        resume_addr,
201        opaque,
202    )
203}
204
205/// A valid suspend type for hart state monitor.
206pub trait SuspendType {
207    /// Get a raw value to pass to SBI environment.
208    fn raw(&self) -> u32;
209}
210
211#[cfg(feature = "integer-impls")]
212impl SuspendType for u32 {
213    #[inline]
214    fn raw(&self) -> u32 {
215        *self
216    }
217}
218
219macro_rules! define_suspend_type {
220    ($($struct:ident($value:expr) #[$doc:meta])*) => {
221        $(
222            #[derive(Clone, Copy, Debug)]
223            #[$doc]
224            pub struct $struct;
225            impl SuspendType for $struct {
226                #[inline]
227                fn raw(&self) -> u32 {
228                    $value
229                }
230            }
231        )*
232    };
233}
234
235define_suspend_type! {
236    Retentive(sbi_spec::hsm::suspend_type::RETENTIVE) /// Default retentive hart suspension.
237    NonRetentive(sbi_spec::hsm::suspend_type::NON_RETENTIVE) /// Default non-retentive hart suspension.
238}