pmu.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. use sbi_spec::binary::SbiRet;
  2. /// Performance Monitoring Unit extension.
  3. ///
  4. /// The RISC-V hardware performance counters such as `mcycle`, `minstret`, and `mhpmcounterX` CSRs
  5. /// are accessible as read-only from supervisor-mode using `cycle`, `instret`, and `hpmcounterX` CSRs.
  6. /// The SBI performance monitoring unit (PMU) extension is an interface for supervisor-mode to configure
  7. /// and use the RISC-V hardware performance counters with assistance from the machine-mode (or hypervisor-mode).
  8. /// These hardware performance counters can only be started, stopped, or configured from machine-mode
  9. /// using `mcountinhibit` and `mhpmeventX` CSRs.
  10. /// Due to this, a machine-mode SBI implementation may choose to disallow SBI PMU extension
  11. /// if `mcountinhibit` CSR is not implemented by the RISC-V platform.
  12. ///
  13. /// A RISC-V platform generally supports monitoring of various hardware events using a limited number
  14. /// of hardware performance counters which are up to 64 bits wide.
  15. /// In addition, a SBI implementation can also provide firmware performance counters which can monitor firmware events
  16. /// such as number of misaligned load/store instructions, number of RFENCEs, number of IPIs, etc.
  17. /// The firmware counters are always 64 bits wide.
  18. ///
  19. /// The SBI PMU extension provides:
  20. ///
  21. /// 1. An interface for supervisor-mode software to discover and configure per-HART hardware/firmware counters
  22. /// 2. A typical perf compatible interface for hardware/firmware performance counters and events
  23. /// 3. Full access to microarchitecture’s raw event encodings
  24. ///
  25. /// To define SBI PMU extension calls, we first define important entities `counter_idx`, `event_idx`, and `event_data`.
  26. /// The `counter_idx` is a logical number assigned to each hardware/firmware counter.
  27. /// The `event_idx `represents a hardware (or firmware) event whereas
  28. /// the `event_data` is 64 bits wide and represents additional configuration (or parameters) for
  29. /// a hardware (or firmware) event.
  30. ///
  31. /// The event_idx is a 20 bits wide number encoded as follows:
  32. ///
  33. /// ```text
  34. /// event_idx[19:16] = type;
  35. /// event_idx[15:0] = code;
  36. /// ```
  37. pub trait Pmu {
  38. /// Returns the number of counters (both hardware and firmware).
  39. ///
  40. /// The value is returned in `SbiRet.value`; this call always returns `SbiRet::success()`.
  41. fn num_counters(&self) -> usize;
  42. /// Get details about the specified counter such as underlying CSR number, width of the counter,
  43. /// type of counter hardware/firmware, etc.
  44. ///
  45. /// The `counter_info` returned by this SBI call is encoded as follows:
  46. ///
  47. /// ```text
  48. /// counter_info[11:0] = CSR; // (12bit CSR number)
  49. /// counter_info[17:12] = Width; // (One less than number of bits in CSR)
  50. /// counter_info[XLEN-2:18] = Reserved; // Reserved for future use
  51. /// counter_info[XLEN-1] = Type; // (0 = hardware and 1 = firmware)
  52. /// ```
  53. /// If `counter_info.type` == `1` then `counter_info.csr` and `counter_info.width` should be ignored.
  54. ///
  55. /// # Return value
  56. ///
  57. /// Returns the `counter_info` described above in `SbiRet.value`.
  58. ///
  59. /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
  60. ///
  61. /// | Return code | Description
  62. /// |:----------------------------|:----------------------------------------------
  63. /// | `SbiRet::success()` | `counter_info` read successfully.
  64. /// | `SbiRet::invalid_param()` | `counter_idx` points to an invalid counter.
  65. fn counter_get_info(&self, counter_idx: usize) -> SbiRet;
  66. /// Find and configure a counter from a set of counters which is not started (or enabled)
  67. /// and can monitor the specified event.
  68. ///
  69. /// # Parameters
  70. ///
  71. /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters,
  72. /// whereas the `event_idx` represents the event to be monitored
  73. /// and `event_data` represents any additional event configuration.
  74. ///
  75. /// The `config_flags` parameter represents additional counter configuration and filter flags.
  76. /// The bit definitions of the `config_flags` parameter are shown in the table below:
  77. ///
  78. /// | Flag Name | Bits | Description
  79. /// |:-------------------------------|:-------------|:------------
  80. /// | `SBI_PMU_CFG_FLAG_SKIP_MATCH` | `0:0` | Skip the counter matching
  81. /// | `SBI_PMU_CFG_FLAG_CLEAR_VALUE` | `1:1` | Clear (or zero) the counter value in counter configuration
  82. /// | `SBI_PMU_CFG_FLAG_AUTO_START` | `2:2` | Start the counter after configuring a matching counter
  83. /// | `SBI_PMU_CFG_FLAG_SET_VUINH` | `3:3` | Event counting inhibited in VU-mode
  84. /// | `SBI_PMU_CFG_FLAG_SET_VSINH` | `4:4` | Event counting inhibited in VS-mode
  85. /// | `SBI_PMU_CFG_FLAG_SET_UINH` | `5:5` | Event counting inhibited in U-mode
  86. /// | `SBI_PMU_CFG_FLAG_SET_SINH` | `6:6` | Event counting inhibited in S-mode
  87. /// | `SBI_PMU_CFG_FLAG_SET_MINH` | `7:7` | Event counting inhibited in M-mode
  88. /// | _RESERVED_ | `8:(XLEN-1)` | _All non-zero values are reserved for future use._
  89. ///
  90. /// *NOTE:* When *SBI_PMU_CFG_FLAG_SKIP_MATCH* is set in `config_flags`, the
  91. /// SBI implementation will unconditionally select the first counter from the
  92. /// set of counters specified by the `counter_idx_base` and `counter_idx_mask`.
  93. ///
  94. /// *NOTE:* The *SBI_PMU_CFG_FLAG_AUTO_START* flag in `config_flags` has no
  95. /// impact on the counter value.
  96. ///
  97. /// *NOTE:* The `config_flags[3:7]` bits are event filtering hints so these
  98. /// can be ignored or overridden by the SBI implementation for security concerns
  99. /// or due to lack of event filtering support in the underlying RISC-V platform.
  100. ///
  101. /// # Return value
  102. ///
  103. /// Returns the `counter_idx` in `sbiret.value` upon success.
  104. ///
  105. /// In case of failure, the possible error codes returned in `sbiret.error` are shown in the table below:
  106. ///
  107. /// | Return code | Description
  108. /// |:--------------------------|:----------------------------------------------
  109. /// | `SbiRet::success()` | counter found and configured successfully.
  110. /// | `SbiRet::invalid_param()` | set of counters has at least one invalid counter.
  111. /// | `SbiRet::not_supported()` | none of the counters can monitor the specified event.
  112. fn counter_config_matching(
  113. &self,
  114. counter_idx_base: usize,
  115. counter_idx_mask: usize,
  116. config_flags: usize,
  117. event_idx: usize,
  118. event_data: u64,
  119. ) -> SbiRet;
  120. /// Start or enable a set of counters on the calling HART with the specified initial value.
  121. ///
  122. /// # Parameters
  123. ///
  124. /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters.
  125. /// whereas the `initial_value` parameter specifies the initial value of the counter.
  126. ///
  127. /// The bit definitions of the `start_flags` parameter are shown in the table below:
  128. ///
  129. /// | Flag Name | Bits | Description
  130. /// |:-------------------------------|:-------------|:------------
  131. /// | `SBI_PMU_START_SET_INIT_VALUE` | `0:0` | Set the value of counters based on the `initial_value` parameter.
  132. /// | _RESERVED_ | `1:(XLEN-1)` | _All non-zero values are reserved for future use._
  133. ///
  134. /// *NOTE*: When `SBI_PMU_START_SET_INIT_VALUE` is not set in `start_flags`, the counter value will
  135. /// not be modified and event counting will start from current counter value.
  136. ///
  137. /// # Return value
  138. ///
  139. /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
  140. ///
  141. /// | Return code | Description
  142. /// |:----------------------------|:----------------------------------------------
  143. /// | `SbiRet::success()` | counter started successfully.
  144. /// | `SbiRet::invalid_param()` | set of counters has at least one invalid counter.
  145. /// | `SbiRet::already_started()` | set of counters includes at least one counter which is already started.
  146. fn counter_start(
  147. &self,
  148. counter_idx_base: usize,
  149. counter_idx_mask: usize,
  150. start_flags: usize,
  151. initial_value: u64,
  152. ) -> SbiRet;
  153. /// Stop or disable a set of counters on the calling HART.
  154. ///
  155. /// # Parameters
  156. ///
  157. /// The `counter_idx_base` and `counter_idx_mask` parameters represent the set of counters.
  158. /// The bit definitions of the `stop_flags` parameter are shown in the table below:
  159. ///
  160. /// | Flag Name | Bits | Description
  161. /// |:--------------------------|:-------------|:------------
  162. /// | `SBI_PMU_STOP_FLAG_RESET` | `0:0` | Reset the counter to event mapping.
  163. /// | _RESERVED_ | `1:(XLEN-1)` | *All non-zero values are reserved for future use.*
  164. ///
  165. /// # Return value
  166. ///
  167. /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
  168. ///
  169. /// | Return code | Description
  170. /// |:----------------------------|:----------------------------------------------
  171. /// | `SbiRet::success()` | counter stopped successfully.
  172. /// | `SbiRet::invalid_param()` | set of counters has at least one invalid counter.
  173. /// | `SbiRet::already_stopped()` | set of counters includes at least one counter which is already stopped.
  174. fn counter_stop(
  175. &self,
  176. counter_idx_base: usize,
  177. counter_idx_mask: usize,
  178. stop_flags: usize,
  179. ) -> SbiRet;
  180. /// Provide the current value of a firmware counter in `SbiRet.value`.
  181. ///
  182. /// On RV32 systems, the `SbiRet.value` will only contain the lower 32 bits of the current
  183. /// firmware counter value.
  184. ///
  185. /// # Parameters
  186. ///
  187. /// This function should be only used to read a firmware counter. It will return an error
  188. /// when user provides a hardware counter in `counter_idx` parameter.
  189. ///
  190. /// # Return value
  191. ///
  192. /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
  193. ///
  194. /// | Return code | Description
  195. /// |:--------------------------|:----------------------------------------------
  196. /// | `SbiRet::success()` | firmware counter read successfully.
  197. /// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
  198. fn counter_fw_read(&self, counter_idx: usize) -> SbiRet;
  199. /// Provide the upper 32 bits of the current firmware counter value in `SbiRet.value`.
  200. ///
  201. /// This function always returns zero in `SbiRet.value` for RV64 (or higher) systems.
  202. ///
  203. /// # Return value
  204. ///
  205. /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
  206. ///
  207. /// | Return code | Description
  208. /// |:--------------------------|:----------------------------------------------
  209. /// | `SbiRet::success()` | firmware counter read successfully.
  210. /// | `SbiRet::invalid_param()` | `counter_idx` points to a hardware counter or an invalid counter.
  211. fn counter_fw_read_hi(&self, counter_idx: usize) -> SbiRet {
  212. match () {
  213. #[cfg(not(target_pointer_width = "32"))]
  214. () => {
  215. let _ = counter_idx;
  216. SbiRet::success(0)
  217. }
  218. #[cfg(target_pointer_width = "32")]
  219. () => {
  220. let _ = counter_idx;
  221. SbiRet::not_supported()
  222. }
  223. }
  224. }
  225. }
  226. impl<T: Pmu> Pmu for &T {
  227. #[inline]
  228. fn num_counters(&self) -> usize {
  229. T::num_counters(self)
  230. }
  231. #[inline]
  232. fn counter_get_info(&self, counter_idx: usize) -> SbiRet {
  233. T::counter_get_info(self, counter_idx)
  234. }
  235. #[inline]
  236. fn counter_config_matching(
  237. &self,
  238. counter_idx_base: usize,
  239. counter_idx_mask: usize,
  240. config_flags: usize,
  241. event_idx: usize,
  242. event_data: u64,
  243. ) -> SbiRet {
  244. T::counter_config_matching(
  245. self,
  246. counter_idx_base,
  247. counter_idx_mask,
  248. config_flags,
  249. event_idx,
  250. event_data,
  251. )
  252. }
  253. #[inline]
  254. fn counter_start(
  255. &self,
  256. counter_idx_base: usize,
  257. counter_idx_mask: usize,
  258. start_flags: usize,
  259. initial_value: u64,
  260. ) -> SbiRet {
  261. T::counter_start(
  262. self,
  263. counter_idx_base,
  264. counter_idx_mask,
  265. start_flags,
  266. initial_value,
  267. )
  268. }
  269. #[inline]
  270. fn counter_stop(
  271. &self,
  272. counter_idx_base: usize,
  273. counter_idx_mask: usize,
  274. stop_flags: usize,
  275. ) -> SbiRet {
  276. T::counter_stop(self, counter_idx_base, counter_idx_mask, stop_flags)
  277. }
  278. #[inline]
  279. fn counter_fw_read(&self, counter_idx: usize) -> SbiRet {
  280. T::counter_fw_read(self, counter_idx)
  281. }
  282. #[inline]
  283. fn counter_fw_read_hi(&self, counter_idx: usize) -> SbiRet {
  284. T::counter_fw_read_hi(self, counter_idx)
  285. }
  286. }