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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
//! A heap allocator for Cortex-M processors //! //! # Example //! //! ``` //! // Plug in the allocator crate //! extern crate alloc_cortex_m; //! extern crate collections; //! //! use collections::Vec; //! //! // These symbols come from a linker script //! extern "C" { //! static mut _heap_start: usize; //! static mut _heap_end: usize; //! } //! //! #[no_mangle] //! pub fn main() -> ! { //! // Initialize the heap BEFORE you use the allocator //! unsafe { alloc_cortex_m::init(&mut _heap_start, &mut _heap_end) } //! //! let mut xs = Vec::new(); //! xs.push(1); //! // ... //! } //! ``` //! //! And in your linker script, you might have something like: //! //! ``` text //! /* space reserved for the stack */ //! _stack_size = 0x1000; //! //! /* `.` is right after the .bss and .data sections */ //! _heap_start = .; //! _heap_end = ORIGIN(SRAM) + LENGTH(SRAM) - _stack_size; //! ``` #![allocator] #![feature(allocator)] #![feature(const_fn)] #![no_std] extern crate cortex_m; extern crate linked_list_allocator; use core::{cmp, ptr}; use linked_list_allocator::Heap; use cortex_m::interrupt::Mutex; /// A global UNINITIALIZED heap allocator /// /// You must initialize this heap using the /// [`init`](struct.Heap.html#method.init) method before using the allocator. static HEAP: Mutex<Heap> = Mutex::new(Heap::empty()); /// Initializes the heap /// /// This function must be called BEFORE you run any code that makes use of the /// allocator. /// /// `start_addr` is the address where the heap will be located. /// /// `end_addr` points to the end of the heap. /// /// Note that: /// /// - The heap grows "upwards", towards larger addresses. Thus `end_addr` must /// be larger than `start_addr` /// /// - The size of the heap will actually be /// `(end_addr as usize) - (start_addr as usize) + 1` because the allocator /// won't use the byte at `end_addr`. /// /// # Unsafety /// /// Obey these or Bad Stuff will happen. /// /// - This function must be called exactly ONCE. /// - `end_addr` > `start_addr` pub unsafe fn init(start_addr: *mut usize, end_addr: *mut usize) { let start = start_addr as usize; let end = end_addr as usize; let size = (end - start) - 1; HEAP.lock(|heap| heap.init(start, size)); } // Rust allocator interface #[doc(hidden)] #[no_mangle] /// Rust allocation function (c.f. malloc) pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { HEAP.lock(|heap| { heap.allocate_first_fit(size, align).expect("out of memory") }) } /// Rust de-allocation function (c.f. free) #[doc(hidden)] #[no_mangle] pub extern "C" fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) { HEAP.lock(|heap| unsafe { heap.deallocate(ptr, size, align) }); } /// Rust re-allocation function (c.f. realloc) #[doc(hidden)] #[no_mangle] pub extern "C" fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> *mut u8 { // from: https://github.com/rust-lang/rust/blob/ // c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/ // src/liballoc_system/lib.rs#L98-L101 let new_ptr = __rust_allocate(new_size, align); unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) }; __rust_deallocate(ptr, size, align); new_ptr } /// Rust re-allocation function which guarantees not to move the data /// somewhere else. #[doc(hidden)] #[no_mangle] pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize, _new_size: usize, _align: usize) -> usize { size } /// Some allocators (pool allocators generally) over-allocate. This checks how /// much space there is at a location. Our allocator doesn't over allocate so /// this just returns `size` #[doc(hidden)] #[no_mangle] pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize { size }