aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Dion Dokter <diondokter@gmail.com> 2023-06-16 11:46:56 +0200
committerGravatar Dion Dokter <diondokter@gmail.com> 2023-06-16 11:46:56 +0200
commit54877baa685c63f085cc50adc251bb3af5bdfb2b (patch)
tree366a9bffc89330b23f69c439d372ed6d6bba0ca8
parent36419ff47e31c4d2bfce23569e070f1bd123c678 (diff)
downloadcortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.tar.gz
cortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.tar.zst
cortex-m-54877baa685c63f085cc50adc251bb3af5bdfb2b.zip
Removed the feature flag and moved the trampoline into the macro
-rw-r--r--cortex-m-rt/CHANGELOG.md4
-rw-r--r--cortex-m-rt/Cargo.toml2
-rw-r--r--cortex-m-rt/macros/Cargo.toml3
-rw-r--r--cortex-m-rt/macros/src/lib.rs226
-rw-r--r--cortex-m-rt/src/lib.rs44
5 files changed, 159 insertions, 120 deletions
diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md
index 28ec16c..40dad58 100644
--- a/cortex-m-rt/CHANGELOG.md
+++ b/cortex-m-rt/CHANGELOG.md
@@ -9,9 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add `zero-init-ram` feature to initialize RAM with zeros on startup. This can be necessary on
safety-critical hardware to properly initialize memory integrity measures.
-- Add `hardfault-trampoline` feature that is enabled by default which enables
- the previously required hardfault trampoline. Now when this feature is not active, there will be
- no trampoline and the function you write is the exact function that is used as hardfault handler.
+- Add optional `exception` argument for `HardFault`. It has one option `trampoline` which is true by default. When set to false, no trampoline will be created and the function will be called as the exception handler directly.
## [v0.7.3]
diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml
index 03cd7f6..3305d34 100644
--- a/cortex-m-rt/Cargo.toml
+++ b/cortex-m-rt/Cargo.toml
@@ -42,12 +42,10 @@ name = "compiletest"
required-features = ["device"]
[features]
-default = ["hardfault-trampoline"]
device = []
set-sp = []
set-vtor = []
zero-init-ram = []
-hardfault-trampoline = ["cortex-m-rt-macros/hardfault-trampoline"]
[package.metadata.docs.rs]
features = ["device"]
diff --git a/cortex-m-rt/macros/Cargo.toml b/cortex-m-rt/macros/Cargo.toml
index 287ad9c..f548e19 100644
--- a/cortex-m-rt/macros/Cargo.toml
+++ b/cortex-m-rt/macros/Cargo.toml
@@ -21,6 +21,3 @@ proc-macro2 = "1.0"
[dependencies.syn]
features = ["extra-traits", "full"]
version = "2.0"
-
-[features]
-hardfault-trampoline = []
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()
diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs
index a39d32a..6456a5e 100644
--- a/cortex-m-rt/src/lib.rs
+++ b/cortex-m-rt/src/lib.rs
@@ -455,31 +455,6 @@ extern crate cortex_m_rt_macros as macros;
use core::arch::global_asm;
use core::fmt;
-// 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.
-#[cfg(all(cortex_m, feature = "hardfault-trampoline"))]
-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",
-);
-
/// Parse cfg attributes inside a global_asm call.
#[cfg(cortex_m)]
macro_rules! cfg_global_asm {
@@ -1058,19 +1033,8 @@ pub fn heap_start() -> *mut u32 {
#[no_mangle]
pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset;
-#[allow(unused_variables)]
#[doc(hidden)]
#[cfg_attr(cortex_m, link_section = ".HardFault.default")]
-#[cfg(feature = "hardfault-trampoline")]
-#[no_mangle]
-pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! {
- #[allow(clippy::empty_loop)]
- loop {}
-}
-
-#[doc(hidden)]
-#[cfg_attr(cortex_m, link_section = ".HardFault.default")]
-#[cfg(not(feature = "hardfault-trampoline"))]
#[no_mangle]
pub unsafe extern "C" fn HardFault_() -> ! {
#[allow(clippy::empty_loop)]
@@ -1125,9 +1089,6 @@ extern "C" {
fn NonMaskableInt();
- #[cfg(feature = "hardfault-trampoline")]
- fn HardFaultTrampoline();
- #[cfg(not(feature = "hardfault-trampoline"))]
fn HardFault();
#[cfg(not(armv6m))]
@@ -1167,11 +1128,6 @@ pub static __EXCEPTIONS: [Vector; 14] = [
handler: NonMaskableInt,
},
// Exception 3: Hard Fault Interrupt.
- #[cfg(feature = "hardfault-trampoline")]
- Vector {
- handler: HardFaultTrampoline,
- },
- #[cfg(not(feature = "hardfault-trampoline"))]
Vector { handler: HardFault },
// Exception 4: Memory Management Interrupt [not on Cortex-M0 variants].
#[cfg(not(armv6m))]