131d94d8fSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 231d94d8fSWedson Almeida Filho 331d94d8fSWedson Almeida Filho //! Allocator support. 4*8a799831SDanilo Krummrich //! 5*8a799831SDanilo Krummrich //! Documentation for the kernel's memory allocators can found in the "Memory Allocation Guide" 6*8a799831SDanilo Krummrich //! linked below. For instance, this includes the concept of "get free page" (GFP) flags and the 7*8a799831SDanilo Krummrich //! typical application of the different kernel allocators. 8*8a799831SDanilo Krummrich //! 9*8a799831SDanilo Krummrich //! Reference: <https://docs.kernel.org/core-api/memory-allocation.html> 1031d94d8fSWedson Almeida Filho 11b6a006e2SWedson Almeida Filho use super::{flags::*, Flags}; 1231d94d8fSWedson Almeida Filho use core::alloc::{GlobalAlloc, Layout}; 1331d94d8fSWedson Almeida Filho use core::ptr; 14*8a799831SDanilo Krummrich use core::ptr::NonNull; 15*8a799831SDanilo Krummrich 16*8a799831SDanilo Krummrich use crate::alloc::AllocError; 17*8a799831SDanilo Krummrich use crate::bindings; 1831d94d8fSWedson Almeida Filho 19941e6553SDanilo Krummrich struct Kmalloc; 2031d94d8fSWedson Almeida Filho 21a654a6e0SDanilo Krummrich /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. 22a654a6e0SDanilo Krummrich fn aligned_size(new_layout: Layout) -> usize { 23a654a6e0SDanilo Krummrich // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. 24a654a6e0SDanilo Krummrich let layout = new_layout.pad_to_align(); 25a654a6e0SDanilo Krummrich 26a654a6e0SDanilo Krummrich // Note that `layout.size()` (after padding) is guaranteed to be a multiple of `layout.align()` 27a654a6e0SDanilo Krummrich // which together with the slab guarantees means the `krealloc` will return a properly aligned 28a654a6e0SDanilo Krummrich // object (see comments in `kmalloc()` for more information). 29a654a6e0SDanilo Krummrich layout.size() 30a654a6e0SDanilo Krummrich } 31a654a6e0SDanilo Krummrich 3231d94d8fSWedson Almeida Filho /// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment. 3331d94d8fSWedson Almeida Filho /// 3431d94d8fSWedson Almeida Filho /// # Safety 3531d94d8fSWedson Almeida Filho /// 3631d94d8fSWedson Almeida Filho /// - `ptr` can be either null or a pointer which has been allocated by this allocator. 3731d94d8fSWedson Almeida Filho /// - `new_layout` must have a non-zero size. 3808d3f549SWedson Almeida Filho pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *mut u8 { 39a654a6e0SDanilo Krummrich let size = aligned_size(new_layout); 4031d94d8fSWedson Almeida Filho 4131d94d8fSWedson Almeida Filho // SAFETY: 4231d94d8fSWedson Almeida Filho // - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the 4331d94d8fSWedson Almeida Filho // function safety requirement. 44ad59baa3SVlastimil Babka // - `size` is greater than 0 since it's from `layout.size()` (which cannot be zero according 45ad59baa3SVlastimil Babka // to the function safety requirement) 46b6a006e2SWedson Almeida Filho unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 } 4731d94d8fSWedson Almeida Filho } 4831d94d8fSWedson Almeida Filho 49*8a799831SDanilo Krummrich /// # Invariants 50*8a799831SDanilo Krummrich /// 51*8a799831SDanilo Krummrich /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`. 52*8a799831SDanilo Krummrich struct ReallocFunc( 53*8a799831SDanilo Krummrich unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void, 54*8a799831SDanilo Krummrich ); 55*8a799831SDanilo Krummrich 56*8a799831SDanilo Krummrich #[expect(dead_code)] 57*8a799831SDanilo Krummrich impl ReallocFunc { 58*8a799831SDanilo Krummrich /// # Safety 59*8a799831SDanilo Krummrich /// 60*8a799831SDanilo Krummrich /// This method has the same safety requirements as [`Allocator::realloc`]. 61*8a799831SDanilo Krummrich /// 62*8a799831SDanilo Krummrich /// # Guarantees 63*8a799831SDanilo Krummrich /// 64*8a799831SDanilo Krummrich /// This method has the same guarantees as `Allocator::realloc`. Additionally 65*8a799831SDanilo Krummrich /// - it accepts any pointer to a valid memory allocation allocated by this function. 66*8a799831SDanilo Krummrich /// - memory allocated by this function remains valid until it is passed to this function. 67*8a799831SDanilo Krummrich unsafe fn call( 68*8a799831SDanilo Krummrich &self, 69*8a799831SDanilo Krummrich ptr: Option<NonNull<u8>>, 70*8a799831SDanilo Krummrich layout: Layout, 71*8a799831SDanilo Krummrich old_layout: Layout, 72*8a799831SDanilo Krummrich flags: Flags, 73*8a799831SDanilo Krummrich ) -> Result<NonNull<[u8]>, AllocError> { 74*8a799831SDanilo Krummrich let size = aligned_size(layout); 75*8a799831SDanilo Krummrich let ptr = match ptr { 76*8a799831SDanilo Krummrich Some(ptr) => { 77*8a799831SDanilo Krummrich if old_layout.size() == 0 { 78*8a799831SDanilo Krummrich ptr::null() 79*8a799831SDanilo Krummrich } else { 80*8a799831SDanilo Krummrich ptr.as_ptr() 81*8a799831SDanilo Krummrich } 82*8a799831SDanilo Krummrich } 83*8a799831SDanilo Krummrich None => ptr::null(), 84*8a799831SDanilo Krummrich }; 85*8a799831SDanilo Krummrich 86*8a799831SDanilo Krummrich // SAFETY: 87*8a799831SDanilo Krummrich // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that 88*8a799831SDanilo Krummrich // `ptr` is NULL or valid. 89*8a799831SDanilo Krummrich // - `ptr` is either NULL or valid by the safety requirements of this function. 90*8a799831SDanilo Krummrich // 91*8a799831SDanilo Krummrich // GUARANTEE: 92*8a799831SDanilo Krummrich // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`. 93*8a799831SDanilo Krummrich // - Those functions provide the guarantees of this function. 94*8a799831SDanilo Krummrich let raw_ptr = unsafe { 95*8a799831SDanilo Krummrich // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed. 96*8a799831SDanilo Krummrich self.0(ptr.cast(), size, flags.0).cast() 97*8a799831SDanilo Krummrich }; 98*8a799831SDanilo Krummrich 99*8a799831SDanilo Krummrich let ptr = if size == 0 { 100*8a799831SDanilo Krummrich crate::alloc::dangling_from_layout(layout) 101*8a799831SDanilo Krummrich } else { 102*8a799831SDanilo Krummrich NonNull::new(raw_ptr).ok_or(AllocError)? 103*8a799831SDanilo Krummrich }; 104*8a799831SDanilo Krummrich 105*8a799831SDanilo Krummrich Ok(NonNull::slice_from_raw_parts(ptr, size)) 106*8a799831SDanilo Krummrich } 107*8a799831SDanilo Krummrich } 108*8a799831SDanilo Krummrich 109db4f72c9SMiguel Ojeda // SAFETY: TODO. 110941e6553SDanilo Krummrich unsafe impl GlobalAlloc for Kmalloc { 11131d94d8fSWedson Almeida Filho unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 11231d94d8fSWedson Almeida Filho // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety 11331d94d8fSWedson Almeida Filho // requirement. 114b6a006e2SWedson Almeida Filho unsafe { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL) } 11531d94d8fSWedson Almeida Filho } 11631d94d8fSWedson Almeida Filho 11731d94d8fSWedson Almeida Filho unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { 118db4f72c9SMiguel Ojeda // SAFETY: TODO. 11931d94d8fSWedson Almeida Filho unsafe { 12031d94d8fSWedson Almeida Filho bindings::kfree(ptr as *const core::ffi::c_void); 12131d94d8fSWedson Almeida Filho } 12231d94d8fSWedson Almeida Filho } 12331d94d8fSWedson Almeida Filho 12431d94d8fSWedson Almeida Filho unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 12531d94d8fSWedson Almeida Filho // SAFETY: 12631d94d8fSWedson Almeida Filho // - `new_size`, when rounded up to the nearest multiple of `layout.align()`, will not 12731d94d8fSWedson Almeida Filho // overflow `isize` by the function safety requirement. 12831d94d8fSWedson Almeida Filho // - `layout.align()` is a proper alignment (i.e. not zero and must be a power of two). 12931d94d8fSWedson Almeida Filho let layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; 13031d94d8fSWedson Almeida Filho 13131d94d8fSWedson Almeida Filho // SAFETY: 13231d94d8fSWedson Almeida Filho // - `ptr` is either null or a pointer allocated by this allocator by the function safety 13331d94d8fSWedson Almeida Filho // requirement. 13431d94d8fSWedson Almeida Filho // - the size of `layout` is not zero because `new_size` is not zero by the function safety 13531d94d8fSWedson Almeida Filho // requirement. 136b6a006e2SWedson Almeida Filho unsafe { krealloc_aligned(ptr, layout, GFP_KERNEL) } 13731d94d8fSWedson Almeida Filho } 13831d94d8fSWedson Almeida Filho 13931d94d8fSWedson Almeida Filho unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 14031d94d8fSWedson Almeida Filho // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety 14131d94d8fSWedson Almeida Filho // requirement. 142b6a006e2SWedson Almeida Filho unsafe { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL | __GFP_ZERO) } 14331d94d8fSWedson Almeida Filho } 14431d94d8fSWedson Almeida Filho } 14531d94d8fSWedson Almeida Filho 14631d94d8fSWedson Almeida Filho #[global_allocator] 147941e6553SDanilo Krummrich static ALLOCATOR: Kmalloc = Kmalloc; 14831d94d8fSWedson Almeida Filho 14931d94d8fSWedson Almeida Filho // See <https://github.com/rust-lang/rust/pull/86844>. 15031d94d8fSWedson Almeida Filho #[no_mangle] 15131d94d8fSWedson Almeida Filho static __rust_no_alloc_shim_is_unstable: u8 = 0; 152