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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Where the image ends and free RAM begins.
//!
//! The companion to [`crate::stack`], which answers the same kind of
//! question about the other reserved region: this one is for a program
//! that wants a heap and has to decide how big it can be.
//!
//! Nothing here allocates or hands out memory. A HAL must not declare a
//! `#[global_allocator]` — a program may have only one, and that choice
//! belongs to the final binary — so what this provides is the *extent*,
//! and the binary passes it to whichever allocator it registered:
//!
//! ```ignore
//! let region = mem::heap_region(&mut mailbox)?;
//! // SAFETY: called once, before anything allocates.
//! unsafe { HEAP.init(region.start, region.len()) };
//! ```
//!
//! `examples/heap_alloc.rs` is that, whole.
//!
//! # Why the top comes from the firmware
//!
//! How much RAM the ARM has is not a property of the board alone. The
//! VideoCore takes its share first, set by `gpu_mem` in `config.txt`, and
//! what is left is what the firmware reports. Hardcoding a number means
//! an image that is wrong on a board with a different split — and wrong
//! in the direction that hands the allocator memory the GPU is also
//! using, which presents as corruption somewhere else entirely rather
//! than as a failure to allocate.
use Range;
use crate;
extern "C"
/// Alignment the heap region starts on.
///
/// The linker script promises `__bss_end` is word-aligned, which is all
/// the boot code's `.bss` zeroing needs. An allocator hands out blocks
/// aligned for `u64`, which is 8 even on AArch32 where a pointer is 4 —
/// so the start is raised to that here, next to the requirement, rather
/// than by asking the script for an alignment only one of its consumers
/// cares about.
const HEAP_ALIGN: usize = 8;
/// Why [`heap_region`] could not answer.
/// First address above the loaded image, aligned for a heap to start on.
///
/// Everything this crate's linker script places — `.text`, `.rodata`,
/// `.data`, the stacks and `.bss` — is below this, so it is the lowest
/// address a program can claim without knowing what else it linked.
///
/// Useful on its own for a program placing something other than a heap
/// there. For a heap, [`heap_region`] pairs it with the upper bound.
/// Every byte between the end of the image and the top of the ARM's share
/// of RAM.
///
/// The whole of what is free: this crate's linker script puts the stacks
/// inside the image rather than leaving them to grow down from the load
/// address, so nothing is reserved above [`image_end`] for anything else
/// to find.
///
/// The region is identity-mapped as cacheable Normal memory by the `mmu`
/// feature's bring-up — it is below the peripheral base, which is where
/// that map stops being RAM — so a program with the MMU on can hand the
/// whole of it to an allocator. With the MMU off it is still RAM, and
/// still Strongly Ordered like everything else, which is slow rather than
/// wrong.
///
/// # Errors
///
/// [`Error::Mailbox`] if the firmware does not answer, and
/// [`Error::NoRoom`] if the image ends at or above the top of the
/// reported memory — which is a board whose `gpu_mem` leaves less than
/// the kernel needs, not a condition to carry on past with a zero-length
/// heap.