How to define interrupt handlers without using external crates

I'm looking for and cannot find any information about how to define interrupt handlers in Rust. Rust Embedded book and most all other resources refer to external crates like cortex-m, etc. I'd like to learn how to do it manually. Maybe there's some way to do it in #[panic_handler] fashion?

I would appreciate any information on this or links to reading from the very basics. Thanks in advance!

This probably depends on the specific device.

The coretex-m crate uses either inline assembly or external library functions to do it, depending on feature flags:

Have you got docs on how you would do it in C? Perhaps that can be translated into Rust directly.

1 Like

No, I haven't, but will look into it. Thanks for the hint.

1 Like

On Cortex-M, you need to put pointers to your interrupt handlers at the right address in flash. This can be done in pure Rust, with the help of a linker script. Check out the code of cortex-m-rt, all the details are in there.

That's not quite right. What I described can be done without inline assembly or external C functions.

What you linked is a function that disables all interrupts, which requires a specific processor instruction, and thus either inline assembly or an external C function. It's useful, of course, but not required to set up the interrupt handlers. (Enabling/disabling specific interrupts is done through the NVIC, which is controlled using memory-mapped I/O. This can also be done in pure Rust.)

5 Likes

Hey,
may I ask at which level you'd like to implement interrupt handlers? As more low level you go - and you've asked this question in the embedded section the more the way you implement the interrupt handling depends on the architecture you are targeting and may require some assembly.

I've done this bare metal on a Raspberry Pi and the very core interrupt dispatching differs a lot on this ARM architecture between aarch32 and aarch64 mode. But having done the "ground work" I've also implemented a proc_macro that allows you to simple annotate your interrupt handling function with the interrupt they should handle - bat again this is really architecture specific.

Examples:

#[IrqHandler(ArmTimer)]
fn timer_handler() {

}

#[IrqHandler(Aux, Uart1)]
fn aux_uart1_handler() {
}

#[IrqHandler(GpioBank0)]
fn handle_gpio_bank0() {
}

The interrupt handling and dispatching is implemented within this crate: ruspiro-interrupt - However, to get this to work end-2-end you would also need to configure the exception vector table as part of the embedded boot sequence (assuming again bare metal development). This vector table setup is done in the ruspiro-boot crate in assembly as you nedd to ensure the respective curruptile registers are propperly saved before the interrupt call and restored after (as well as some system registers in cas of re-entrant interrupts). Also the signature of those exception table entries differ between aarch32/64 quite a bit and I'm sure they may do aswell between cortex-m, cortex-a etc.
:open_mouth:

So from my experience - and I'm still a rust green-horn - I'd say the exception table setup and initial interrupt stubs are hardly possible to do in rust, but the interrupt dispatching could easily be done within the beloved language :blush:

I'm targeting AArch64. Thanks for the tips, I'll definitely check your crates. In fact, I already bookmarked RusPiRo sources as they inspired me with some ideas of how to implement various things and in what direction to move :wink:

1 Like