Skip to main content

rp235x_hal/
vector_table.rs

1//! Interrupt vector table utilities
2//!
3//! Provide functionality to switch to another vector table using the
4//! Vector Table Offset Register (VTOR) of the Cortex-33
5//! Also provides types and utilities for copying a vector table into RAM
6
7/// Entry for a Vector in the Interrupt Vector Table.
8///
9/// Each entry in the Vector table is a union with usize to allow it to be 0 initialized via const initializer
10///
11/// Implementation borrowed from https://docs.rs/cortex-m-rt/0.7.1/cortex_m_rt/index.html#__interrupts
12#[derive(Clone, Copy)]
13union Vector {
14    handler: extern "C" fn(),
15    reserved: usize,
16}
17
18/// Data type for a properly aligned interrupt vector table
19///
20/// The VTOR register can only point to a 128 byte offsets - see
21/// [Cortex-33 Devices Generic User Guide](https://developer.arm.com/documentation/100235/0004/the-cortex-m33-peripherals/system-control-block/vector-table-offset-register?lang=en) -
22/// so that is our required alignment.
23/// The vector table length depends on the number of interrupts the system supports.
24/// The first 16 words are defined in the ARM Cortex-M spec.
25/// The Cortex-M33 cores on RP235x have 52 interrupts, of which only 47 are wired to external interrupt
26/// signals - but the last 6 can be used for software interrupts so leave room for them
27#[repr(C, align(128))]
28pub struct VectorTable {
29    /// SP + Reset vector + 14 exceptions + 52 interrupts = 68 entries (272 bytes) in an rp235x core's VectorTable
30    table: [Vector; 68],
31}
32
33impl Default for VectorTable {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl VectorTable {
40    /// Create a new vector table. All entries will point to 0 - you must call init()
41    /// on this to copy the current vector table before setting it as active
42    pub const fn new() -> VectorTable {
43        VectorTable {
44            table: [Vector { reserved: 0 }; 68],
45        }
46    }
47
48    /// Initialise our vector table by copying the current table on top of it
49    #[allow(unknown_lints)]
50    #[allow(clippy::needless_pass_by_ref_mut)]
51    pub fn init(&mut self, ppb: &mut crate::pac::PPB) {
52        let mut vector_table = ppb.vtor().read().bits() as *const usize;
53        for entry in self.table.iter_mut() {
54            // Safety:
55            //
56            // This value must be valid because it's in the current vector table.
57            *entry = Vector {
58                reserved: unsafe { vector_table.read() },
59            };
60            // Safety:
61            //
62            // We are iterating through our copy of the vector table, which we
63            // know is the same size as the real vector table.
64            unsafe {
65                vector_table = vector_table.add(1);
66            }
67        }
68    }
69
70    /// Dynamically register a function as being an interrupt handler
71    pub fn register_handler(&mut self, interrupt_idx: usize, interrupt_fn: extern "C" fn()) {
72        self.table[16 + interrupt_idx].handler = interrupt_fn;
73    }
74
75    /// Set the stack pointer address in a VectorTable. This will be used on Reset
76    ///
77    /// # Safety
78    /// There is no checking whether this is a valid stack pointer address
79    pub unsafe fn set_sp(&mut self, stack_pointer_address: usize) {
80        self.table[0].reserved = stack_pointer_address;
81    }
82
83    /// Set the entry-point address in a VectorTable. This will be used on Reset
84    ///
85    /// # Safety
86    /// There is no checking whether this is a valid entry point
87    pub unsafe fn set_entry(&mut self, entry_address: usize) {
88        self.table[1].reserved = entry_address;
89    }
90
91    /// Switch the current core to use this Interrupt Vector Table
92    ///
93    /// # Safety
94    /// Until the vector table has valid entries, activating it will cause an unhandled hardfault!
95    /// You must call init() first.
96    #[allow(unknown_lints)]
97    #[allow(clippy::needless_pass_by_ref_mut)]
98    pub unsafe fn activate(&mut self, ppb: &mut crate::pac::PPB) {
99        ppb.vtor()
100            .write(|w| w.bits(&mut self.table as *mut _ as *mut u32 as u32));
101    }
102}