blob: eea2e9883399dcec6b2c2faefd384872f4adb87b [file] [log] [blame]
Pierre-Clément Tosifc531152022-10-20 12:22:23 +01001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Heap implementation.
16
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000017use alloc::alloc::alloc;
18use alloc::alloc::Layout;
19use alloc::boxed::Box;
20
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000021use core::alloc::GlobalAlloc as _;
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000022use core::ffi::c_void;
23use core::mem;
24use core::num::NonZeroUsize;
25use core::ptr;
26use core::ptr::NonNull;
27
Pierre-Clément Tosifc531152022-10-20 12:22:23 +010028use buddy_system_allocator::LockedHeap;
29
30#[global_allocator]
31static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
32
Andrew Walbran739c9e62023-01-16 11:59:33 +000033/// 128 KiB
Alice Wang815461f2023-01-31 12:59:00 +000034const HEAP_SIZE: usize = 0x20000;
Andrew Walbran739c9e62023-01-16 11:59:33 +000035static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
Pierre-Clément Tosifc531152022-10-20 12:22:23 +010036
37pub unsafe fn init() {
38 HEAP_ALLOCATOR.lock().init(HEAP.as_mut_ptr() as usize, HEAP.len());
39}
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000040
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000041/// Allocate an aligned but uninitialized slice of heap.
42pub fn aligned_boxed_slice(size: usize, align: usize) -> Option<Box<[u8]>> {
43 let size = NonZeroUsize::new(size)?.get();
44 let layout = Layout::from_size_align(size, align).ok()?;
45 // SAFETY - We verify that `size` and the returned `ptr` are non-null.
46 let ptr = unsafe { alloc(layout) };
47 let ptr = NonNull::new(ptr)?.as_ptr();
48 let slice_ptr = ptr::slice_from_raw_parts_mut(ptr, size);
49
50 // SAFETY - The memory was allocated using the proper layout by our global_allocator.
51 Some(unsafe { Box::from_raw(slice_ptr) })
52}
53
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000054#[no_mangle]
55unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
Pierre-Clément Tosiaaa08692023-03-10 13:55:19 +000056 malloc_(size, false).map_or(ptr::null_mut(), |p| p.cast::<c_void>().as_ptr())
57}
58
59#[no_mangle]
60unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
61 let Some(size) = nmemb.checked_mul(size) else {
62 return ptr::null_mut()
63 };
64 malloc_(size, true).map_or(ptr::null_mut(), |p| p.cast::<c_void>().as_ptr())
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000065}
66
67#[no_mangle]
68unsafe extern "C" fn free(ptr: *mut c_void) {
69 if let Some(ptr) = NonNull::new(ptr).map(|p| p.cast::<usize>().as_ptr().offset(-1)) {
70 if let Some(size) = NonZeroUsize::new(*ptr) {
71 if let Some(layout) = malloc_layout(size) {
72 HEAP_ALLOCATOR.dealloc(ptr as *mut u8, layout);
73 }
74 }
75 }
76}
77
Pierre-Clément Tosiaaa08692023-03-10 13:55:19 +000078unsafe fn malloc_(size: usize, zeroed: bool) -> Option<NonNull<usize>> {
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000079 let size = NonZeroUsize::new(size)?.checked_add(mem::size_of::<usize>())?;
Pierre-Clément Tosiaaa08692023-03-10 13:55:19 +000080 let layout = malloc_layout(size)?;
81 let ptr =
82 if zeroed { HEAP_ALLOCATOR.alloc_zeroed(layout) } else { HEAP_ALLOCATOR.alloc(layout) };
Pierre-Clément Tosi54e71d02022-12-08 13:57:43 +000083 let ptr = NonNull::new(ptr)?.cast::<usize>().as_ptr();
84 *ptr = size.get();
85 NonNull::new(ptr.offset(1))
86}
87
88fn malloc_layout(size: NonZeroUsize) -> Option<Layout> {
89 const ALIGN: usize = mem::size_of::<u64>();
90 Layout::from_size_align(size.get(), ALIGN).ok()
91}