lib.rs 24 KB

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