Skip to main content

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}