Skip to content

Add default exception handlers and simplify default handler #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

robamu
Copy link
Contributor

@robamu robamu commented Mar 25, 2025

  • Add three new default assembly exception handlers for data abort, prefetch abort and undefined exception. These handlers implement the ARM exception return model.
  • The new ASM handlers will call the Rust _default_handler by default, but the Rust handler can be overriden with _undefined_handler, _prefetch_handler and _abort_handler
  • The default handler is now a simple empty permanent loop

// state save from compiled code
srsfd sp!, {und_mode}
"#,
save_context_ignore_fpu!(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth a comment explaining why FPU regs don't have to be saved here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. Maybe we should save them? I have not put too much thought in this. I searched the code for various exception handlers (did not find much), none of them really saved the FPU regs. But I guess if the exception return works, it would be correct to safe them?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handler could touch them, so I think they should be saved when you have the FPU feature on or are using the eabihf ABI.

//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn boot_core(cpu_id: u32) -> !;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right function name? I'm fine with harmonising A and R run-times here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, copy & paste error.. Harmonizing them should not be too difficult actually. If I try this, should I do it in a separate PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, a separate PR I think

@@ -30,7 +30,7 @@ pub fn main() -> ! {
}

/// This is our SVC exception handler
#[no_mangle]
#[unsafe(no_mangle)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this OK with our MRSV?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would CI not catch this? This is edition 2024 related I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-attributes.html

To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows:

So it was added in Rust 1.82, and works in any edition. Edition 2024 just makes the new style mandatory.

@jonathanpallant
Copy link
Contributor

This looks amazing. Just a couple of minor notes.

// state save from compiled code
srsfd sp!, {und_mode}
"#,
save_context_ignore_fpu!(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. Maybe we should save them? I have not put too much thought in this. I searched the code for various exception handlers (did not find much), none of them really saved the FPU regs. But I guess if the exception return works, it would be correct to safe them?

@@ -30,7 +30,7 @@ pub fn main() -> ! {
}

/// This is our SVC exception handler
#[no_mangle]
#[unsafe(no_mangle)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would CI not catch this? This is edition 2024 related I think.

//! * `_asm_fiq_handler` - a naked function to call when a Fast Interrupt
//! Request (FIQ) occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_fiq_handler` but you can override it.
//! * `_asm_undefined_handler` - a naked function to call when an Undefined
//! Exception occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_handler` but you can override it.
//! `_asm_defeault_undefined_handler` but you can override it.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops

//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn boot_core(cpu_id: u32) -> !;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, copy & paste error.. Harmonizing them should not be too difficult actually. If I try this, should I do it in a separate PR?

@robamu
Copy link
Contributor Author

robamu commented Mar 25, 2025

I now use the regular context saving/ restoration, tests still all run without issues.

@robamu
Copy link
Contributor Author

robamu commented Mar 25, 2025

By the way, I manually checked the faulting address argument against the binary disassembly when I wrote the tests, but I do not check them in the tests anymore. I think this would lead to extremely brittle tests, if a new version of the nightly compiler generates code with different layout.

@robamu robamu force-pushed the update-exception-handlers branch 3 times, most recently from 4f36a44 to 7d892c7 Compare March 25, 2025 09:38
@jonathanpallant
Copy link
Contributor

By the way, I manually checked the faulting address argument against the binary disassembly when I wrote the tests, but I do not check them in the tests anymore. I think this would lead to extremely brittle tests, if a new version of the nightly compiler generates code with different layout.

I think that's fine. Another PR could try and run objdump or nm or something and check that the printed address matches what is in the ELF file.

tst r4, {t_bit}
// If not in Thumb mode, branch to not_thumb
beq not_thumb
subs lr, lr, #2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a sneaky tab snuck in.

tst r4, {t_bit}
// If not in Thumb mode, branch to not_thumb
beq not_thumb
subs lr, lr, #2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subs lr, lr, #2
subs lr, lr, #2

.type _asm_default_prefetch_handler, %function
_asm_default_prefetch_handler:
// Subtract 4 from the stored LR, see p.1212 of the ARMv7-A architecture manual.
subs lr, lr, #4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subs lr, lr, #4
subs lr, lr, #4

.type _asm_default_abort_handler, %function
_asm_default_abort_handler:
// Subtract 8 from the stored LR, see p.1214 of the ARMv7-A architecture manual.
subs lr, lr, #8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subs lr, lr, #8
subs lr, lr, #8


#[no_mangle]
unsafe extern "C" fn _undefined_handler(_faulting_instruction: u32) {
static mut COUNTER: u32 = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-entering this function using a static mut is UB. It should probably be at AtomicU32 using fetch_add.


#[unsafe(no_mangle)]
unsafe extern "C" fn _prefetch_handler(_faulting_instruction: u32) {
static mut COUNTER: u32 = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-entering this function using a static mut is UB. It should probably be at AtomicU32 using fetch_add.


#[unsafe(no_mangle)]
unsafe extern "C" fn _abort_handler(_faulting_instruction: u32) {
static mut COUNTER: u32 = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-entering this function using a static mut is UB. It should probably be at AtomicU32 using fetch_add.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, replaced those with Atomics.

@jonathanpallant
Copy link
Contributor

I did a second pass on my desktop rather than my phone, and I observed some misalignment in the assembly code.

- Add three new default assembly exception handlers for data abort,
  prefetch abort and undefined exception. These handlers implement
  the ARM exception return model.
- The new ASM handlers will call the Rust _default_handler by default,
  but the Rust handler can be overriden with _undefined_handler,
  _prefetch_handler and _abort_handler
- The default handler is now a simple empty permanent loop
@robamu robamu force-pushed the update-exception-handlers branch from 04cd215 to ca2c26c Compare March 25, 2025 10:36
@jonathanpallant
Copy link
Contributor

One thing that would be good is tests for the mps3-an536, but we can't run those in CI, I'll just open a ticket.

@jonathanpallant jonathanpallant merged commit cea640e into rust-embedded:main Mar 25, 2025
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants