#![no_std]
#![doc = include_str!(concat!("../", env!("CARGO_PKG_README")))]
use core::{arch::asm, mem::size_of, ops::Range};
pub const STACK_PAINT_VALUE: u32 = 0xCCCC_CCCC;
#[inline]
pub const fn stack() -> Range<*mut u32> {
unsafe extern "C" {
static mut _stack_start: u32;
static mut _stack_end: u32;
}
core::ptr::addr_of_mut!(_stack_start)..core::ptr::addr_of_mut!(_stack_end)
}
#[inline]
pub const fn stack_rev() -> Range<*mut u32> {
stack().end..stack().start
}
#[inline]
pub fn current_stack_ptr() -> *mut u32 {
let res;
unsafe { asm!("mov {}, sp", out(reg) res) };
res
}
#[inline]
pub const fn stack_size() -> u32 {
(unsafe { stack().start.byte_offset_from_unsigned(stack().end) }) as u32
}
#[inline]
pub fn current_stack_in_use() -> u32 {
(unsafe { stack().start.byte_offset_from_unsigned(current_stack_ptr()) }) as u32
}
#[inline]
pub fn current_stack_free() -> u32 {
stack_size().saturating_sub(current_stack_in_use())
}
#[inline]
pub fn current_stack_fraction() -> f32 {
current_stack_in_use() as f32 / stack_size() as f32
}
#[inline(never)]
pub fn repaint_stack() {
unsafe {
asm!(
"0:",
"cmp sp, {ptr}",
"bls 1f",
"stmia {ptr}!, {{{paint}}}",
"b 0b",
"1:",
ptr = inout(reg) stack().end => _,
paint = in(reg) STACK_PAINT_VALUE,
)
};
}
#[inline(never)]
pub fn stack_painted() -> u32 {
let res: *const u32;
unsafe {
asm!(
"0:",
"cmp sp, {ptr}",
"bls 1f",
"ldr {value}, [{ptr}]",
"cmp {value}, {paint}",
"bne 1f",
"adds {ptr}, #4",
"b 0b",
"1:",
ptr = inout(reg) stack().end => res,
value = out(reg) _,
paint = in(reg) STACK_PAINT_VALUE,
options(nostack, readonly)
)
};
(unsafe { res.byte_offset_from_unsigned(stack().end) }) as u32
}
pub unsafe fn stack_painted_binary() -> u32 {
let slice = unsafe {
&*core::ptr::slice_from_raw_parts(stack().end, current_stack_free() as usize / 4)
};
(slice.partition_point(|&word| word == STACK_PAINT_VALUE) * size_of::<u32>()) as u32
}