traits.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #[cfg(feature = "machine")]
  2. use riscv::register::{marchid, mimpid, mvendorid};
  3. use spec::binary::{HartMask, Physical, SbiRet, SharedPtr};
  4. /// RustSBI environment call handler.
  5. pub trait RustSBI {
  6. /// Handle supervisor environment call with given parameters and return the `SbiRet` result.
  7. fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet;
  8. }
  9. impl<T: RustSBI> RustSBI for &T {
  10. #[inline(always)]
  11. fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
  12. <T as RustSBI>::handle_ecall(self, extension, function, param)
  13. }
  14. }
  15. /// Machine environment information.
  16. ///
  17. /// This trait is useful to build an SBI environment when RustSBI is not run directly on RISC-V machine mode.
  18. pub trait EnvInfo {
  19. /// Vendor ID for the supervisor environment.
  20. ///
  21. /// Provides JEDEC manufacturer ID of the provider of the core.
  22. fn mvendorid(&self) -> usize;
  23. /// Architecture ID for the supervisor environment.
  24. ///
  25. /// Encodes the base micro-architecture of the hart.
  26. fn marchid(&self) -> usize;
  27. /// Implementation ID for the supervisor environment.
  28. ///
  29. /// Provides a unique encoding of the version of the processor implementation.
  30. fn mimpid(&self) -> usize;
  31. }
  32. impl<T: EnvInfo> EnvInfo for &T {
  33. #[inline(always)]
  34. fn mvendorid(&self) -> usize {
  35. <T as EnvInfo>::mvendorid(self)
  36. }
  37. #[inline(always)]
  38. fn marchid(&self) -> usize {
  39. <T as EnvInfo>::marchid(self)
  40. }
  41. #[inline(always)]
  42. fn mimpid(&self) -> usize {
  43. <T as EnvInfo>::mimpid(self)
  44. }
  45. }
  46. // Macro internal structures and functions.
  47. // DO NOT USE code here directly; use derive macro #[derive(RustSBI)] instead.
  48. #[cfg(feature = "machine")]
  49. #[doc(hidden)]
  50. #[inline(always)]
  51. pub fn _rustsbi_base_bare<U: _ExtensionProbe>(
  52. param: [usize; 6],
  53. function: usize,
  54. probe: U,
  55. ) -> SbiRet {
  56. let [param0] = [param[0]];
  57. let value = match function {
  58. spec::base::GET_SBI_SPEC_VERSION => (crate::SBI_SPEC_MAJOR << 24) | (crate::SBI_SPEC_MINOR),
  59. spec::base::GET_SBI_IMPL_ID => crate::IMPL_ID_RUSTSBI,
  60. spec::base::GET_SBI_IMPL_VERSION => crate::RUSTSBI_VERSION,
  61. spec::base::PROBE_EXTENSION => probe.probe_extension(param0),
  62. spec::base::GET_MVENDORID => mvendorid::read().map(|r| r.bits()).unwrap_or(0),
  63. spec::base::GET_MARCHID => marchid::read().map(|r| r.bits()).unwrap_or(0),
  64. spec::base::GET_MIMPID => mimpid::read().map(|r| r.bits()).unwrap_or(0),
  65. _ => return SbiRet::not_supported(),
  66. };
  67. SbiRet::success(value)
  68. }
  69. #[doc(hidden)]
  70. #[inline(always)]
  71. pub fn _rustsbi_base_env_info<T: EnvInfo, U: _ExtensionProbe>(
  72. param: [usize; 6],
  73. function: usize,
  74. env_info: &T,
  75. probe: U,
  76. ) -> SbiRet {
  77. let [param0] = [param[0]];
  78. let value = match function {
  79. spec::base::GET_SBI_SPEC_VERSION => (crate::SBI_SPEC_MAJOR << 24) | (crate::SBI_SPEC_MINOR),
  80. spec::base::GET_SBI_IMPL_ID => crate::IMPL_ID_RUSTSBI,
  81. spec::base::GET_SBI_IMPL_VERSION => crate::RUSTSBI_VERSION,
  82. spec::base::PROBE_EXTENSION => probe.probe_extension(param0),
  83. spec::base::GET_MVENDORID => env_info.mvendorid(),
  84. spec::base::GET_MARCHID => env_info.marchid(),
  85. spec::base::GET_MIMPID => env_info.mimpid(),
  86. _ => return SbiRet::not_supported(),
  87. };
  88. SbiRet::success(value)
  89. }
  90. // Probe not only standard SBI extensions, but also (reserving for) custom extensions.
  91. // For standard SBI extensions only, the macro would use `_StandardExtensionProbe`;
  92. // for implementation with custom SBI extension, a custom structure implementing this trait
  93. // would be used by macro.
  94. pub trait _ExtensionProbe {
  95. // Implementors are encouraged to add #[inline] hints on this function.
  96. fn probe_extension(&self, extension: usize) -> usize;
  97. }
  98. #[doc(hidden)]
  99. pub struct _StandardExtensionProbe {
  100. pub base: usize,
  101. pub fence: usize,
  102. pub timer: usize,
  103. pub ipi: usize,
  104. pub hsm: usize,
  105. pub reset: usize,
  106. pub pmu: usize,
  107. pub console: usize,
  108. pub susp: usize,
  109. pub cppc: usize,
  110. pub nacl: usize,
  111. pub sta: usize,
  112. // NOTE: don't forget to add to `fn probe_extension` in `impl _ExtensionProbe` as well
  113. }
  114. impl _ExtensionProbe for _StandardExtensionProbe {
  115. #[inline(always)]
  116. fn probe_extension(&self, extension: usize) -> usize {
  117. match extension {
  118. spec::base::EID_BASE => self.base,
  119. spec::time::EID_TIME => self.timer,
  120. spec::spi::EID_SPI => self.ipi,
  121. spec::rfnc::EID_RFNC => self.fence,
  122. spec::srst::EID_SRST => self.reset,
  123. spec::hsm::EID_HSM => self.hsm,
  124. spec::pmu::EID_PMU => self.pmu,
  125. spec::dbcn::EID_DBCN => self.console,
  126. spec::susp::EID_SUSP => self.susp,
  127. spec::cppc::EID_CPPC => self.cppc,
  128. spec::nacl::EID_NACL => self.nacl,
  129. spec::sta::EID_STA => self.sta,
  130. _ => spec::base::UNAVAILABLE_EXTENSION,
  131. }
  132. }
  133. }
  134. #[doc(hidden)]
  135. #[inline(always)]
  136. pub fn _rustsbi_fence<T: crate::Fence>(fence: &T, param: [usize; 6], function: usize) -> SbiRet {
  137. let [param0, param1, param2, param3, param4] =
  138. [param[0], param[1], param[2], param[3], param[4]];
  139. let hart_mask = HartMask::from_mask_base(param0, param1);
  140. match function {
  141. spec::rfnc::REMOTE_FENCE_I => fence.remote_fence_i(hart_mask),
  142. spec::rfnc::REMOTE_SFENCE_VMA => fence.remote_sfence_vma(hart_mask, param2, param3),
  143. spec::rfnc::REMOTE_SFENCE_VMA_ASID => {
  144. fence.remote_sfence_vma_asid(hart_mask, param2, param3, param4)
  145. }
  146. spec::rfnc::REMOTE_HFENCE_GVMA_VMID => {
  147. fence.remote_hfence_gvma_vmid(hart_mask, param2, param3, param4)
  148. }
  149. spec::rfnc::REMOTE_HFENCE_GVMA => fence.remote_hfence_gvma(hart_mask, param2, param3),
  150. spec::rfnc::REMOTE_HFENCE_VVMA_ASID => {
  151. fence.remote_hfence_vvma_asid(hart_mask, param2, param3, param4)
  152. }
  153. spec::rfnc::REMOTE_HFENCE_VVMA => fence.remote_hfence_vvma(hart_mask, param2, param3),
  154. _ => SbiRet::not_supported(),
  155. }
  156. }
  157. #[doc(hidden)]
  158. #[inline(always)]
  159. pub fn _rustsbi_timer<T: crate::Timer>(timer: &T, param: [usize; 6], function: usize) -> SbiRet {
  160. match () {
  161. #[cfg(target_pointer_width = "64")]
  162. () => {
  163. let [param0] = [param[0]];
  164. match function {
  165. spec::time::SET_TIMER => {
  166. timer.set_timer(param0 as _);
  167. SbiRet::success(0)
  168. }
  169. _ => SbiRet::not_supported(),
  170. }
  171. }
  172. #[cfg(target_pointer_width = "32")]
  173. () => {
  174. let [param0, param1] = [param[0], param[1]];
  175. match function {
  176. spec::time::SET_TIMER => {
  177. timer.set_timer(concat_u32(param1, param0));
  178. SbiRet::success(0)
  179. }
  180. _ => SbiRet::not_supported(),
  181. }
  182. }
  183. }
  184. }
  185. #[doc(hidden)]
  186. #[inline(always)]
  187. pub fn _rustsbi_ipi<T: crate::Ipi>(ipi: &T, param: [usize; 6], function: usize) -> SbiRet {
  188. let [param0, param1] = [param[0], param[1]];
  189. match function {
  190. spec::spi::SEND_IPI => ipi.send_ipi(HartMask::from_mask_base(param0, param1)),
  191. _ => SbiRet::not_supported(),
  192. }
  193. }
  194. #[doc(hidden)]
  195. #[inline(always)]
  196. pub fn _rustsbi_hsm<T: crate::Hsm>(hsm: &T, param: [usize; 6], function: usize) -> SbiRet {
  197. let [param0, param1, param2] = [param[0], param[1], param[2]];
  198. match function {
  199. spec::hsm::HART_START => hsm.hart_start(param0, param1, param2),
  200. spec::hsm::HART_STOP => hsm.hart_stop(),
  201. spec::hsm::HART_GET_STATUS => hsm.hart_get_status(param0),
  202. spec::hsm::HART_SUSPEND => {
  203. if let Ok(suspend_type) = u32::try_from(param0) {
  204. hsm.hart_suspend(suspend_type, param1, param2)
  205. } else {
  206. SbiRet::invalid_param()
  207. }
  208. }
  209. _ => SbiRet::not_supported(),
  210. }
  211. }
  212. #[doc(hidden)]
  213. #[inline(always)]
  214. pub fn _rustsbi_reset<T: crate::Reset>(reset: &T, param: [usize; 6], function: usize) -> SbiRet {
  215. let [param0, param1] = [param[0], param[1]];
  216. match function {
  217. spec::srst::SYSTEM_RESET => match (u32::try_from(param0), u32::try_from(param1)) {
  218. (Ok(reset_type), Ok(reset_reason)) => reset.system_reset(reset_type, reset_reason),
  219. (_, _) => SbiRet::invalid_param(),
  220. },
  221. _ => SbiRet::not_supported(),
  222. }
  223. }
  224. #[doc(hidden)]
  225. #[inline(always)]
  226. pub fn _rustsbi_pmu<T: crate::Pmu>(pmu: &T, param: [usize; 6], function: usize) -> SbiRet {
  227. match () {
  228. #[cfg(target_pointer_width = "64")]
  229. () => {
  230. let [param0, param1, param2, param3, param4] =
  231. [param[0], param[1], param[2], param[3], param[4]];
  232. match function {
  233. spec::pmu::NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
  234. spec::pmu::COUNTER_GET_INFO => pmu.counter_get_info(param0),
  235. spec::pmu::COUNTER_CONFIG_MATCHING => {
  236. pmu.counter_config_matching(param0, param1, param2, param3, param4 as _)
  237. }
  238. spec::pmu::COUNTER_START => pmu.counter_start(param0, param1, param2, param3 as _),
  239. spec::pmu::COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
  240. spec::pmu::COUNTER_FW_READ => pmu.counter_fw_read(param0),
  241. spec::pmu::COUNTER_FW_READ_HI => pmu.counter_fw_read_hi(param0),
  242. _ => SbiRet::not_supported(),
  243. }
  244. }
  245. #[cfg(target_pointer_width = "32")]
  246. () => {
  247. let [param0, param1, param2, param3, param4, param5] =
  248. [param[0], param[1], param[2], param[3], param[4], param[5]];
  249. match function {
  250. spec::pmu::NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
  251. spec::pmu::COUNTER_GET_INFO => pmu.counter_get_info(param0),
  252. spec::pmu::COUNTER_CONFIG_MATCHING => pmu.counter_config_matching(
  253. param0,
  254. param1,
  255. param2,
  256. param3,
  257. concat_u32(param5, param4),
  258. ),
  259. spec::pmu::COUNTER_START => {
  260. pmu.counter_start(param0, param1, param2, concat_u32(param4, param3))
  261. }
  262. spec::pmu::COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
  263. spec::pmu::COUNTER_FW_READ => pmu.counter_fw_read(param0),
  264. spec::pmu::COUNTER_FW_READ_HI => pmu.counter_fw_read_hi(param0),
  265. _ => SbiRet::not_supported(),
  266. }
  267. }
  268. }
  269. }
  270. #[doc(hidden)]
  271. #[inline(always)]
  272. pub fn _rustsbi_console<T: crate::Console>(
  273. console: &T,
  274. param: [usize; 6],
  275. function: usize,
  276. ) -> SbiRet {
  277. let [param0, param1, param2] = [param[0], param[1], param[2]];
  278. match function {
  279. spec::dbcn::CONSOLE_WRITE => {
  280. let bytes = Physical::new(param0, param1, param2);
  281. console.write(bytes)
  282. }
  283. spec::dbcn::CONSOLE_READ => {
  284. let bytes = Physical::new(param0, param1, param2);
  285. console.read(bytes)
  286. }
  287. spec::dbcn::CONSOLE_WRITE_BYTE => console.write_byte((param0 & 0xFF) as u8),
  288. _ => SbiRet::not_supported(),
  289. }
  290. }
  291. #[doc(hidden)]
  292. #[inline(always)]
  293. pub fn _rustsbi_susp<T: crate::Susp>(susp: &T, param: [usize; 6], function: usize) -> SbiRet {
  294. let [param0, param1, param2] = [param[0], param[1], param[2]];
  295. match function {
  296. spec::susp::SUSPEND => match u32::try_from(param0) {
  297. Ok(sleep_type) => susp.system_suspend(sleep_type, param1, param2),
  298. _ => SbiRet::invalid_param(),
  299. },
  300. _ => SbiRet::not_supported(),
  301. }
  302. }
  303. #[doc(hidden)]
  304. #[inline(always)]
  305. pub fn _rustsbi_cppc<T: crate::Cppc>(cppc: &T, param: [usize; 6], function: usize) -> SbiRet {
  306. match () {
  307. #[cfg(target_pointer_width = "64")]
  308. () => {
  309. let [param0, param1] = [param[0], param[1]];
  310. match function {
  311. spec::cppc::PROBE => match u32::try_from(param0) {
  312. Ok(reg_id) => cppc.probe(reg_id),
  313. _ => SbiRet::invalid_param(),
  314. },
  315. spec::cppc::READ => match u32::try_from(param0) {
  316. Ok(reg_id) => cppc.read(reg_id),
  317. _ => SbiRet::invalid_param(),
  318. },
  319. spec::cppc::READ_HI => match u32::try_from(param0) {
  320. Ok(reg_id) => cppc.read_hi(reg_id),
  321. _ => SbiRet::invalid_param(),
  322. },
  323. spec::cppc::WRITE => match u32::try_from(param0) {
  324. Ok(reg_id) => cppc.write(reg_id, param1 as _),
  325. _ => SbiRet::invalid_param(),
  326. },
  327. _ => SbiRet::not_supported(),
  328. }
  329. }
  330. #[cfg(target_pointer_width = "32")]
  331. () => {
  332. let [param0, param1, param2] = [param[0], param[1], param[2]];
  333. match function {
  334. spec::cppc::PROBE => cppc.probe(param0 as _),
  335. spec::cppc::READ => cppc.read(param0 as _),
  336. spec::cppc::READ_HI => cppc.read_hi(param0 as _),
  337. spec::cppc::WRITE => cppc.write(param0 as _, concat_u32(param2, param1)),
  338. _ => SbiRet::not_supported(),
  339. }
  340. }
  341. }
  342. }
  343. #[doc(hidden)]
  344. #[inline(always)]
  345. pub fn _rustsbi_nacl<T: crate::Nacl>(nacl: &T, param: [usize; 6], function: usize) -> SbiRet {
  346. let [param0, param1, param2] = [param[0], param[1], param[2]];
  347. match function {
  348. spec::nacl::PROBE_FEATURE => match u32::try_from(param0) {
  349. Ok(feature_id) => nacl.probe_feature(feature_id),
  350. _ => SbiRet::invalid_param(),
  351. },
  352. spec::nacl::SET_SHMEM => nacl.set_shmem(SharedPtr::new(param0, param1), param2),
  353. spec::nacl::SYNC_CSR => nacl.sync_csr(param0),
  354. spec::nacl::SYNC_HFENCE => nacl.sync_hfence(param0),
  355. spec::nacl::SYNC_SRET => nacl.sync_sret(),
  356. _ => SbiRet::not_supported(),
  357. }
  358. }
  359. #[doc(hidden)]
  360. #[inline(always)]
  361. pub fn _rustsbi_sta<T: crate::Sta>(sta: &T, param: [usize; 6], function: usize) -> SbiRet {
  362. let [param0, param1, param2] = [param[0], param[1], param[2]];
  363. match function {
  364. spec::sta::SET_SHMEM => sta.set_shmem(SharedPtr::new(param0, param1), param2),
  365. _ => SbiRet::not_supported(),
  366. }
  367. }
  368. #[cfg(target_pointer_width = "32")]
  369. #[inline]
  370. const fn concat_u32(h: usize, l: usize) -> u64 {
  371. ((h as u64) << 32) | (l as u64)
  372. }