aarch32-rt 0.3.0

Run-time support for Arm AArch32
Documentation
//! Code for examining linker allocated stacks

/// Represents one of the AArch32 stacks
#[derive(Debug, Copy, Clone)]
pub enum Stack {
    /// UND mode stack
    Und,
    /// SVC mode stack
    Svc,
    /// ABT mode stack, for data abort and prefetch abort
    Abt,
    /// HYP mode stack, for EL2
    Hyp,
    /// IRQ mode stack, for interrupts
    Irq,
    /// FIQ mode stack, for fast interrupts
    Fiq,
    /// SYS mode stack, for the main thread
    Sys,
}

impl core::fmt::Display for Stack {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        f.pad(match self {
            Stack::Und => "UND",
            Stack::Svc => "SVC",
            Stack::Abt => "ABT",
            Stack::Hyp => "HYP",
            Stack::Irq => "IRQ",
            Stack::Fiq => "FIQ",
            Stack::Sys => "SYS",
        })
    }
}

impl Stack {
    /// Create an iterator over all the stacks
    pub fn iter() -> impl Iterator<Item = Stack> {
        StackIter::new()
    }

    /// Get the highest address of this stack, for the given core
    pub fn top(&self, core: usize) -> Option<*const u32> {
        if core > Self::num_cores() {
            return None;
        }
        let top = self.stack_top();
        let core = core as isize;
        let per_core_size_words = self.per_core_size_words();
        Some(unsafe { top.offset(-per_core_size_words * core) })
    }

    /// Get the lowest address of this stack, for the given core
    pub fn bottom(&self, core: usize) -> Option<*const u32> {
        self.top(core)
            .map(|p| unsafe { p.offset(-self.per_core_size_words()) })
    }

    /// Get the range of this stack, for the given core
    pub fn range(&self, core: usize) -> Option<core::ops::Range<*const u32>> {
        if let (Some(bottom), Some(top)) = (self.bottom(core), self.top(core)) {
            Some(bottom..top)
        } else {
            None
        }
    }

    /// Get the inclusive range of this stack, for the given core
    ///
    /// This is the range you need to give to the PMSAv8 MPU code.
    pub fn mpu_range(&self, core: usize) -> Option<core::ops::RangeInclusive<*const u8>> {
        if let (Some(bottom), Some(top)) = (self.bottom(core), self.top(core)) {
            let top = top as *const u8;
            let bottom = bottom as *const u8;
            let top_under = unsafe { top.offset(-1) };
            Some(bottom..=top_under)
        } else {
            None
        }
    }

    /// Get number of cores in this system
    pub fn num_cores() -> usize {
        unsafe extern "C" {
            safe static _num_cores: u8;
        }
        core::ptr::addr_of!(_num_cores) as usize
    }

    /// Get the total size of this stack across all cores
    pub fn per_core_size_words(&self) -> isize {
        use core::ptr::addr_of;
        unsafe extern "C" {
            static _und_stack_size: u8;
            static _svc_stack_size: u8;
            static _abt_stack_size: u8;
            static _hyp_stack_size: u8;
            static _irq_stack_size: u8;
            static _fiq_stack_size: u8;
            static _sys_stack_size: u8;
        }
        let size_bytes = match self {
            Stack::Und => addr_of!(_und_stack_size) as isize,
            Stack::Svc => addr_of!(_svc_stack_size) as isize,
            Stack::Abt => addr_of!(_abt_stack_size) as isize,
            Stack::Hyp => addr_of!(_hyp_stack_size) as isize,
            Stack::Irq => addr_of!(_irq_stack_size) as isize,
            Stack::Fiq => addr_of!(_fiq_stack_size) as isize,
            Stack::Sys => addr_of!(_sys_stack_size) as isize,
        };
        size_bytes / 4
    }

    /// Get the top address for this stack
    fn stack_top(&self) -> *const u32 {
        use core::ptr::addr_of;
        unsafe extern "C" {
            static _und_stack_high_end: u32;
            static _svc_stack_high_end: u32;
            static _abt_stack_high_end: u32;
            static _hyp_stack_high_end: u32;
            static _irq_stack_high_end: u32;
            static _fiq_stack_high_end: u32;
            static _sys_stack_high_end: u32;
        }
        match self {
            Stack::Und => addr_of!(_und_stack_high_end),
            Stack::Svc => addr_of!(_svc_stack_high_end),
            Stack::Abt => addr_of!(_abt_stack_high_end),
            Stack::Hyp => addr_of!(_hyp_stack_high_end),
            Stack::Irq => addr_of!(_irq_stack_high_end),
            Stack::Fiq => addr_of!(_fiq_stack_high_end),
            Stack::Sys => addr_of!(_sys_stack_high_end),
        }
    }
}

/// Iterator over all the [`Stack`] variants
pub struct StackIter {
    next: Option<Stack>,
}

impl StackIter {
    /// Create a new [`StackIter`]
    pub fn new() -> Self {
        Self {
            next: Some(Stack::Und),
        }
    }
}

impl Default for StackIter {
    fn default() -> Self {
        StackIter::new()
    }
}

impl Iterator for StackIter {
    type Item = Stack;

    fn next(&mut self) -> Option<Self::Item> {
        let current = self.next;
        self.next = match self.next {
            Some(Stack::Und) => Some(Stack::Svc),
            Some(Stack::Svc) => Some(Stack::Abt),
            Some(Stack::Abt) => Some(Stack::Hyp),
            Some(Stack::Hyp) => Some(Stack::Irq),
            Some(Stack::Irq) => Some(Stack::Fiq),
            Some(Stack::Fiq) => Some(Stack::Sys),
            Some(Stack::Sys) | None => None,
        };
        current
    }
}