Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 42 additions & 55 deletions aarch32-rt-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use syn::{
/// ```rust
/// #[doc(hidden)]
/// #[export_name = "kmain"]
/// pub unsafe extern "C" fn __cortex_ar_rt_kmain() -> ! {
/// pub unsafe extern "C" fn __aarch32_rt_kmain() -> ! {
/// foo()
/// }
///
Expand Down Expand Up @@ -80,10 +80,18 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
.into();
}

let tramp_ident = Ident::new("__cortex_ar_rt_kmain", Span::call_site());
let ident = &f.sig.ident;

if let Err(error) = check_attr_whitelist(&f.attrs, Kind::Entry) {
// This is the name that other Rust code needs to use to call this function -
// we make it long an complicated because no-one is supposed to call this function.
// The `__aarch32_rt` prefix re-inforces this.
//
// However, this is not the symbol that the linker sees - we override that to be
// `kmain` because that's what the start-up assembly code is looking for. As you
// cannot call that symbol without using `extern "C" { }`, it should be sufficiently
// well hidden.
let tramp_ident = Ident::new("__aarch32_rt_kmain", Span::call_site());
let block = f.block;

if let Err(error) = check_attr_whitelist(&f.attrs, VectorKind::Entry) {
return error;
}

Expand All @@ -95,10 +103,8 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
#[doc(hidden)]
#[export_name = "kmain"]
pub unsafe extern "C" fn #tramp_ident() -> ! {
#ident()
#block
}

#f
)
.into()
}
Expand Down Expand Up @@ -144,7 +150,7 @@ impl std::fmt::Display for Exception {
/// ```rust
/// #[doc(hidden)]
/// #[export_name = "_undefined_handler"]
/// pub unsafe extern "C" fn __cortex_ar_rt_undefined_handler(addr: usize) -> ! {
/// pub unsafe extern "C" fn __aarch32_rt_undefined_handler(addr: usize) -> ! {
/// foo(addr)
/// }
///
Expand All @@ -162,7 +168,7 @@ impl std::fmt::Display for Exception {
/// * Irq (creates `_irq_handler`) - although people should prefer `#[irq]`.
#[proc_macro_attribute]
pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
handle_exception_interrupt(args, input, Kind::Exception)
handle_vector(args, input, VectorKind::Exception)
}

/// Creates an `unsafe` interrupt handler.
Expand All @@ -184,7 +190,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
/// ```rust
/// #[doc(hidden)]
/// #[export_name = "_irq_handler"]
/// pub unsafe extern "C" fn __cortex_ar_rt_irq_handler(addr: usize) -> ! {
/// pub unsafe extern "C" fn __aarch32_rt_irq_handler(addr: usize) -> ! {
/// foo(addr)
/// }
///
Expand All @@ -197,12 +203,12 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
/// probably won't consider interrupts to be a form of exception.
#[proc_macro_attribute]
pub fn irq(args: TokenStream, input: TokenStream) -> TokenStream {
handle_exception_interrupt(args, input, Kind::Interrupt)
handle_vector(args, input, VectorKind::Interrupt)
}

/// Note if we got `#[entry]`, `#[exception(...)]` or `#[irq]`
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum Kind {
enum VectorKind {
/// Corresponds to `#[entry]`
Entry,
/// Corresponds to `#[exception(...)]`
Expand All @@ -212,7 +218,7 @@ enum Kind {
}

/// A common routine for handling exception or interrupt functions
fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind) -> TokenStream {
fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);

if let Err(error) = check_attr_whitelist(&f.attrs, kind) {
Expand All @@ -225,10 +231,10 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
};

let exception = match kind {
Kind::Entry => {
panic!("Don't handle #[entry] with `handle_exception_interrupt`!");
VectorKind::Entry => {
panic!("Don't handle #[entry] with `handle_vector`!");
}
Kind::Exception => {
VectorKind::Exception => {
let mut args_iter = args.into_iter();
let Some(TokenTree::Ident(exception_name)) = args_iter.next() else {
return parse::Error::new(
Expand Down Expand Up @@ -292,28 +298,27 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
}
}
}
Kind::Interrupt => Exception::Irq,
VectorKind::Interrupt => Exception::Irq,
};

let ident = &f.sig.ident;
let block = f.block;
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());

let handler = match exception {
// extern "C" fn _undefined_handler(addr: usize) -> !;
// unsafe extern "C" fn _undefined_handler(addr: usize) -> usize;
Exception::Undefined => {
let tramp_ident = Ident::new("__cortex_ar_rt_undefined_handler", Span::call_site());
let tramp_ident = Ident::new("__aarch32_rt_undefined_handler", Span::call_site());
if returns_never {
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_undefined_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
#ident(addr)
#block
}

#f
)
} else {
quote!(
Expand All @@ -322,31 +327,25 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
#[doc(hidden)]
#[export_name = "_undefined_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
unsafe {
#ident(addr)
}
#block
}

#f
)
}
}
// extern "C" fn _prefetch_abort_handler(addr: usize) -> !;
// unsafe extern "C" fn _prefetch_abort_handler(addr: usize) -> usize;
Exception::PrefetchAbort => {
let tramp_ident =
Ident::new("__cortex_ar_rt_prefetch_abort_handler", Span::call_site());
let tramp_ident = Ident::new("__aarch32_rt_prefetch_abort_handler", Span::call_site());
if returns_never {
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_prefetch_abort_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
#ident(addr)
#block
}

#f
)
} else {
quote!(
Expand All @@ -355,30 +354,26 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
#[doc(hidden)]
#[export_name = "_prefetch_abort_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
unsafe {
#ident(addr)
}
#block
}

#f
)
}
}
// extern "C" fn _data_abort_handler(addr: usize) -> !;
// unsafe extern "C" fn _data_abort_handler(addr: usize) -> usize;
Exception::DataAbort => {
let tramp_ident = Ident::new("__cortex_ar_rt_data_abort_handler", Span::call_site());
let tramp_ident = Ident::new("__aarch32_rt_data_abort_handler", Span::call_site());
if returns_never {
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_data_abort_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
#ident(addr)
#block
}

#f
)
} else {
quote!(
Expand All @@ -387,43 +382,35 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
#[doc(hidden)]
#[export_name = "_data_abort_handler"]
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
unsafe {
#ident(addr)
}
#block
}

#f
)
}
}
// extern "C" fn _svc_handler(addr: usize);
Exception::SupervisorCall => {
let tramp_ident = Ident::new("__cortex_ar_rt_svc_handler", Span::call_site());
let tramp_ident = Ident::new("__aarch32_rt_svc_handler", Span::call_site());
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_svc_handler"]
pub unsafe extern "C" fn #tramp_ident(arg: u32) {
#ident(arg)
#block
}

