Skip to main content

aarch32_cpu/
stacks.rs

1//! Code for checking stack usage
2
3/// Reports stack usage as a count of bytes
4///
5/// It starts at the lower bound, and looks for values that are set to 0,
6/// concluding that those values have never been used. It returns `(total,
7/// used)` in bytes.
8///
9/// # Safety
10///
11/// Pass a range of valid, readable, memory with 32-bit aligned addresses.
12pub unsafe fn stack_used_bytes(stack: core::ops::Range<*const u32>) -> (usize, usize) {
13    let size_words = unsafe { stack.end.offset_from(stack.start) } as usize;
14    let unused_words = unsafe { stack_unused_bytes_asm(stack.start, size_words) };
15    let used_words = size_words - unused_words;
16    (
17        size_words * core::mem::size_of::<u32>(),
18        used_words * core::mem::size_of::<u32>(),
19    )
20}
21
22/// Counts number of words that are equal to zero
23///
24/// Written in Arm assembly to avoid any issues with pointing at things that are
25/// not validly initialised integers (as far as Rust is concerned).
26///
27/// Returns a count of the number of contiguous words equal to 0x0 at `start`, with a
28/// maximum of `size` words
29///
30/// # Safety
31///
32/// The address `start` must be correctly aligned, and point to a region of memory
33/// of at least `size` words in length.
34unsafe fn stack_unused_bytes_asm(start: *const u32, size: usize) -> usize {
35    let result: usize;
36    unsafe {
37        core::arch::asm!(
38            r#"
39            // skip out if size is zero
40            movs    {result}, #0
41            cmp     {size}, #0
42            beq     3f
43    2:      // loop
44            ldr     {scratch}, [{start}]
45            cmp     {scratch}, #0
46            // break out if value is non-zero
47            bne     3f
48            // otherwise increment counter
49            adds    {result}, {result}, #1
50            adds    {start}, {start}, #4
51            // loop if not finished yet
52            cmp     {result}, {size}
53            bne     2b
54            // all finished
55    3:
56            "#,
57            size = in(reg) size,
58            start = inout(reg) start => _,
59            result = out(reg) result,
60            scratch = out(reg) _,
61        );
62    }
63    result
64}