pmu.rs 12 KB

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