umm_malloc/lib.rs
1#![no_std]
2
3//! Provides a global allocator using the [umm_malloc][0] library.
4//! You must call [`umm_malloc::init_heap()`](fn@init) exactly once
5//! before allocating anything using the global memory allocator.
6//!
7//! All allocations from this allocator are aligned by 8 bytes.
8//! Requesting a larger alignment is not implemented and will panic.
9//!
10//! # Global Allocator Critical Sections
11//!
12//! Concurrent access to the global allocator is Undefined Behavior. Enable only one of the following cargo features to
13//! configure how access to the global allocator is controlled.
14//!
15//! - `cortex-m-interrupt-critical-section`: interrupt-disabled critical section for ARM Cortex-M processors.
16//! - `extern-critical-section`: Uses the extern functions `void _umm_critical_entry(uint32_t*)` and
17//! `void _umm_critical_exit(uint32_t*)` to implement the global allocator critical sections. You MUST supply those
18//! functions via some other means.
19//! Note that critical sections may nest.
20//! - `unsafe-no-critical-section`: no critical sections around the global allocator. You MUST prevent concurrent use
21//! of the global allcator to avoid Undefined Behavior.
22//!
23//! [0]: https://github.com/rhempel/umm_malloc
24
25use umm_malloc_sys as ffi;
26
27/// Initializes the heap from extern addresses
28///
29/// This function initializes the heap using the address defined by the extern pointer `UMM_MALLOC_CFG_HEAP_ADDR` with
30/// size defined by the extern u32 `UMM_MALLOC_CFG_HEAP_ADDR`. You must define symbols with those (unmangled) names
31/// elsewhere, e.g. in your linker script.
32///
33/// See [`umm_malloc::init_heap()`](fn@init) for runtime initialization.
34///
35/// # Note
36///
37/// - The heap grows "upwards", towards larger addresses. Thus `end_addr` must
38/// be larger than `start_addr`.
39/// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`. The
40/// allocator won't use the byte at `end_addr`.
41///
42/// # Safety
43///
44/// Obey these or Bad Stuff will happen.
45///
46/// - This function must be called exactly ONCE.
47/// - This function must be called BEFORE you run any code that makes use of the allocator unless the cargo feature
48/// `init-if-uninitialized` or `hang-if-uninitialized` is enabled.
49#[inline]
50pub unsafe fn init() {
51 ffi::umm_init()
52}
53
54/// Initializes the heap with the given block of memory
55///
56/// `start_addr` is the address where the heap will be located.
57///
58/// `size` is the size of the heap in bytes.
59///
60/// # Note
61///
62/// - The heap grows "upwards", towards larger addresses. Thus `end_addr` must
63/// be larger than `start_addr`.
64/// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`. The
65/// allocator won't use the byte at `end_addr`.
66/// - This memory will be zeroed by the allocator.
67///
68/// # Safety
69///
70/// Obey these or Bad Stuff will happen.
71///
72/// - This function must be called exactly ONCE.
73/// - `size > 0`
74/// - This function must be called BEFORE you run any code that makes use of the allocator unless the cargo feature
75/// `init-if-uninitialized` or `hang-if-uninitialized` is enabled.
76#[inline]
77pub unsafe fn init_heap(start_addr: usize, size: usize) {
78 ffi::umm_init_heap(start_addr as *mut _, size)
79}
80
81struct UmmHeap {}
82
83#[global_allocator]
84static ALLOCATOR: UmmHeap = UmmHeap {};
85
86/// All allocations from this allocator are aligned to `MIN_ALIGN`.
87/// Alignments larger than `MIN_ALIGN` are currently not supported.
88/// Calling `alloc()` or `realloc()` with a `layout` requesting a larger
89/// alignment will panic.
90pub const MIN_ALIGN: usize = 8;
91
92unsafe impl core::alloc::GlobalAlloc for UmmHeap {
93 #[inline]
94 unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
95 if layout.align() <= MIN_ALIGN {
96 ffi::umm_malloc(layout.size()).cast()
97 } else {
98 unimplemented!("Aligned alloc not implemented");
99 }
100 }
101
102 #[inline]
103 unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
104 ffi::umm_free(ptr.cast());
105 }
106
107 #[inline]
108 // The contract of realloc requires `new_size` to be greater than zero. This method will
109 // `free()` and return `null`.
110 unsafe fn realloc(
111 &self,
112 ptr: *mut u8,
113 layout: core::alloc::Layout,
114 new_size: usize,
115 ) -> *mut u8 {
116 if layout.align() <= MIN_ALIGN {
117 ffi::umm_realloc(ptr.cast(), new_size).cast()
118 } else {
119 unimplemented!("Aligned alloc not implemented");
120 }
121 }
122
123 // umm_calloc doesn't do anything special
124}
125
126#[cfg(any(
127 all(
128 feature = "cortex-m-interrupt-critical-section",
129 any(
130 feature = "unsafe-no-critical-section",
131 feature = "extern-critical-section"
132 )
133 ),
134 all(
135 feature = "unsafe-no-critical-section",
136 any(
137 feature = "cortex-m-interrupt-critical-section",
138 feature = "extern-critical-section"
139 )
140 ),
141 all(
142 feature = "extern-critical-section",
143 any(
144 feature = "cortex-m-interrupt-critical-section",
145 feature = "unsafe-no-critical-section"
146 )
147 ),
148))]
149compile_error!("Only enable one critical section cargo feature");
150
151#[cfg(not(any(
152 feature = "cortex-m-interrupt-critical-section",
153 feature = "extern-critical-section",
154 feature = "unsafe-no-critical-section"
155)))]
156compile_error!("A critical section cargo feature must be enabled");