hermit/mm/
allocator.rs

1//! Implementation of the Hermit Allocator for dynamically allocating heap memory
2//! in the kernel.
3
4use core::alloc::{GlobalAlloc, Layout};
5
6use hermit_sync::RawInterruptTicketMutex;
7use talc::{ErrOnOom, Span, Talc, Talck};
8
9pub struct LockedAllocator(Talck<RawInterruptTicketMutex, ErrOnOom>);
10
11impl LockedAllocator {
12	pub const fn new() -> Self {
13		Self(Talc::new(ErrOnOom).lock())
14	}
15
16	#[inline]
17	fn align_layout(layout: Layout) -> Layout {
18		let align = layout
19			.align()
20			.max(core::mem::align_of::<crossbeam_utils::CachePadded<u8>>());
21		Layout::from_size_align(layout.size(), align).unwrap()
22	}
23
24	pub unsafe fn init(&self, heap_bottom: *mut u8, heap_size: usize) {
25		let arena = Span::from_base_size(heap_bottom, heap_size);
26		unsafe {
27			self.0.lock().claim(arena).unwrap();
28		}
29	}
30}
31
32/// To avoid false sharing, the global memory allocator align
33/// all requests to a cache line.
34unsafe impl GlobalAlloc for LockedAllocator {
35	unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
36		let layout = Self::align_layout(layout);
37		unsafe { self.0.alloc(layout) }
38	}
39
40	unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
41		let layout = Self::align_layout(layout);
42		unsafe { self.0.dealloc(ptr, layout) }
43	}
44
45	unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
46		let layout = Self::align_layout(layout);
47		unsafe { self.0.alloc_zeroed(layout) }
48	}
49
50	unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
51		let layout = Self::align_layout(layout);
52		unsafe { self.0.realloc(ptr, layout, new_size) }
53	}
54}
55
56#[cfg(all(test, not(target_os = "none")))]
57mod tests {
58	use core::mem;
59
60	use super::*;
61
62	#[test]
63	fn empty() {
64		const ARENA_SIZE: usize = 0x1000;
65		let mut arena: [u8; ARENA_SIZE] = [0; ARENA_SIZE];
66		let allocator: LockedAllocator = LockedAllocator::new();
67		unsafe {
68			allocator.init(arena.as_mut_ptr(), ARENA_SIZE);
69		}
70
71		let layout = Layout::from_size_align(1, 1).unwrap();
72		// we have 4 kbyte  memory
73		assert!(unsafe { !allocator.alloc(layout.clone()).is_null() });
74
75		let layout = Layout::from_size_align(0x1000, mem::align_of::<usize>()).unwrap();
76		let addr = unsafe { allocator.alloc(layout) };
77		assert!(addr.is_null());
78	}
79}