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");