Skip to main content

aarch32_rt/
stacks.rs

1//! Code for examining linker allocated stacks
2
3/// Represents one of the AArch32 stacks
4#[derive(Debug, Copy, Clone)]
5pub enum Stack {
6    /// UND mode stack
7    Und,
8    /// SVC mode stack
9    Svc,
10    /// ABT mode stack, for data abort and prefetch abort
11    Abt,
12    /// HYP mode stack, for EL2
13    Hyp,
14    /// IRQ mode stack, for interrupts
15    Irq,
16    /// FIQ mode stack, for fast interrupts
17    Fiq,
18    /// SYS mode stack, for the main thread
19    Sys,
20}
21
22impl core::fmt::Display for Stack {
23    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
24        f.pad(match self {
25            Stack::Und => "UND",
26            Stack::Svc => "SVC",
27            Stack::Abt => "ABT",
28            Stack::Hyp => "HYP",
29            Stack::Irq => "IRQ",
30            Stack::Fiq => "FIQ",
31            Stack::Sys => "SYS",
32        })
33    }
34}
35
36impl Stack {
37    /// Create an iterator over all the stacks
38    pub fn iter() -> impl Iterator<Item = Stack> {
39        StackIter::new()
40    }
41
42    /// Get the highest address of this stack, for the given core
43    pub fn top(&self, core: usize) -> Option<*const u32> {
44        if core > Self::num_cores() {
45            return None;
46        }
47        let top = self.stack_top();
48        let core = core as isize;
49        let per_core_size_words = self.per_core_size_words();
50        Some(unsafe { top.offset(-per_core_size_words * core) })
51    }
52
53    /// Get the lowest address of this stack, for the given core
54    pub fn bottom(&self, core: usize) -> Option<*const u32> {
55        self.top(core)
56            .map(|p| unsafe { p.offset(-self.per_core_size_words()) })
57    }
58
59    /// Get the range of this stack, for the given core
60    pub fn range(&self, core: usize) -> Option<core::ops::Range<*const u32>> {
61        if let (Some(bottom), Some(top)) = (self.bottom(core), self.top(core)) {
62            Some(bottom..top)
63        } else {
64            None
65        }
66    }
67
68    /// Get the inclusive range of this stack, for the given core
69    ///
70    /// This is the range you need to give to the PMSAv8 MPU code.
71    pub fn mpu_range(&self, core: usize) -> Option<core::ops::RangeInclusive<*const u8>> {
72        if let (Some(bottom), Some(top)) = (self.bottom(core), self.top(core)) {
73            let top = top as *const u8;
74            let bottom = bottom as *const u8;
75            let top_under = unsafe { top.offset(-1) };
76            Some(bottom..=top_under)
77        } else {
78            None
79        }
80    }
81
82    /// Get number of cores in this system
83    pub fn num_cores() -> usize {
84        unsafe extern "C" {
85            safe static _num_cores: u8;
86        }
87        core::ptr::addr_of!(_num_cores) as usize
88    }
89
90    /// Get the total size of this stack across all cores
91    pub fn per_core_size_words(&self) -> isize {
92        use core::ptr::addr_of;
93        unsafe extern "C" {
94            static _und_stack_size: u8;
95            static _svc_stack_size: u8;
96            static _abt_stack_size: u8;
97            static _hyp_stack_size: u8;
98            static _irq_stack_size: u8;
99            static _fiq_stack_size: u8;
100            static _sys_stack_size: u8;
101        }
102        let size_bytes = match self {
103            Stack::Und => addr_of!(_und_stack_size) as isize,
104            Stack::Svc => addr_of!(_svc_stack_size) as isize,
105            Stack::Abt => addr_of!(_abt_stack_size) as isize,
106            Stack::Hyp => addr_of!(_hyp_stack_size) as isize,
107            Stack::Irq => addr_of!(_irq_stack_size) as isize,
108            Stack::Fiq => addr_of!(_fiq_stack_size) as isize,
109            Stack::Sys => addr_of!(_sys_stack_size) as isize,
110        };
111        size_bytes / 4
112    }
113
114    /// Get the top address for this stack
115    fn stack_top(&self) -> *const u32 {
116        use core::ptr::addr_of;
117        unsafe extern "C" {
118            static _und_stack_high_end: u32;
119            static _svc_stack_high_end: u32;
120            static _abt_stack_high_end: u32;
121            static _hyp_stack_high_end: u32;
122            static _irq_stack_high_end: u32;
123            static _fiq_stack_high_end: u32;
124            static _sys_stack_high_end: u32;
125        }
126        match self {
127            Stack::Und => addr_of!(_und_stack_high_end),
128            Stack::Svc => addr_of!(_svc_stack_high_end),
129            Stack::Abt => addr_of!(_abt_stack_high_end),
130            Stack::Hyp => addr_of!(_hyp_stack_high_end),
131            Stack::Irq => addr_of!(_irq_stack_high_end),
132            Stack::Fiq => addr_of!(_fiq_stack_high_end),
133            Stack::Sys => addr_of!(_sys_stack_high_end),
134        }
135    }
136}
137
138/// Iterator over all the [`Stack`] variants
139pub struct StackIter {
140    next: Option<Stack>,
141}
142
143impl StackIter {
144    /// Create a new [`StackIter`]
145    pub fn new() -> Self {
146        Self {
147            next: Some(Stack::Und),
148        }
149    }
150}
151
152impl Default for StackIter {
153    fn default() -> Self {
154        StackIter::new()
155    }
156}
157
158impl Iterator for StackIter {
159    type Item = Stack;
160
161    fn next(&mut self) -> Option<Self::Item> {
162        let current = self.next;
163        self.next = match self.next {
164            Some(Stack::Und) => Some(Stack::Svc),
165            Some(Stack::Svc) => Some(Stack::Abt),
166            Some(Stack::Abt) => Some(Stack::Hyp),
167            Some(Stack::Hyp) => Some(Stack::Irq),
168            Some(Stack::Irq) => Some(Stack::Fiq),
169            Some(Stack::Fiq) => Some(Stack::Sys),
170            Some(Stack::Sys) | None => None,
171        };
172        current
173    }
174}