alloc_cortex_m/lib.rs
1//! A heap allocator for Cortex-M processors.
2//!
3//! Note that using this as your global allocator requires nightly Rust.
4//!
5//! # Example
6//!
7//! For a usage example, see `examples/global_alloc.rs`.
8
9#![no_std]
10
11use core::alloc::{GlobalAlloc, Layout};
12use core::cell::RefCell;
13use core::ptr::{self, NonNull};
14
15use cortex_m::interrupt::Mutex;
16use linked_list_allocator::Heap;
17
18pub struct CortexMHeap {
19 heap: Mutex<RefCell<Heap>>,
20}
21
22impl CortexMHeap {
23 /// Crate a new UNINITIALIZED heap allocator
24 ///
25 /// You must initialize this heap using the
26 /// [`init`](struct.CortexMHeap.html#method.init) method before using the allocator.
27 pub const fn empty() -> CortexMHeap {
28 CortexMHeap {
29 heap: Mutex::new(RefCell::new(Heap::empty())),
30 }
31 }
32
33 /// Initializes the heap
34 ///
35 /// This function must be called BEFORE you run any code that makes use of the
36 /// allocator.
37 ///
38 /// `start_addr` is the address where the heap will be located.
39 ///
40 /// `size` is the size of the heap in bytes.
41 ///
42 /// Note that:
43 ///
44 /// - The heap grows "upwards", towards larger addresses. Thus `end_addr` must
45 /// be larger than `start_addr`
46 ///
47 /// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`. The
48 /// allocator won't use the byte at `end_addr`.
49 ///
50 /// # Safety
51 ///
52 /// Obey these or Bad Stuff will happen.
53 ///
54 /// - This function must be called exactly ONCE.
55 /// - `size > 0`
56 pub unsafe fn init(&self, start_addr: usize, size: usize) {
57 cortex_m::interrupt::free(|cs| {
58 self.heap
59 .borrow(cs)
60 .borrow_mut()
61 .init(start_addr as *mut u8, size);
62 });
63 }
64
65 /// Returns an estimate of the amount of bytes in use.
66 pub fn used(&self) -> usize {
67 cortex_m::interrupt::free(|cs| self.heap.borrow(cs).borrow_mut().used())
68 }
69
70 /// Returns an estimate of the amount of bytes available.
71 pub fn free(&self) -> usize {
72 cortex_m::interrupt::free(|cs| self.heap.borrow(cs).borrow_mut().free())
73 }
74}
75
76unsafe impl GlobalAlloc for CortexMHeap {
77 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
78 cortex_m::interrupt::free(|cs| {
79 self.heap
80 .borrow(cs)
81 .borrow_mut()
82 .allocate_first_fit(layout)
83 .ok()
84 .map_or(ptr::null_mut(), |allocation| allocation.as_ptr())
85 })
86 }
87
88 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
89 cortex_m::interrupt::free(|cs| {
90 self.heap
91 .borrow(cs)
92 .borrow_mut()
93 .deallocate(NonNull::new_unchecked(ptr), layout)
94 });
95 }
96}