pmu.rs 12 KB

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