tartan_arch/arm/
interrupt.rs

1//! Exception and interrupt handling.
2
3use crate::{cp15_register_get, cp15_register_set};
4
5// Must be re-exported so that crates that use these macros will be able to resolve it
6#[doc(hidden)]
7pub use paste::paste;
8
9
10/// Define an exception vector table that forwards all exceptions to the designated
11/// handler.
12///
13/// The first argument is the name of the vector table, which will be exported as an
14/// unmangled symbol and exposed to Rust code as an immutable static of type
15/// [`VectorTable`].
16///
17/// The second argument is the name of the handler function, which should have
18/// signature `func(Kind)`.
19///
20/// # Example
21/// ```ignore
22/// # use tartan_arch::arm_exception_vector_table;
23/// # use tartan_arch::arm::ExceptionLevel;
24/// # use tartan_arch::arm::interrupt::{Kind, VectorBaseAddressRegister};
25/// #
26/// arm_exception_vector_table!(exception_table, handle_exception);
27///
28/// fn handle_exception(kind: Kind) {
29///     panic!("Exception {:?}", kind);
30/// }
31///
32/// fn main() {
33///     VectorBaseAddressRegister::set(unsafe { &exception_table });
34/// }
35/// ```
36#[macro_export]
37macro_rules! arm_exception_vector_table {
38    [$table:ident, $handler:path] => {
39        extern "C" {
40            #[no_mangle]
41            static $table: $crate::arm::interrupt::VectorTable;
42        }
43
44        core::arch::global_asm!(concat!("
45            .arm  // Exception handlers always use 32-bit (Arm-mode) instructions
46            .balign 0x10
47        ", stringify!($table), ":
48
49        . = ", stringify!($table), " + 0x00
50            // Reset
51            ldr pc, ", stringify!($table), "_reset
52
53        . = ", stringify!($table), " + 0x04
54            // Undefined instruction
55            ldr pc, ", stringify!($table), "_undefined
56
57        . = ", stringify!($table), " + 0x08
58            // Software interrupt
59            ldr pc, ", stringify!($table), "_software
60
61        . = ", stringify!($table), " + 0x0c
62            // Prefetch abort
63            ldr pc, ", stringify!($table), "_prefetch
64
65        . = ", stringify!($table), " + 0x10
66            // Data abort
67            ldr pc, ", stringify!($table), "_data
68
69        . = ", stringify!($table), " + 0x18
70            // Hardware interrupt (IRQ)
71            ldr pc, ", stringify!($table), "_interrupt
72
73        . = ", stringify!($table), " + 0x1c
74            // Fast hardware interrupt (FIQ)
75            ldr pc, ", stringify!($table), "_fast_interrupt
76        "));
77
78        $crate::arm::interrupt::paste! {
79            #[no_mangle]
80            fn [< $table _reset >]() {
81                $handler($crate::arm::interrupt::Kind::Reset);
82            }
83
84            #[no_mangle]
85            fn [< $table _undefined >]() {
86                $handler($crate::arm::interrupt::Kind::UndefinedInstruction);
87            }
88
89            #[no_mangle]
90            fn [< $table _software >]() {
91                $handler($crate::arm::interrupt::Kind::SoftwareInterrupt);
92            }
93
94            #[no_mangle]
95            fn [< $table _prefetch >]() {
96                $handler($crate::arm::interrupt::Kind::PrefetchAbort);
97            }
98
99            #[no_mangle]
100            fn [< $table _data >]() {
101                $handler($crate::arm::interrupt::Kind::DataAbort);
102            }
103
104            #[no_mangle]
105            fn [< $table _interrupt >]() {
106                $handler($crate::arm::interrupt::Kind::HardwareInterrupt);
107            }
108
109            #[no_mangle]
110            fn [< $table _fast_interrupt >]() {
111                $handler($crate::arm::interrupt::Kind::FastHardwareInterrupt);
112            }
113        }
114    };
115}
116
117
118/// The kind of exception being handled
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120#[allow(missing_docs)]
121pub enum Kind {
122    Reset,
123    UndefinedInstruction,
124    SoftwareInterrupt,
125    PrefetchAbort,
126    DataAbort,
127    HardwareInterrupt,
128    FastHardwareInterrupt,
129}
130
131
132/// Exception vector table that contains code to handle each exception [`Kind`].
133#[repr(align(0x10))]
134#[allow(dead_code)]
135pub struct VectorTable([u8; 0x20]);
136
137
138/// Contains the address of the [`VectorTable`] that the processor should use.
139pub enum VectorBaseAddressRegister {}
140
141impl VectorBaseAddressRegister {
142    /// Retrieve the current value of this register for the specified exception level.
143    ///
144    /// Only defined for exception levels 1–3. The register for a given exception level is
145    /// only accessible from that level or higher.
146    pub fn get() -> *const VectorTable {
147        let usize_value = cp15_register_get!(0, "c12", "c0", 0);
148        usize_value as *const VectorTable
149    }
150
151    /// Update the register for the specified exception level with the given value.
152    ///
153    /// Address must be aligned to 11 bits (2048).
154    pub fn set(value: *const VectorTable) {
155        unsafe {
156            cp15_register_set!(0, "c12", "c0", 0, value as usize);
157        }
158    }
159}