#![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 fn stack() -> Range<*mut u32> {
unsafe extern "C" {
static mut _stack_start: u32;
static _hart_stack_size: usize;
}
let hartid: usize;
unsafe { asm!("csrr {}, mhartid", out(reg) hartid) };
let stksz = &raw const _hart_stack_size as usize;
let start = unsafe { (&raw mut _stack_start).byte_sub(hartid * stksz) };
let end = unsafe { start.byte_sub(stksz) };
let start = start.map_addr(|p| p & !0b11);
let end = end.map_addr(|p| p & !0b11);
start..end
}
#[inline]
pub fn stack_rev() -> Range<*mut u32> {
unsafe { stack().end.add(1)..stack().start.add(1) }
}
#[inline]
pub fn current_stack_ptr() -> *mut u32 {
let res;
unsafe { asm!("mv {}, sp", out(reg) res) };
res
}
#[inline]
pub fn stack_size() -> usize {
unsafe { stack().start.byte_offset_from_unsigned(stack().end) }
}
#[inline]
pub fn current_stack_in_use() -> usize {
unsafe { stack().start.byte_offset_from_unsigned(current_stack_ptr()) }
}
#[inline]
pub fn current_stack_free() -> usize {
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:",
"bgeu {ptr}, sp, 1f",
"sw {paint}, 0({ptr})",
"addi {ptr}, {ptr}, 4",
"j 0b",
"1:",
ptr = inout(reg) stack().end.add(1) => _,
paint = in(reg) STACK_PAINT_VALUE,
)
};
}
#[inline(never)]
pub fn stack_painted() -> usize {
let res: *const u32;
unsafe {
asm!(
"0:",
"bgeu {ptr}, sp, 1f",
"lw {value}, 0({ptr})",
"bne {value}, {paint}, 1f",
"addi {ptr}, {ptr}, 4",
"j 0b",
"1:",
ptr = inout(reg) stack().end.add(1) => res,
value = out(reg) _,
paint = in(reg) STACK_PAINT_VALUE,
options(nostack, readonly)
)
};
unsafe { res.byte_offset_from_unsigned(stack().end) }
}
pub unsafe fn stack_painted_binary() -> usize {
let slice =
unsafe { &*core::ptr::slice_from_raw_parts(stack().end.add(1), current_stack_free() / 4) };
slice.partition_point(|&word| word == STACK_PAINT_VALUE) * size_of::<usize>()
}