rustsbi_macros/
lib.rs

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