traits.rs 14 KB

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