//! Chapter 11. Performance Monitoring Unit Extension (EID #0x504D55 "PMU") use crate::binary::{sbi_call_0, sbi_call_1, sbi_call_3, SbiRet}; use sbi_spec::pmu::{ COUNTER_CONFIG_MATCHING, COUNTER_FW_READ, COUNTER_FW_READ_HI, COUNTER_GET_INFO, COUNTER_START, COUNTER_STOP, EID_PMU, NUM_COUNTERS, }; /// Returns the number of counters, both hardware and firmware. /// /// This call would always succeed without returning any error. /// /// This function is defined in RISC-V SBI Specification chapter 11.5. #[inline] pub fn pmu_num_counters() -> usize { sbi_call_0(EID_PMU, NUM_COUNTERS).value } /// Get details about the specified counter. /// /// The value returned includes details such as underlying CSR number, width of the counter, /// type of counter hardware/firmware, etc. /// /// The `counter_info` returned by this SBI call is encoded as follows: /// /// ```text /// counter_info[11:0] = CSR; // (12bit CSR number) /// counter_info[17:12] = Width; // (One less than number of bits in CSR) /// counter_info[XLEN-2:18] = Reserved; // Reserved for future use /// counter_info[XLEN-1] = Type; // (0 = hardware and 1 = firmware) /// ``` /// If `counter_info.type` == `1` then `counter_info.csr` and `counter_info.width` should be ignored. /// /// This function is defined in RISC-V SBI Specification chapter 11.6. /// /// # Return value /// /// Returns the `counter_info` described above in `SbiRet.value`. /// /// The possible return error codes returned in `SbiRet.error` are shown in the table below: /// /// | Return code | Description /// |:--------------------------|:---------------------------------------------- /// | `SbiRet::success()` | `counter_info` read successfully. /// | `SbiRet::invalid_param()` | `counter_idx` points to an invalid counter. /// /// This function is defined in RISC-V SBI Specification chapter 11.6. #[inline] pub fn pmu_counter_get_info(counter_idx: usize) -> SbiRet { sbi_call_1(EID_PMU, COUNTER_GET_INFO, counter_idx) } /// Find and configure a counter from a set of counters. /// /// The counters to be found and configured should not be started (or enabled) /// and should be able to monitor the specified event. /// /// # Parameters /// /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters, /// whereas the `event_idx` represent the event to be monitored /// and `event_data` represents any additional event configuration. /// /// The `config_flags` parameter represent additional counter configuration and filter flags. /// The bit definitions of the `config_flags` parameter are shown in the table below: /// /// | Flag Name | Bits | Description /// |:-----------------------------|:-----------|:------------ /// | SBI_PMU_CFG_FLAG_SKIP_MATCH | 0:0 | Skip the counter matching /// | SBI_PMU_CFG_FLAG_CLEAR_VALUE | 1:1 | Clear (or zero) the counter value in counter configuration /// | SBI_PMU_CFG_FLAG_AUTO_START | 2:2 | Start the counter after configuring a matching counter /// | SBI_PMU_CFG_FLAG_SET_VUINH | 3:3 | Event counting inhibited in VU-mode /// | SBI_PMU_CFG_FLAG_SET_VSINH | 4:4 | Event counting inhibited in VS-mode /// | SBI_PMU_CFG_FLAG_SET_UINH | 5:5 | Event counting inhibited in U-mode /// | SBI_PMU_CFG_FLAG_SET_SINH | 6:6 | Event counting inhibited in S-mode /// | SBI_PMU_CFG_FLAG_SET_MINH | 7:7 | Event counting inhibited in M-mode /// | _RESERVED_ | 8:(XLEN-1) | _All non-zero values are reserved for future use._ /// /// *NOTE:* When *SBI_PMU_CFG_FLAG_SKIP_MATCH* is set in `config_flags`, the /// SBI implementation will unconditionally select the first counter from the /// set of counters specified by the `counter_idx_base` and `counter_idx_mask`. /// /// *NOTE:* The *SBI_PMU_CFG_FLAG_AUTO_START* flag in `config_flags` has no /// impact on the counter value. /// /// *NOTE:* The `config_flags[3:7]` bits are event filtering hints so these /// can be ignored or overridden by the SBI implementation for security concerns /// or due to lack of event filtering support in the underlying RISC-V platform. /// /// # Return value /// /// Returns the `counter_idx` in `sbiret.value` upon success. /// /// In case of failure, the possible error codes returned in `sbiret.error` are shown in the table below: /// /// | Return code | Description /// |:--------------------------|:---------------------------------------------- /// | `SbiRet::success()` | counter found and configured successfully. /// | `SbiRet::invalid_param()` | set of counters has an invalid counter. /// | `SbiRet::not_supported()` | none of the counters can monitor specified event. /// /// This function is defined in RISC-V SBI Specification chapter 11.7. #[inline] pub fn pmu_counter_config_matching( counter_idx_base: usize, counter_idx_mask: usize, config_flags: T, event_idx: usize, event_data: u64, ) -> SbiRet where T: ConfigFlags, { match () { #[cfg(target_pointer_width = "32")] () => crate::binary::sbi_call_6( EID_PMU, COUNTER_CONFIG_MATCHING, counter_idx_base, counter_idx_mask, config_flags.raw(), event_idx, event_data as _, (event_data >> 32) as _, ), #[cfg(target_pointer_width = "64")] () => crate::binary::sbi_call_5( EID_PMU, COUNTER_CONFIG_MATCHING, counter_idx_base, counter_idx_mask, config_flags.raw(), event_idx, event_data as _, ), } } /// Start or enable a set of counters on the calling hart with the specified initial value. /// /// # Parameters /// /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters. /// whereas the `initial_value` parameter specifies the initial value of the counter. /// /// The bit definitions of the `start_flags` parameter are shown in the table below: /// /// | Flag Name | Bits | Description /// |:-----------------------------|:-----------|:------------ /// | SBI_PMU_START_SET_INIT_VALUE | 0:0 | Set the value of counters based on the `initial_value` parameter. /// | _RESERVED_ | 1:(XLEN-1) | _All non-zero values are reserved for future use._ /// /// *NOTE*: When `SBI_PMU_START_SET_INIT_VALUE` is not set in `start_flags`, the counter value will /// not be modified and event counting will start from current counter value. /// /// # Return value /// /// The possible return error codes returned in `SbiRet.error` are shown in the table below: /// /// | Return code | Description /// |:----------------------------|:---------------------------------------------- /// | `SbiRet::success()` | counter started successfully. /// | `SbiRet::invalid_param()` | some of the counters specified in parameters are invalid. /// | `SbiRet::already_started()` | some of the counters specified in parameters are already started. /// /// This function is defined in RISC-V SBI Specification chapter 11.8. #[inline] pub fn pmu_counter_start( counter_idx_base: usize, counter_idx_mask: usize, start_flags: T, initial_value: u64, ) -> SbiRet where T: StartFlags, { match () { #[cfg(target_pointer_width = "32")] () => crate::binary::sbi_call_5( EID_PMU, COUNTER_START, counter_idx_base, counter_idx_mask, start_flags.raw(), initial_value as _, (initial_value >> 32) as _, ), #[cfg(target_pointer_width = "64")] () => crate::binary::sbi_call_4( EID_PMU, COUNTER_START, counter_idx_base, counter_idx_mask, start_flags.raw(), initial_value as _, ), } } /// Stop or disable a set of counters on the calling hart. /// /// # Parameters /// /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters. /// The bit definitions of the `stop_flags` parameter are shown in the table below: /// /// | Flag Name | Bits | Description /// |:------------------------|:-----------|:------------ /// | SBI_PMU_STOP_FLAG_RESET | 0:0 | Reset the counter to event mapping. /// | _RESERVED_ | 1:(XLEN-1) | *All non-zero values are reserved for future use.* /// /// # Return value /// /// The possible return error codes returned in `SbiRet.error` are shown in the table below: /// /// | Return code | Description /// |:----------------------------|:---------------------------------------------- /// | `SbiRet::success()` | counter stopped successfully. /// | `SbiRet::invalid_param()` | some of the counters specified in parameters are invalid. /// | `SbiRet::already_stopped()` | some of the counters specified in parameters are already stopped. /// /// This function is defined in RISC-V SBI Specification chapter 11.9. #[inline] pub fn pmu_counter_stop( counter_idx_base: usize, counter_idx_mask: usize, stop_flags: T, ) -> SbiRet where T: StopFlags, { sbi_call_3( EID_PMU, COUNTER_STOP, counter_idx_base, counter_idx_mask, stop_flags.raw(), ) } /// Provide the current value of a firmware counter. /// /// On RV32 systems, the `SbiRet.value` will only contain the lower 32 bits of the current /// firmware counter value. /// /// # Parameters /// /// This function should be only used to read a firmware counter. It will return an error /// when user provides a hardware counter in `counter_idx` parameter. /// /// # Return value /// /// The possible return error codes returned in `SbiRet.error` are shown in the table below: /// /// | Return code | Description /// |:--------------------------|:---------------------------------------------- /// | `SbiRet::success()` | firmware counter read successfully. /// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter. /// /// This function is defined in RISC-V SBI Specification chapter 11.10. #[inline] pub fn pmu_counter_fw_read(counter_idx: usize) -> SbiRet { sbi_call_1(EID_PMU, COUNTER_FW_READ, counter_idx) } /// Provide the upper 32 bits of the current firmware counter value. /// /// This function always returns zero in `SbiRet.value` for RV64 (or higher) systems. /// /// # Return value /// /// The possible return error codes returned in `SbiRet.error` are shown in the table below: /// /// | Return code | Description /// |:--------------------------|:---------------------------------------------- /// | `SbiRet::success()` | firmware counter read successfully. /// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter. /// /// This function is defined in RISC-V SBI Specification chapter 11.11. #[inline] pub fn pmu_counter_fw_read_hi(counter_idx: usize) -> SbiRet { sbi_call_1(EID_PMU, COUNTER_FW_READ_HI, counter_idx) } /// Flags to configure performance counter. pub trait ConfigFlags { /// Get a raw value to pass to SBI environment. fn raw(&self) -> usize; } #[cfg(feature = "integer-impls")] impl ConfigFlags for usize { #[inline] fn raw(&self) -> usize { *self } } /// Flags to start performance counter. pub trait StartFlags { /// Get a raw value to pass to SBI environment. fn raw(&self) -> usize; } #[cfg(feature = "integer-impls")] impl StartFlags for usize { #[inline] fn raw(&self) -> usize { *self } } /// Flags to stop performance counter. pub trait StopFlags { /// Get a raw value to pass to SBI environment. fn raw(&self) -> usize; } #[cfg(feature = "integer-impls")] impl StopFlags for usize { #[inline] fn raw(&self) -> usize { *self } }