#f
)
}
// extern "C" fn _irq_handler(addr: usize);
Exception::Irq => {
let tramp_ident = Ident::new("__cortex_ar_rt_irq_handler", Span::call_site());
let tramp_ident = Ident::new("__aarch32_rt_irq_handler", Span::call_site());
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_irq_handler"]
pub unsafe extern "C" fn #tramp_ident() {
#ident()
#block
}

#f
)
}
};
Expand Down Expand Up @@ -453,7 +440,7 @@ fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
}

/// Check whether any disallowed attributes have been applied to our entry/exception function.
fn check_attr_whitelist(attrs: &[Attribute], caller: Kind) -> Result<(), TokenStream> {
fn check_attr_whitelist(attrs: &[Attribute], caller: VectorKind) -> Result<(), TokenStream> {
let whitelist = &[
"doc",
"link_section",
Expand All @@ -475,11 +462,11 @@ fn check_attr_whitelist(attrs: &[Attribute], caller: Kind) -> Result<(), TokenSt
}

let err_str = match caller {
Kind::Entry => "this attribute is not allowed on an aarch32-rt entry point",
Kind::Exception => {
VectorKind::Entry => "this attribute is not allowed on an aarch32-rt entry point",
VectorKind::Exception => {
"this attribute is not allowed on an exception handler controlled by aarch32-rt"
}
Kind::Interrupt => {
VectorKind::Interrupt => {
"this attribute is not allowed on an interrupt handler controlled by aarch32-rt"
}
};
Expand Down
5 changes: 4 additions & 1 deletion aarch32-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@
//! ```
//!
//! You can also create a 'kmain' function by using the `#[entry]` attribute on
//! a normal Rust function.
//! a normal Rust function. The function will be renamed in such a way that the
//! start-up assembly code can find it, but normal Rust code cannot. Therefore
//! you can be assured that the function will only be called once (unless someone
//! resorts to `unsafe` Rust to import the `kmain` symbol as an `extern "C" fn`).
//!
//! ```rust
//! use aarch32_rt::entry;
Expand Down
4 changes: 3 additions & 1 deletion examples/mps3-an536/src/bin/gic-priority-ceiling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ fn dump_cpsr() {
println!("CPSR: {:?}", cpsr);
}

// This function doesn't need to be unsafe - I'm just checking you can apply the unsafe
// attribute to it
#[irq]
fn irq_handler() {
unsafe fn irq_handler() {
println!("> IRQ");
while let Some(int_id) = GicCpuInterface::get_and_acknowledge_interrupt(InterruptGroup::Group1)
{
Expand Down