sbi_rt/
pmu.rs

1//! Chapter 11. Performance Monitoring Unit Extension (EID #0x504D55 "PMU")
2
3use crate::binary::{sbi_call_0, sbi_call_1, sbi_call_3};
4
5use sbi_spec::{
6    binary::SbiRet,
7    pmu::{
8        COUNTER_CONFIG_MATCHING, COUNTER_FW_READ, COUNTER_FW_READ_HI, COUNTER_GET_INFO,
9        COUNTER_START, COUNTER_STOP, EID_PMU, NUM_COUNTERS,
10    },
11};
12
13/// Returns the number of counters, both hardware and firmware.
14///
15/// This call would always succeed without returning any error.
16///
17/// This function is defined in RISC-V SBI Specification chapter 11.5.
18#[inline]
19pub fn pmu_num_counters() -> usize {
20    sbi_call_0(EID_PMU, NUM_COUNTERS).value
21}
22
23/// Get details about the specified counter.
24///
25/// The value returned includes details such as underlying CSR number, width of the counter,
26/// type of counter (hardware or firmware), etc.
27///
28/// The `counter_info` returned by this SBI call is encoded as follows:
29///
30/// ```text
31///     counter_info[11:0] = CSR; // (12bit CSR number)
32///     counter_info[17:12] = Width; // (One less than number of bits in CSR)
33///     counter_info[XLEN-2:18] = Reserved; // Reserved for future use
34///     counter_info[XLEN-1] = Type; // (0 = hardware and 1 = firmware)
35/// ```
36/// If `counter_info.type` == `1` then `counter_info.csr` and `counter_info.width` should be ignored.
37///
38/// This function is defined in RISC-V SBI Specification chapter 11.6.
39///
40/// # Return value
41///
42/// Returns the `counter_info` described above in `SbiRet.value`.
43///
44/// The possible return error codes returned in `SbiRet.error` are shown in the table below:    
45///
46/// | Return code               | Description
47/// |:--------------------------|:----------------------------------------------
48/// | `SbiRet::success()`       | `counter_info` read successfully.
49/// | `SbiRet::invalid_param()` | `counter_idx` points to an invalid counter.
50///
51/// This function is defined in RISC-V SBI Specification chapter 11.6.
52#[inline]
53pub fn pmu_counter_get_info(counter_idx: usize) -> SbiRet {
54    sbi_call_1(EID_PMU, COUNTER_GET_INFO, counter_idx)
55}
56
57/// Find and configure a counter from a set of counters.
58///
59/// The counters to be found and configured should not be started (or enabled)
60/// and should be able to monitor the specified event.
61///
62/// # Parameters
63///
64/// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters,
65/// whereas the `event_idx` represent the event to be monitored
66/// and `event_data` represents any additional event configuration.
67///
68/// The `config_flags` parameter represents additional configuration and filter flags of the counter.
69/// The bit definitions of the `config_flags` parameter are shown in the table below:
70///
71/// | Flag Name                    | Bits       | Description
72/// |:-----------------------------|:-----------|:------------
73/// | SBI_PMU_CFG_FLAG_SKIP_MATCH  | 0:0        | Skip the counter matching
74/// | SBI_PMU_CFG_FLAG_CLEAR_VALUE | 1:1        | Clear (or zero) the counter value in counter configuration
75/// | SBI_PMU_CFG_FLAG_AUTO_START  | 2:2        | Start the counter after configuring a matching counter
76/// | SBI_PMU_CFG_FLAG_SET_VUINH   | 3:3        | Event counting inhibited in VU-mode
77/// | SBI_PMU_CFG_FLAG_SET_VSINH   | 4:4        | Event counting inhibited in VS-mode
78/// | SBI_PMU_CFG_FLAG_SET_UINH    | 5:5        | Event counting inhibited in U-mode
79/// | SBI_PMU_CFG_FLAG_SET_SINH    | 6:6        | Event counting inhibited in S-mode
80/// | SBI_PMU_CFG_FLAG_SET_MINH    | 7:7        | Event counting inhibited in M-mode
81/// | _RESERVED_                   | 8:(XLEN-1) | _All non-zero values are reserved for future use._
82///
83/// *NOTE:* When *SBI_PMU_CFG_FLAG_SKIP_MATCH* is set in `config_flags`, the
84/// SBI implementation will unconditionally select the first counter from the
85/// set of counters specified by the `counter_idx_base` and `counter_idx_mask`.
86///
87/// *NOTE:* The *SBI_PMU_CFG_FLAG_AUTO_START* flag in `config_flags` has no
88/// impact on the value of the counter.
89///
90/// *NOTE:* The `config_flags[3:7]` bits are event filtering hints so these
91/// can be ignored or overridden by the SBI implementation for security concerns
92/// or due to lack of event filtering support in the underlying RISC-V platform.
93///
94/// # Return value
95///
96/// Returns the `counter_idx` in `sbiret.value` upon success.
97///
98/// In case of failure, the possible error codes returned in `sbiret.error` are shown in the table below:    
99///
100/// | Return code               | Description
101/// |:--------------------------|:----------------------------------------------
102/// | `SbiRet::success()`       | counter found and configured successfully.
103/// | `SbiRet::invalid_param()` | set of counters has an invalid counter.
104/// | `SbiRet::not_supported()` | none of the counters can monitor specified event.
105///
106/// This function is defined in RISC-V SBI Specification chapter 11.7.
107#[inline]
108pub fn pmu_counter_config_matching<T>(
109    counter_idx_base: usize,
110    counter_idx_mask: usize,
111    config_flags: T,
112    event_idx: usize,
113    event_data: u64,
114) -> SbiRet
115where
116    T: ConfigFlags,
117{
118    match () {
119        #[cfg(target_pointer_width = "32")]
120        () => crate::binary::sbi_call_6(
121            EID_PMU,
122            COUNTER_CONFIG_MATCHING,
123            counter_idx_base,
124            counter_idx_mask,
125            config_flags.raw(),
126            event_idx,
127            event_data as _,
128            (event_data >> 32) as _,
129        ),
130        #[cfg(target_pointer_width = "64")]
131        () => crate::binary::sbi_call_5(
132            EID_PMU,
133            COUNTER_CONFIG_MATCHING,
134            counter_idx_base,
135            counter_idx_mask,
136            config_flags.raw(),
137            event_idx,
138            event_data as _,
139        ),
140    }
141}
142
143/// Start or enable a set of counters on the calling hart with the specified initial value.
144///
145/// # Parameters
146///
147/// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters.
148/// whereas the `initial_value` parameter specifies the initial value of the counter.
149///
150/// The bit definitions of the `start_flags` parameter are shown in the table below:
151///
152/// | Flag Name                    | Bits       | Description
153/// |:-----------------------------|:-----------|:------------
154/// | SBI_PMU_START_SET_INIT_VALUE | 0:0        | Set the value of counters based on the `initial_value` parameter.
155/// | _RESERVED_                   | 1:(XLEN-1) | _All non-zero values are reserved for future use._
156///
157/// *NOTE*: When `SBI_PMU_START_SET_INIT_VALUE` is not set in `start_flags`, the value of counter will
158/// not be modified, and event counting will start from the current value of counter.
159///
160/// # Return value
161///
162/// The possible return error codes returned in `SbiRet.error` are shown in the table below:    
163///
164/// | Return code                 | Description
165/// |:----------------------------|:----------------------------------------------
166/// | `SbiRet::success()`         | counter started successfully.
167/// | `SbiRet::invalid_param()`   | some of the counters specified in parameters are invalid.
168/// | `SbiRet::already_started()` | some of the counters specified in parameters are already started.
169///
170/// This function is defined in RISC-V SBI Specification chapter 11.8.
171#[inline]
172pub fn pmu_counter_start<T>(
173    counter_idx_base: usize,
174    counter_idx_mask: usize,
175    start_flags: T,
176    initial_value: u64,
177) -> SbiRet
178where
179    T: StartFlags,
180{
181    match () {
182        #[cfg(target_pointer_width = "32")]
183        () => crate::binary::sbi_call_5(
184            EID_PMU,
185            COUNTER_START,
186            counter_idx_base,
187            counter_idx_mask,
188            start_flags.raw(),
189            initial_value as _,
190            (initial_value >> 32) as _,
191        ),
192        #[cfg(target_pointer_width = "64")]
193        () => crate::binary::sbi_call_4(
194            EID_PMU,
195            COUNTER_START,
196            counter_idx_base,
197            counter_idx_mask,
198            start_flags.raw(),
199            initial_value as _,
200        ),
201    }
202}
203
204/// Stop or disable a set of counters on the calling hart.
205///
206/// # Parameters
207///
208/// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters.
209/// The bit definitions of the `stop_flags` parameter are shown in the table below:
210///
211/// | Flag Name               | Bits       | Description
212/// |:------------------------|:-----------|:------------
213/// | SBI_PMU_STOP_FLAG_RESET | 0:0        | Reset the counter to event mapping.
214/// | _RESERVED_              | 1:(XLEN-1) | *All non-zero values are reserved for future use.*
215///
216/// # Return value
217///
218/// The possible return error codes returned in `SbiRet.error` are shown in the table below:    
219///
220/// | Return code                 | Description
221/// |:----------------------------|:----------------------------------------------
222/// | `SbiRet::success()`         | counter stopped successfully.
223/// | `SbiRet::invalid_param()`   | some of the counters specified in parameters are invalid.
224/// | `SbiRet::already_stopped()` | some of the counters specified in parameters are already stopped.
225///
226/// This function is defined in RISC-V SBI Specification chapter 11.9.
227#[inline]
228pub fn pmu_counter_stop<T>(
229    counter_idx_base: usize,
230    counter_idx_mask: usize,
231    stop_flags: T,
232) -> SbiRet
233where
234    T: StopFlags,
235{
236    sbi_call_3(
237        EID_PMU,
238        COUNTER_STOP,
239        counter_idx_base,
240        counter_idx_mask,
241        stop_flags.raw(),
242    )
243}
244
245/// Provide the current value of a firmware counter.
246///
247/// On RV32 systems, the `SbiRet.value` will only contain the lower 32 bits from the current
248/// value of the firmware counter.
249///
250/// # Parameters
251///
252/// This function should be only used to read a firmware counter. It will return an error
253/// when a user provides a hardware counter in `counter_idx` parameter.
254///
255/// # Return value
256///
257/// The possible return error codes returned in `SbiRet.error` are shown in the table below:    
258///
259/// | Return code               | Description
260/// |:--------------------------|:----------------------------------------------
261/// | `SbiRet::success()`       | firmware counter read successfully.
262/// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
263///
264/// This function is defined in RISC-V SBI Specification chapter 11.10.
265#[inline]
266pub fn pmu_counter_fw_read(counter_idx: usize) -> SbiRet {
267    sbi_call_1(EID_PMU, COUNTER_FW_READ, counter_idx)
268}
269
270/// Provide the upper 32 bits from the value of a firmware counter.
271///
272/// This function always returns zero in `SbiRet.value` for RV64 (or higher) systems.
273///
274/// # Return value
275///
276/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
277///
278/// | Return code               | Description
279/// |:--------------------------|:----------------------------------------------
280/// | `SbiRet::success()`       | firmware counter read successfully.
281/// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
282///
283/// This function is defined in RISC-V SBI Specification chapter 11.11.
284#[inline]
285pub fn pmu_counter_fw_read_hi(counter_idx: usize) -> SbiRet {
286    sbi_call_1(EID_PMU, COUNTER_FW_READ_HI, counter_idx)
287}
288
289/// Flags to configure performance counter.
290pub trait ConfigFlags {
291    /// Get a raw value to pass to SBI environment.
292    fn raw(&self) -> usize;
293}
294
295#[cfg(feature = "integer-impls")]
296impl ConfigFlags for usize {
297    #[inline]
298    fn raw(&self) -> usize {
299        *self
300    }
301}
302
303/// Flags to start performance counter.
304pub trait StartFlags {
305    /// Get a raw value to pass to SBI environment.
306    fn raw(&self) -> usize;
307}
308
309#[cfg(feature = "integer-impls")]
310impl StartFlags for usize {
311    #[inline]
312    fn raw(&self) -> usize {
313        *self
314    }
315}
316
317/// Flags to stop performance counter.
318pub trait StopFlags {
319    /// Get a raw value to pass to SBI environment.
320    fn raw(&self) -> usize;
321}
322
323#[cfg(feature = "integer-impls")]
324impl StopFlags for usize {
325    #[inline]
326    fn raw(&self) -> usize {
327        *self
328    }
329}