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::{CounterMask, SbiRet, SharedPtr},
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, SNAPSHOT_SET_SHMEM, shmem_size::SIZE,
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.6.
18#[inline]
19#[doc(alias = "sbi_pmu_num_counters")]
20pub fn pmu_num_counters() -> usize {
21 sbi_call_0(EID_PMU, NUM_COUNTERS).value
22}
23
24/// Get details about the specified counter.
25///
26/// The value returned includes details such as underlying CSR number, width of the counter,
27/// type of counter (hardware or firmware), etc.
28///
29/// The `counter_info` returned by this SBI call is encoded as follows:
30///
31/// ```text
32/// counter_info[11:0] = CSR; // (12bit CSR number)
33/// counter_info[17:12] = Width; // (One less than number of bits in CSR)
34/// counter_info[XLEN-2:18] = Reserved; // Reserved for future use
35/// counter_info[XLEN-1] = Type; // (0 = hardware and 1 = firmware)
36/// ```
37/// If `counter_info.type` == `1` then `counter_info.csr` and `counter_info.width` should be ignored.
38///
39/// # Return value
40///
41/// Returns the `counter_info` described above in `SbiRet.value`.
42///
43/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
44///
45/// | Return code | Description
46/// |:--------------------------|:----------------------------------------------
47/// | `SbiRet::success()` | `counter_info` read successfully.
48/// | `SbiRet::invalid_param()` | `counter_idx` points to an invalid counter.
49///
50/// This function is defined in RISC-V SBI Specification chapter 11.7.
51#[inline]
52#[doc(alias = "sbi_pmu_counter_get_info")]
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` parameter 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`.
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.8.
107#[inline]
108#[doc(alias = "sbi_pmu_counter_config_matching")]
109pub fn pmu_counter_config_matching<T>(
110 counter_idx: CounterMask,
111 config_flags: T,
112 event_idx: usize,
113 event_data: u64,
114) -> SbiRet
115where
116 T: ConfigFlags,
117{
118 let (counter_idx_mask, counter_idx_base) = counter_idx.into_inner();
119 match () {
120 #[cfg(target_pointer_width = "32")]
121 () => crate::binary::sbi_call_6(
122 EID_PMU,
123 COUNTER_CONFIG_MATCHING,
124 counter_idx_base,
125 counter_idx_mask,
126 config_flags.raw(),
127 event_idx,
128 event_data as _,
129 (event_data >> 32) as _,
130 ),
131 #[cfg(target_pointer_width = "64")]
132 () => crate::binary::sbi_call_5(
133 EID_PMU,
134 COUNTER_CONFIG_MATCHING,
135 counter_idx_base,
136 counter_idx_mask,
137 config_flags.raw(),
138 event_idx,
139 event_data as _,
140 ),
141 }
142}
143
144/// Start or enable a set of counters on the calling hart with the specified initial value.
145///
146/// # Parameters
147///
148/// The `counter_idx` parameter represent the set of counters.
149/// whereas the `initial_value` parameter specifies the initial value of the counter.
150///
151/// The bit definitions of the `start_flags` parameter are shown in the table below:
152///
153/// | Flag Name | Bits | Description
154/// |:-----------------------------|:-----------|:------------
155/// | SBI_PMU_START_SET_INIT_VALUE | 0:0 | Set the value of counters based on the `initial_value` parameter.
156/// | _RESERVED_ | 1:(XLEN-1) | _All non-zero values are reserved for future use._
157///
158/// *NOTE*: When `SBI_PMU_START_SET_INIT_VALUE` is not set in `start_flags`, the value of counter will
159/// not be modified, and event counting will start from the current value of counter.
160///
161/// # Return value
162///
163/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
164///
165/// | Return code | Description
166/// |:----------------------------|:----------------------------------------------
167/// | `SbiRet::success()` | counter started successfully.
168/// | `SbiRet::invalid_param()` | some of the counters specified in parameters are invalid.
169/// | `SbiRet::already_started()` | some of the counters specified in parameters are already started.
170///
171/// This function is defined in RISC-V SBI Specification chapter 11.9.
172#[inline]
173#[doc(alias = "sbi_pmu_counter_start")]
174pub fn pmu_counter_start<T>(counter_idx: CounterMask, start_flags: T, initial_value: u64) -> SbiRet
175where
176 T: StartFlags,
177{
178 let (counter_idx_mask, counter_idx_base) = counter_idx.into_inner();
179 match () {
180 #[cfg(target_pointer_width = "32")]
181 () => crate::binary::sbi_call_5(
182 EID_PMU,
183 COUNTER_START,
184 counter_idx_base,
185 counter_idx_mask,
186 start_flags.raw(),
187 initial_value as _,
188 (initial_value >> 32) as _,
189 ),
190 #[cfg(target_pointer_width = "64")]
191 () => crate::binary::sbi_call_4(
192 EID_PMU,
193 COUNTER_START,
194 counter_idx_base,
195 counter_idx_mask,
196 start_flags.raw(),
197 initial_value as _,
198 ),
199 }
200}
201
202/// Stop or disable a set of counters on the calling hart.
203///
204/// # Parameters
205///
206/// The `counter_idx` parameter represents the set of counters.
207/// The bit definitions of the `stop_flags` parameter are shown in the table below:
208///
209/// | Flag Name | Bits | Description
210/// |:------------------------|:-----------|:------------
211/// | SBI_PMU_STOP_FLAG_RESET | 0:0 | Reset the counter to event mapping.
212/// | _RESERVED_ | 1:(XLEN-1) | *All non-zero values are reserved for future use.*
213///
214/// # Return value
215///
216/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
217///
218/// | Return code | Description
219/// |:----------------------------|:----------------------------------------------
220/// | `SbiRet::success()` | counter stopped successfully.
221/// | `SbiRet::invalid_param()` | some of the counters specified in parameters are invalid.
222/// | `SbiRet::already_stopped()` | some of the counters specified in parameters are already stopped.
223///
224/// This function is defined in RISC-V SBI Specification chapter 11.10.
225#[inline]
226#[doc(alias = "sbi_pmu_counter_stop")]
227pub fn pmu_counter_stop<T>(counter_idx: CounterMask, stop_flags: T) -> SbiRet
228where
229 T: StopFlags,
230{
231 let (counter_idx_mask, counter_idx_base) = counter_idx.into_inner();
232 sbi_call_3(
233 EID_PMU,
234 COUNTER_STOP,
235 counter_idx_base,
236 counter_idx_mask,
237 stop_flags.raw(),
238 )
239}
240
241/// Provide the current value of a firmware counter.
242///
243/// On RV32 systems, the `SbiRet.value` will only contain the lower 32 bits from the current
244/// value of the firmware counter.
245///
246/// # Parameters
247///
248/// This function should be only used to read a firmware counter. It will return an error
249/// when a user provides a hardware counter in `counter_idx` parameter.
250///
251/// # Return value
252///
253/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
254///
255/// | Return code | Description
256/// |:--------------------------|:----------------------------------------------
257/// | `SbiRet::success()` | firmware counter read successfully.
258/// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
259///
260/// This function is defined in RISC-V SBI Specification chapter 11.11.
261#[inline]
262#[doc(alias = "sbi_pmu_counter_fw_read")]
263pub fn pmu_counter_fw_read(counter_idx: usize) -> SbiRet {
264 sbi_call_1(EID_PMU, COUNTER_FW_READ, counter_idx)
265}
266
267/// Provide the upper 32 bits from the value of a firmware counter.
268///
269/// This function always returns zero in `SbiRet.value` for RV64 (or higher) systems.
270///
271/// # Return value
272///
273/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
274///
275/// | Return code | Description
276/// |:--------------------------|:----------------------------------------------
277/// | `SbiRet::success()` | firmware counter read successfully.
278/// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
279///
280/// This function is defined in RISC-V SBI Specification chapter 11.12.
281#[inline]
282#[doc(alias = "sbi_pmu_counter_fw_read_hi")]
283pub fn pmu_counter_fw_read_hi(counter_idx: usize) -> SbiRet {
284 sbi_call_1(EID_PMU, COUNTER_FW_READ_HI, counter_idx)
285}
286
287/// Set and enable the PMU snapshot shared memory on the calling hart.
288///
289/// This function should be invoked only once per hart at boot time. Once configured, the SBI
290/// implementation has read/write access to the shared memory when `sbi_pmu_counter_stop` is
291/// invoked with the `TAKE_SNAPSHOT` flag set.
292///
293/// # Parameters
294///
295/// If `shmem` address parameter are not all-ones bitwise then
296/// `shmem` specifies the shared memory physical base address.
297/// The `shmem` physical address MUST be 4096 bytes (i.e. page) aligned
298/// and the size of the snapshot shared memory must be 4096 bytes.
299///
300/// The `flags` parameter is reserved for future use and must be zero.
301///
302/// # Return value
303///
304/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
305///
306/// | Return code | Description
307/// |:----------------------------|:----------------------------------------------
308/// | `SbiRet::success()` | Shared memory was set or cleared successfully.
309/// | `SbiRet::not_supported()` | The SBI PMU snapshot functionality is not available in the SBI implementation.
310/// | `SbiRet::invalid_param()` | The flags parameter is not zero or the `shmem` parameter is not 4096 bytes aligned.
311/// | `SbiRet::invalid_address()` | The shared memory pointed to by the `shmem` parameter is not writable or does not satisfy other requirements of RISC-V SBI Specification chapter 3.2.
312/// | `SbiRet::failed()` | The request failed for unspecified or unknown other reasons.
313///
314/// This function is defined in RISC-V SBI Specification chapter 11.13.
315#[inline]
316#[doc(alias = "sbi_pmu_snapshot_set_shmem")]
317pub fn pmu_snapshot_set_shmem(shmem: SharedPtr<[u8; SIZE]>, flags: usize) -> SbiRet {
318 sbi_call_3(
319 EID_PMU,
320 SNAPSHOT_SET_SHMEM,
321 shmem.phys_addr_lo(),
322 shmem.phys_addr_hi(),
323 flags,
324 )
325}
326
327/// Flags to configure performance counter.
328pub trait ConfigFlags {
329 /// Get a raw value to pass to SBI environment.
330 fn raw(&self) -> usize;
331}
332
333#[cfg(feature = "integer-impls")]
334impl ConfigFlags for usize {
335 #[inline]
336 fn raw(&self) -> usize {
337 *self
338 }
339}
340
341/// Flags to start performance counter.
342pub trait StartFlags {
343 /// Get a raw value to pass to SBI environment.
344 fn raw(&self) -> usize;
345}
346
347#[cfg(feature = "integer-impls")]
348impl StartFlags for usize {
349 #[inline]
350 fn raw(&self) -> usize {
351 *self
352 }
353}
354
355/// Flags to stop performance counter.
356pub trait StopFlags {
357 /// Get a raw value to pass to SBI environment.
358 fn raw(&self) -> usize;
359}
360
361#[cfg(feature = "integer-impls")]
362impl StopFlags for usize {
363 #[inline]
364 fn raw(&self) -> usize {
365 *self
366 }
367}