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}