lib.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. //! Internal implementation details of RustSBI macros.
  2. //!
  3. //! Do not use this crate directly.
  4. use proc_macro::TokenStream;
  5. use quote::{quote, ToTokens};
  6. use syn::{parse_macro_input, Data, DeriveInput, Generics, Ident, Member};
  7. #[derive(Clone)]
  8. enum ParseMode {
  9. Static,
  10. Dynamic,
  11. }
  12. #[derive(Clone, Default)]
  13. struct StaticImpl {
  14. fence: Option<Member>,
  15. hsm: Option<Member>,
  16. ipi: Option<Member>,
  17. reset: Option<Member>,
  18. timer: Option<Member>,
  19. pmu: Option<Member>,
  20. console: Option<Member>,
  21. susp: Option<Member>,
  22. cppc: Option<Member>,
  23. nacl: Option<Member>,
  24. sta: Option<Member>,
  25. env_info: Option<Member>,
  26. }
  27. impl StaticImpl {
  28. fn replace_sbi_extension_ident(
  29. &mut self,
  30. extension_name: &str,
  31. member: Member,
  32. ) -> (bool, Option<Member>) {
  33. match extension_name {
  34. "rfnc" | "fence" => (true, self.fence.replace(member)),
  35. "hsm" => (true, self.hsm.replace(member)),
  36. "spi" | "ipi" => (true, self.ipi.replace(member)),
  37. "srst" | "reset" => (true, self.reset.replace(member)),
  38. "time" | "timer" => (true, self.timer.replace(member)),
  39. "pmu" => (true, self.pmu.replace(member)),
  40. "dbcn" | "console" => (true, self.console.replace(member)),
  41. "susp" => (true, self.susp.replace(member)),
  42. "cppc" => (true, self.cppc.replace(member)),
  43. "nacl" => (true, self.nacl.replace(member)),
  44. "sta" => (true, self.sta.replace(member)),
  45. "info" | "env_info" => (true, self.env_info.replace(member)),
  46. _ => (false, None),
  47. }
  48. }
  49. }
  50. #[derive(Clone, Default)]
  51. struct DynamicImpl {
  52. fence: Vec<Member>,
  53. hsm: Vec<Member>,
  54. ipi: Vec<Member>,
  55. reset: Vec<Member>,
  56. timer: Vec<Member>,
  57. pmu: Vec<Member>,
  58. console: Vec<Member>,
  59. susp: Vec<Member>,
  60. cppc: Vec<Member>,
  61. nacl: Vec<Member>,
  62. sta: Vec<Member>,
  63. env_info: Option<Member>,
  64. }
  65. impl DynamicImpl {
  66. fn push_sbi_extension_ident(&mut self, extension_name: &str, member: Member) -> bool {
  67. match extension_name {
  68. "rfnc" | "fence" => self.fence.push(member),
  69. "hsm" => self.hsm.push(member),
  70. "spi" | "ipi" => self.ipi.push(member),
  71. "srst" | "reset" => self.reset.push(member),
  72. "time" | "timer" => self.timer.push(member),
  73. "pmu" => self.pmu.push(member),
  74. "dbcn" | "console" => self.console.push(member),
  75. "susp" => self.susp.push(member),
  76. "cppc" => self.cppc.push(member),
  77. "nacl" => self.nacl.push(member),
  78. "sta" => self.sta.push(member),
  79. "info" | "env_info" => return self.env_info.replace(member).is_none(),
  80. _ => return false,
  81. }
  82. true
  83. }
  84. }
  85. /// This macro should be used in `rustsbi` crate as `rustsbi::RustSBI`.
  86. #[proc_macro_derive(RustSBI, attributes(rustsbi))]
  87. pub fn derive_rustsbi(input: TokenStream) -> TokenStream {
  88. let input = parse_macro_input!(input as DeriveInput);
  89. let Data::Struct(strukt) = &input.data else {
  90. panic!("#[derive(RustSBI)] must be used on structs");
  91. };
  92. let mut ans = TokenStream::new();
  93. let mut parse_mode = ParseMode::Static;
  94. for attr in &input.attrs {
  95. if !attr.path().is_ident("rustsbi") {
  96. continue;
  97. }
  98. let parsed = attr.parse_nested_meta(|meta| {
  99. if meta.path.is_ident("dynamic") {
  100. parse_mode = ParseMode::Dynamic;
  101. Ok(())
  102. } else {
  103. let path = meta.path.to_token_stream().to_string().replace(' ', "");
  104. Err(meta.error(format_args!("unknown RustSBI struct attribute `{}`", path)))
  105. }
  106. });
  107. if let Err(err) = parsed {
  108. ans.extend(TokenStream::from(err.to_compile_error()));
  109. }
  110. }
  111. let mut static_impl = StaticImpl::default();
  112. let mut dynamic_impl = DynamicImpl::default();
  113. for (i, field) in strukt.fields.iter().enumerate() {
  114. let member = match &field.ident {
  115. Some(ident) => Member::Named(ident.clone()),
  116. None => Member::Unnamed(i.into()),
  117. };
  118. let mut field_already_parsed = false;
  119. for attr in &field.attrs {
  120. if !attr.path().is_ident("rustsbi") {
  121. continue;
  122. }
  123. let parsed = attr.parse_nested_meta(|meta| {
  124. let mut current_meta_accepted = false;
  125. if meta.path.is_ident("skip") {
  126. // accept meta but do nothing, effectively skip this field in RustSBI
  127. current_meta_accepted = true;
  128. } else if let Some(meta_path_ident) = meta.path.get_ident() {
  129. let extension_name = &meta_path_ident.to_string();
  130. match parse_mode {
  131. ParseMode::Static => {
  132. let (replaced, origin) = static_impl
  133. .replace_sbi_extension_ident(extension_name, member.clone());
  134. if replaced {
  135. check_already_exists(field, extension_name, origin, &mut ans);
  136. current_meta_accepted = true;
  137. }
  138. }
  139. ParseMode::Dynamic => {
  140. let replaced = dynamic_impl
  141. .push_sbi_extension_ident(extension_name, member.clone());
  142. if replaced {
  143. current_meta_accepted = true;
  144. }
  145. }
  146. }
  147. }
  148. if current_meta_accepted {
  149. field_already_parsed = true;
  150. Ok(())
  151. } else {
  152. let path = meta.path.to_token_stream().to_string().replace(' ', "");
  153. Err(meta.error(format_args!("unknown RustSBI variant attribute `{}`", path)))
  154. }
  155. });
  156. if let Err(err) = parsed {
  157. ans.extend(TokenStream::from(err.to_compile_error()));
  158. }
  159. }
  160. // Already parsed by inner attribute.
  161. // Could be either skipped using #[rustsbi(skip)], or renamed using #[rustsbi(some_extension)]
  162. if field_already_parsed {
  163. continue;
  164. }
  165. if let Some(field_ident) = &field.ident {
  166. match parse_mode {
  167. ParseMode::Static => {
  168. let (_replaced, origin) = static_impl
  169. .replace_sbi_extension_ident(field_ident.to_string().as_str(), member);
  170. check_already_exists(field, &field_ident.to_string(), origin, &mut ans);
  171. }
  172. ParseMode::Dynamic => {
  173. let _replaced = dynamic_impl
  174. .push_sbi_extension_ident(field_ident.to_string().as_str(), member);
  175. }
  176. }
  177. }
  178. }
  179. match parse_mode {
  180. ParseMode::Static => ans.extend(impl_derive_rustsbi_static(
  181. &input.ident,
  182. static_impl,
  183. &input.generics,
  184. )),
  185. ParseMode::Dynamic => ans.extend(impl_derive_rustsbi_dynamic(
  186. &input.ident,
  187. dynamic_impl,
  188. &input.generics,
  189. )),
  190. };
  191. ans
  192. }
  193. fn check_already_exists(
  194. field: &syn::Field,
  195. extension_name: &str,
  196. origin: Option<Member>,
  197. ans: &mut TokenStream,
  198. ) {
  199. if let Some(_origin) = origin {
  200. // TODO: provide more detailed proc macro error hinting that previous
  201. // definition of this extension resides in `origin` once RFC 1566
  202. // (Procedural Macro Diagnostics) is stabilized.
  203. // Link: https://github.com/rust-lang/rust/issues/54140
  204. let error = syn::Error::new_spanned(
  205. field,
  206. format!(
  207. "more than one field defined SBI extension '{}'. \
  208. At most one fields should define the same SBI extension; consider using \
  209. #[rustsbi(skip)] to ignore fields that shouldn't be treated as an extension.",
  210. extension_name
  211. ),
  212. );
  213. ans.extend(TokenStream::from(error.to_compile_error()));
  214. }
  215. }
  216. fn impl_derive_rustsbi_static(name: &Ident, imp: StaticImpl, generics: &Generics) -> TokenStream {
  217. let base_probe: usize = 1;
  218. let fence_probe: usize = if imp.fence.is_some() { 1 } else { 0 };
  219. let hsm_probe: usize = if imp.hsm.is_some() { 1 } else { 0 };
  220. let ipi_probe: usize = if imp.ipi.is_some() { 1 } else { 0 };
  221. let reset_probe: usize = if imp.reset.is_some() { 1 } else { 0 };
  222. let timer_probe: usize = if imp.timer.is_some() { 1 } else { 0 };
  223. let pmu_probe: usize = if imp.pmu.is_some() { 1 } else { 0 };
  224. let console_probe: usize = if imp.console.is_some() { 1 } else { 0 };
  225. let susp_probe: usize = if imp.susp.is_some() { 1 } else { 0 };
  226. let cppc_probe: usize = if imp.cppc.is_some() { 1 } else { 0 };
  227. let nacl_probe: usize = if imp.nacl.is_some() { 1 } else { 0 };
  228. let sta_probe: usize = if imp.sta.is_some() { 1 } else { 0 };
  229. let probe = quote! {
  230. ::rustsbi::_StandardExtensionProbe {
  231. base: #base_probe,
  232. fence: #fence_probe,
  233. hsm: #hsm_probe,
  234. ipi: #ipi_probe,
  235. reset: #reset_probe,
  236. timer: #timer_probe,
  237. pmu: #pmu_probe,
  238. console: #console_probe,
  239. susp: #susp_probe,
  240. cppc: #cppc_probe,
  241. nacl: #nacl_probe,
  242. sta: #sta_probe,
  243. }
  244. };
  245. let mut match_arms = quote! {};
  246. let base_procedure = if let Some(env_info) = imp.env_info {
  247. quote! {
  248. ::rustsbi::spec::base::EID_BASE => ::rustsbi::_rustsbi_base_env_info(param, function, &self.#env_info, #probe),
  249. }
  250. } else {
  251. match () {
  252. #[cfg(not(feature = "machine"))]
  253. () => quote! {
  254. ::rustsbi::spec::base::EID_BASE => compile_error!(
  255. "can't derive RustSBI: #[cfg(feature = \"machine\")] is needed to derive RustSBI with no extra `EnvInfo` provided; \
  256. consider adding an `info` parameter to provide machine environment information implementing `rustsbi::EnvInfo`\
  257. if RustSBI is not run on machine mode."
  258. ),
  259. },
  260. #[cfg(feature = "machine")]
  261. () => quote! {
  262. ::rustsbi::spec::base::EID_BASE => ::rustsbi::_rustsbi_base_bare(param, function, #probe),
  263. },
  264. }
  265. };
  266. match_arms.extend(base_procedure);
  267. if let Some(fence) = &imp.fence {
  268. match_arms.extend(quote! {
  269. ::rustsbi::spec::rfnc::EID_RFNC => ::rustsbi::_rustsbi_fence(&self.#fence, param, function),
  270. })
  271. };
  272. if let Some(timer) = &imp.timer {
  273. match_arms.extend(quote! {
  274. ::rustsbi::spec::time::EID_TIME => ::rustsbi::_rustsbi_timer(&self.#timer, param, function),
  275. })
  276. };
  277. if let Some(ipi) = &imp.ipi {
  278. match_arms.extend(quote! {
  279. ::rustsbi::spec::spi::EID_SPI => ::rustsbi::_rustsbi_ipi(&self.#ipi, param, function),
  280. })
  281. }
  282. if let Some(hsm) = &imp.hsm {
  283. match_arms.extend(quote! {
  284. ::rustsbi::spec::hsm::EID_HSM => ::rustsbi::_rustsbi_hsm(&self.#hsm, param, function),
  285. })
  286. }
  287. if let Some(reset) = &imp.reset {
  288. match_arms.extend(quote! {
  289. ::rustsbi::spec::srst::EID_SRST => ::rustsbi::_rustsbi_reset(&self.#reset, param, function),
  290. })
  291. }
  292. if let Some(pmu) = &imp.pmu {
  293. match_arms.extend(quote! {
  294. ::rustsbi::spec::pmu::EID_PMU => ::rustsbi::_rustsbi_pmu(&self.#pmu, param, function),
  295. })
  296. }
  297. if let Some(console) = &imp.console {
  298. match_arms.extend(quote! {
  299. ::rustsbi::spec::dbcn::EID_DBCN => ::rustsbi::_rustsbi_console(&self.#console, param, function),
  300. })
  301. }
  302. if let Some(susp) = &imp.susp {
  303. match_arms.extend(quote! {
  304. ::rustsbi::spec::susp::EID_SUSP => ::rustsbi::_rustsbi_susp(&self.#susp, param, function),
  305. })
  306. }
  307. if let Some(cppc) = &imp.cppc {
  308. match_arms.extend(quote! {
  309. ::rustsbi::spec::cppc::EID_CPPC => ::rustsbi::_rustsbi_cppc(&self.#cppc, param, function),
  310. })
  311. }
  312. if let Some(nacl) = &imp.nacl {
  313. match_arms.extend(quote! {
  314. ::rustsbi::spec::nacl::EID_NACL => ::rustsbi::_rustsbi_nacl(&self.#nacl, param, function),
  315. })
  316. }
  317. if let Some(sta) = &imp.sta {
  318. match_arms.extend(quote! {
  319. ::rustsbi::spec::sta::EID_STA => ::rustsbi::_rustsbi_sta(&self.#sta, param, function),
  320. })
  321. }
  322. let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
  323. let gen = quote! {
  324. impl #impl_generics ::rustsbi::RustSBI for #name #ty_generics #where_clause {
  325. #[inline]
  326. fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> ::rustsbi::SbiRet {
  327. match extension {
  328. #match_arms
  329. _ => ::rustsbi::SbiRet::not_supported(),
  330. }
  331. }
  332. }
  333. };
  334. gen.into()
  335. }
  336. fn impl_derive_rustsbi_dynamic(name: &Ident, imp: DynamicImpl, generics: &Generics) -> TokenStream {
  337. let mut fence_contents = quote! {};
  338. let mut prober_ipi = quote! {};
  339. let mut prober_fence = quote! {};
  340. let mut prober_timer = quote! {};
  341. let mut prober_base = quote! {};
  342. let mut prober_reset = quote! {};
  343. let mut prober_hsm = quote! {};
  344. let mut prober_pmu = quote! {};
  345. let mut prober_console = quote! {};
  346. let mut prober_susp = quote! {};
  347. let mut prober_cppc = quote! {};
  348. let mut prober_nacl = quote! {};
  349. let mut prober_sta = quote! {};
  350. for fence in &imp.fence {
  351. fence_contents.extend(quote! {
  352. if ::rustsbi::_rustsbi_fence_probe(&self.#fence) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  353. return ::rustsbi::_rustsbi_fence(&self.#fence, param, function)
  354. }
  355. });
  356. prober_fence.extend(quote! {
  357. let value = ::rustsbi::_rustsbi_fence_probe(&self.0.#fence);
  358. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  359. return value
  360. }
  361. });
  362. }
  363. let mut timer_contents = quote! {};
  364. for timer in &imp.timer {
  365. timer_contents.extend(quote! {
  366. if ::rustsbi::_rustsbi_timer_probe(&self.#timer) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  367. return ::rustsbi::_rustsbi_timer(&self.#timer, param, function)
  368. }
  369. });
  370. prober_timer.extend(quote! {
  371. let value = ::rustsbi::_rustsbi_timer_probe(&self.0.#timer);
  372. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  373. return value
  374. }
  375. });
  376. }
  377. let mut ipi_contents = quote! {};
  378. for ipi in &imp.ipi {
  379. ipi_contents.extend(quote! {
  380. if ::rustsbi::_rustsbi_ipi_probe(&self.#ipi) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  381. return ::rustsbi::_rustsbi_ipi(&self.#ipi, param, function)
  382. }
  383. });
  384. prober_ipi.extend(quote! {
  385. let value = ::rustsbi::_rustsbi_ipi_probe(&self.0.#ipi);
  386. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  387. return value
  388. }
  389. });
  390. }
  391. let mut hsm_contents = quote! {};
  392. for hsm in &imp.hsm {
  393. hsm_contents.extend(quote! {
  394. if ::rustsbi::_rustsbi_hsm_probe(&self.#hsm) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  395. return ::rustsbi::_rustsbi_hsm(&self.#hsm, param, function)
  396. }
  397. });
  398. prober_hsm.extend(quote! {
  399. let value = ::rustsbi::_rustsbi_hsm_probe(&self.0.#hsm);
  400. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  401. return value
  402. }
  403. });
  404. }
  405. let mut reset_contents = quote! {};
  406. for reset in &imp.reset {
  407. reset_contents.extend(quote! {
  408. if ::rustsbi::_rustsbi_reset_probe(&self.#reset) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  409. return ::rustsbi::_rustsbi_reset(&self.#reset, param, function)
  410. }
  411. });
  412. prober_reset.extend(quote! {
  413. let value = ::rustsbi::_rustsbi_reset_probe(&self.0.#reset);
  414. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  415. return value
  416. }
  417. });
  418. }
  419. let mut pmu_contents = quote! {};
  420. for pmu in &imp.pmu {
  421. pmu_contents.extend(quote! {
  422. if ::rustsbi::_rustsbi_pmu_probe(&self.#pmu) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  423. return ::rustsbi::_rustsbi_pmu(&self.#pmu, param, function)
  424. }
  425. });
  426. prober_pmu.extend(quote! {
  427. let value = ::rustsbi::_rustsbi_pmu_probe(&self.0.#pmu);
  428. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  429. return value
  430. }
  431. });
  432. }
  433. let mut console_contents = quote! {};
  434. for console in &imp.console {
  435. console_contents.extend(quote! {
  436. if ::rustsbi::_rustsbi_console_probe(&self.#console) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  437. return ::rustsbi::_rustsbi_console(&self.#console, param, function)
  438. }
  439. });
  440. prober_console.extend(quote! {
  441. let value = ::rustsbi::_rustsbi_console_probe(&self.0.#console);
  442. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  443. return value
  444. }
  445. });
  446. }
  447. let mut susp_contents = quote! {};
  448. for susp in &imp.susp {
  449. susp_contents.extend(quote! {
  450. if ::rustsbi::_rustsbi_susp_probe(&self.#susp) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  451. return ::rustsbi::_rustsbi_susp(&self.#susp, param, function)
  452. }
  453. });
  454. prober_susp.extend(quote! {
  455. let value = ::rustsbi::_rustsbi_susp_probe(&self.0.#susp);
  456. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  457. return value
  458. }
  459. });
  460. }
  461. let mut cppc_contents = quote! {};
  462. for cppc in &imp.cppc {
  463. cppc_contents.extend(quote! {
  464. if ::rustsbi::_rustsbi_cppc_probe(&self.#cppc) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  465. return ::rustsbi::_rustsbi_cppc(&self.#cppc, param, function)
  466. }
  467. });
  468. prober_cppc.extend(quote! {
  469. let value = ::rustsbi::_rustsbi_cppc_probe(&self.0.#cppc);
  470. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  471. return value
  472. }
  473. });
  474. }
  475. let mut nacl_contents = quote! {};
  476. for nacl in &imp.nacl {
  477. nacl_contents.extend(quote! {
  478. if ::rustsbi::_rustsbi_nacl_probe(&self.#nacl) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  479. return ::rustsbi::_rustsbi_nacl(&self.#nacl, param, function)
  480. }
  481. });
  482. prober_nacl.extend(quote! {
  483. let value = ::rustsbi::_rustsbi_nacl_probe(&self.0.#nacl);
  484. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  485. return value
  486. }
  487. });
  488. }
  489. let mut sta_contents = quote! {};
  490. for sta in &imp.sta {
  491. sta_contents.extend(quote! {
  492. if ::rustsbi::_rustsbi_sta_probe(&self.#sta) != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  493. return ::rustsbi::_rustsbi_sta(&self.#sta, param, function)
  494. }
  495. });
  496. prober_sta.extend(quote! {
  497. let value = ::rustsbi::_rustsbi_sta_probe(&self.0.#sta);
  498. if value != ::rustsbi::spec::base::UNAVAILABLE_EXTENSION {
  499. return value
  500. }
  501. });
  502. }
  503. let define_prober = quote! {
  504. struct _Prober<'a>(&'a #name);
  505. impl<'a> ::rustsbi::_ExtensionProbe for _Prober<'a> {
  506. #[inline(always)]
  507. fn probe_extension(&self, extension: usize) -> usize {
  508. match extension {
  509. ::rustsbi::spec::base::EID_BASE => { #prober_base ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  510. ::rustsbi::spec::time::EID_TIME => { #prober_timer ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  511. ::rustsbi::spec::spi::EID_SPI => { #prober_ipi ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  512. ::rustsbi::spec::rfnc::EID_RFNC => { #prober_fence ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  513. ::rustsbi::spec::srst::EID_SRST => { #prober_reset ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  514. ::rustsbi::spec::hsm::EID_HSM => { #prober_hsm ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  515. ::rustsbi::spec::pmu::EID_PMU => { #prober_pmu ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  516. ::rustsbi::spec::dbcn::EID_DBCN => { #prober_console ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  517. ::rustsbi::spec::susp::EID_SUSP => { #prober_susp ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  518. ::rustsbi::spec::cppc::EID_CPPC => { #prober_cppc ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  519. ::rustsbi::spec::nacl::EID_NACL => { #prober_nacl ::rustsbi::spec::base::UNAVAILABLE_EXTENSION },
  520. ::rustsbi::spec::sta::EID_STA => { #prober_sta ::rustsbi::spec::base::UNAVAILABLE_EXTENSION}
  521. _ => ::rustsbi::spec::base::UNAVAILABLE_EXTENSION,
  522. }
  523. }
  524. }
  525. };
  526. let base_result = if let Some(env_info) = imp.env_info {
  527. quote! {
  528. ::rustsbi::_rustsbi_base_env_info(param, function, &self.#env_info, prober)
  529. }
  530. } else {
  531. match () {
  532. #[cfg(not(feature = "machine"))]
  533. () => quote! {
  534. compile_error!(
  535. "can't derive RustSBI: #[cfg(feature = \"machine\")] is needed to derive RustSBI with no extra `EnvInfo` provided; \
  536. consider adding an `info` parameter to provide machine environment information implementing `rustsbi::EnvInfo`\
  537. if RustSBI is not run on machine mode."
  538. )
  539. },
  540. #[cfg(feature = "machine")]
  541. () => quote! {
  542. ::rustsbi::_rustsbi_base_bare(param, function, prober)
  543. },
  544. }
  545. };
  546. let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
  547. let gen = quote! {
  548. impl #impl_generics ::rustsbi::RustSBI for #name #ty_generics #where_clause {
  549. #[inline]
  550. fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> ::rustsbi::SbiRet {
  551. match extension {
  552. ::rustsbi::spec::rfnc::EID_RFNC => { #fence_contents ::rustsbi::SbiRet::not_supported() },
  553. ::rustsbi::spec::time::EID_TIME => { #timer_contents ::rustsbi::SbiRet::not_supported() },
  554. ::rustsbi::spec::spi::EID_SPI => { #ipi_contents ::rustsbi::SbiRet::not_supported() },
  555. ::rustsbi::spec::hsm::EID_HSM => { #hsm_contents ::rustsbi::SbiRet::not_supported() },
  556. ::rustsbi::spec::srst::EID_SRST => { #reset_contents ::rustsbi::SbiRet::not_supported() },
  557. ::rustsbi::spec::pmu::EID_PMU => { #pmu_contents ::rustsbi::SbiRet::not_supported() },
  558. ::rustsbi::spec::dbcn::EID_DBCN => { #console_contents ::rustsbi::SbiRet::not_supported() },
  559. ::rustsbi::spec::susp::EID_SUSP => { #susp_contents ::rustsbi::SbiRet::not_supported() },
  560. ::rustsbi::spec::cppc::EID_CPPC => { #cppc_contents ::rustsbi::SbiRet::not_supported() },
  561. ::rustsbi::spec::nacl::EID_NACL => { #nacl_contents ::rustsbi::SbiRet::not_supported() },
  562. ::rustsbi::spec::sta::EID_STA => { #sta_contents ::rustsbi::SbiRet::not_supported() },
  563. ::rustsbi::spec::base::EID_BASE => {
  564. #define_prober
  565. let prober = _Prober(&self);
  566. #base_result
  567. }
  568. _ => ::rustsbi::SbiRet::not_supported(),
  569. }
  570. }
  571. }
  572. };
  573. gen.into()
  574. }