1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Extent of the main stack, and how much of it is left.
//!
//! The stack is a region the linker script reserves and `boot.s` points
//! `sp` at, rather than whatever happened to sit below the load address
//! — so its size is a number in a file (`__stack_size`, 1 MiB by
//! default, overridable with `-Wl,--defsym=__stack_size=...`), the same
//! on both architectures.
//!
//! What this module is for is the question that is otherwise
//! unanswerable from inside a program: *how close am I?* An overflow
//! runs off the bottom of the region and takes a data abort — the `mmu`
//! feature leaves the margin below it unmapped for exactly that reason —
//! and with no handler for it that abort parks silently and looks like a
//! hang in a driver. `rpi-hal`'s `fault-report` feature prints it
//! instead, and names the overflow rather than leaving a plain
//! translation fault to be recognised. One line at startup —
//!
//! ```ignore
//! writeln!(uart, "sp {:#x}, {} KiB free", stack::pointer(),
//! stack::headroom().unwrap_or(0) / 1024)?;
//! ```
//!
//! — turns that class of bug from a debugging session into a number.
//!
//! Only core 0's main stack lives in this region. A secondary core runs
//! on the [`Stack<BYTES>`](crate::multicore::Stack) its application
//! supplied, and the AArch32 exception modes run on their own banked
//! regions, which is why [`used`] and
//! [`headroom`] are `Option` — they
//! report `None` rather than a meaningless number when `sp` isn't in
//! this region at all.
extern "C"
/// Lowest address of the main stack region.
/// One past the highest address of the main stack region — where `sp`
/// starts.
/// Size of the main stack region in bytes (`__stack_size`).
/// The calling core's current stack pointer.
///
/// On a secondary core, or in an AArch32 exception mode, this is a
/// pointer into that context's own stack rather than into this region —
/// see this module's doc comment.
/// Bytes of the main stack currently in use, or `None` if the caller
/// isn't running on it.
/// Bytes between the current stack pointer and the bottom of the main
/// stack — the headroom left before an overflow — or `None` if the
/// caller isn't running on it.
///
/// Worth logging once at startup in any program whose deepest call path
/// isn't obvious: a `rustls` configuration or a mounted FAT volume can
/// put tens of KiB in a single frame.