diff options
author | 2023-06-16 11:46:56 +0200 | |
---|---|---|
committer | 2023-06-16 11:46:56 +0200 | |
commit | 54877baa685c63f085cc50adc251bb3af5bdfb2b (patch) | |
tree | 366a9bffc89330b23f69c439d372ed6d6bba0ca8 /cortex-m-rt/macros/src | |
parent | 36419ff47e31c4d2bfce23569e070f1bd123c678 (diff) | |
download | cortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.tar.gz cortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.tar.zst cortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.zip |
Removed the feature flag and moved the trampoline into the macro
Diffstat (limited to 'cortex-m-rt/macros/src')
-rw-r--r-- | cortex-m-rt/macros/src/lib.rs | 226 |
1 files changed, 158 insertions, 68 deletions
diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index e9be224..527dcc4 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -10,8 +10,11 @@ use quote::quote; use std::collections::HashSet; use std::iter; use syn::{ - parse, parse_macro_input, spanned::Spanned, AttrStyle, Attribute, FnArg, Ident, Item, ItemFn, - ItemStatic, ReturnType, Stmt, Type, Visibility, + parse::{self, Parse}, + parse_macro_input, + spanned::Spanned, + AttrStyle, Attribute, FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type, + Visibility, }; #[proc_macro_attribute] @@ -113,21 +116,73 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { #[derive(Debug, PartialEq)] enum Exception { DefaultHandler, - HardFault, + HardFault(HardFaultArgs), NonMaskableInt, Other, } +#[derive(Debug, PartialEq)] +struct HardFaultArgs { + trampoline: bool, +} + +impl Default for HardFaultArgs { + fn default() -> Self { + Self { trampoline: true } + } +} + +impl Parse for HardFaultArgs { + fn parse(input: parse::ParseStream) -> syn::Result<Self> { + let mut items = Vec::new(); + // Read a list of `ident = value,` + loop { + if input.is_empty() { + break; + } + + let name = input.parse::<Ident>()?; + input.parse::<syn::Token!(=)>()?; + let value = input.parse::<syn::Lit>()?; + + items.push((name, value)); + + if input.is_empty() { + break; + } + + input.parse::<syn::Token!(,)>()?; + } + + let mut args = Self::default(); + + for (name, value) in items { + match name.to_string().as_str() { + "trampoline" => match value { + syn::Lit::Bool(val) => { + args.trampoline = val.value(); + } + _ => { + return Err(syn::Error::new_spanned( + value, + "Not a valid value. `trampoline` takes a boolean literal", + )) + } + }, + _ => { + return Err(syn::Error::new_spanned(name, "Not a valid argument name")); + } + } + } + + Ok(args) + } +} + #[proc_macro_attribute] pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let mut f = parse_macro_input!(input as ItemFn); - if !args.is_empty() { - return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") - .to_compile_error() - .into(); - } - if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Exception) { return error; } @@ -137,14 +192,34 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let ident_s = ident.to_string(); let exn = match &*ident_s { - "DefaultHandler" => Exception::DefaultHandler, - "HardFault" => Exception::HardFault, - "NonMaskableInt" => Exception::NonMaskableInt, + "DefaultHandler" => { + if !args.is_empty() { + return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") + .to_compile_error() + .into(); + } + Exception::DefaultHandler + } + "HardFault" => Exception::HardFault(parse_macro_input!(args)), + "NonMaskableInt" => { + if !args.is_empty() { + return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") + .to_compile_error() + .into(); + } + Exception::NonMaskableInt + } // NOTE that at this point we don't check if the exception is available on the target (e.g. // MemoryManagement is not available on Cortex-M0) "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other, _ => { + if !args.is_empty() { + return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") + .to_compile_error() + .into(); + } + return parse::Error::new(ident.span(), "This is not a valid exception name") .to_compile_error() .into(); @@ -153,7 +228,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { if f.sig.unsafety.is_none() { match exn { - Exception::DefaultHandler | Exception::HardFault | Exception::NonMaskableInt => { + Exception::DefaultHandler | Exception::HardFault(_) | Exception::NonMaskableInt => { // These are unsafe to define. let name = if exn == Exception::DefaultHandler { "`DefaultHandler`".to_string() @@ -232,17 +307,24 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { #f ) } - Exception::HardFault if cfg!(feature = "hardfault-trampoline") => { + Exception::HardFault(args) => { let valid_signature = f.sig.constness.is_none() && f.vis == Visibility::Inherited && f.sig.abi.is_none() - && f.sig.inputs.len() == 1 - && match &f.sig.inputs[0] { - FnArg::Typed(arg) => match arg.ty.as_ref() { - Type::Reference(r) => r.lifetime.is_none() && r.mutability.is_none(), + && if args.trampoline { + match &f.sig.inputs[0] { + FnArg::Typed(arg) => match arg.ty.as_ref() { + Type::Reference(r) => { + r.lifetime.is_none() + && r.mutability.is_none() + && f.sig.inputs.len() == 1 + } + _ => false, + }, _ => false, - }, - _ => false, + } + } else { + f.sig.inputs.is_empty() } && f.sig.generics.params.is_empty() && f.sig.generics.where_clause.is_none() @@ -255,66 +337,74 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { if !valid_signature { return parse::Error::new( fspan, - "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`", + if args.trampoline { + "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`" + } else { + "`HardFault` handler must have signature `unsafe fn() -> !`" + }, ) .to_compile_error() .into(); } f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); - let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); - let ident = &f.sig.ident; - let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + if args.trampoline { + let tramp_ident = + Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); + let ident = &f.sig.ident; - quote!( - #(#cfgs)* - #(#attrs)* - #[doc(hidden)] - #[export_name = "HardFault"] - // Only emit link_section when building for embedded targets, - // because some hosted platforms (used to check the build) - // cannot handle the long link section names. - #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] - pub unsafe extern "C" fn #tramp_ident(frame: &::cortex_m_rt::ExceptionFrame) { - #ident(frame) - } + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); - #f - ) - } - Exception::HardFault => { - let valid_signature = f.sig.constness.is_none() - && f.vis == Visibility::Inherited - && f.sig.abi.is_none() - && f.sig.inputs.is_empty() - && f.sig.generics.params.is_empty() - && f.sig.generics.where_clause.is_none() - && f.sig.variadic.is_none() - && match f.sig.output { - ReturnType::Default => false, - ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)), - }; + quote!( + #(#cfgs)* + #(#attrs)* + #[doc(hidden)] + #[export_name = "HardFault"] + // Only emit link_section when building for embedded targets, + // because some hosted platforms (used to check the build) + // cannot handle the long link section names. + #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] + pub unsafe extern "C" fn #tramp_ident(frame: &::cortex_m_rt::ExceptionFrame) { + #ident(frame) + } - if !valid_signature { - return parse::Error::new( - fspan, - "`HardFault` handler must have signature `unsafe fn() -> !`", + #f + + // HardFault exceptions are bounced through this trampoline which grabs the stack pointer at + // the time of the exception and passes it to the user's HardFault handler in r0. + // Depending on the stack mode in EXC_RETURN, fetches stack from either MSP or PSP. + core::arch::global_asm!( + ".cfi_sections .debug_frame + .section .HardFaultTrampoline, \"ax\" + .global HardFaultTrampline + .type HardFaultTrampline,%function + .thumb_func + .cfi_startproc + HardFaultTrampoline:", + "mov r0, lr + movs r1, #4 + tst r0, r1 + bne 0f + mrs r0, MSP + b HardFault + 0: + mrs r0, PSP + b HardFault", + ".cfi_endproc + .size HardFaultTrampoline, . - HardFaultTrampoline", + ); + ) + } else { + quote!( + #[export_name = "HardFault"] + // Only emit link_section when building for embedded targets, + // because some hosted platforms (used to check the build) + // cannot handle the long link section names. + #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] + #f ) - .to_compile_error() - .into(); } - - f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); - - quote!( - #[export_name = "HardFault"] - // Only emit link_section when building for embedded targets, - // because some hosted platforms (used to check the build) - // cannot handle the long link section names. - #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] - #f - ) } Exception::NonMaskableInt | Exception::Other => { let valid_signature = f.sig.constness.is_none() |