1 use klog_types::{AllocLogItem, LogSource}; 2 3 use crate::{ 4 arch::mm::LockedFrameAllocator, 5 debug::klog::mm::mm_debug_log, 6 libs::align::page_align_up, 7 mm::{MMArch, MemoryManagementArch, VirtAddr}, 8 }; 9 10 use core::{ 11 alloc::{AllocError, GlobalAlloc, Layout}, 12 intrinsics::unlikely, 13 ptr::NonNull, 14 }; 15 16 use super::{ 17 page_frame::{FrameAllocator, PageFrameCount}, 18 slab::{slab_init_state, SLABALLOCATOR}, 19 }; 20 21 /// 类kmalloc的分配器应当实现的trait 22 pub trait LocalAlloc { 23 unsafe fn local_alloc(&self, layout: Layout) -> *mut u8; 24 unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8; 25 unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout); 26 } 27 28 pub struct KernelAllocator; 29 30 impl KernelAllocator { 31 unsafe fn alloc_in_buddy(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 32 // 计算需要申请的页数,向上取整 33 let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two(); 34 let page_frame_count = PageFrameCount::new(count); 35 let (phy_addr, allocated_frame_count) = LockedFrameAllocator 36 .allocate(page_frame_count) 37 .ok_or(AllocError)?; 38 39 let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr).ok_or(AllocError)? }; 40 if unlikely(virt_addr.is_null()) { 41 return Err(AllocError); 42 } 43 44 let slice = unsafe { 45 core::slice::from_raw_parts_mut( 46 virt_addr.data() as *mut u8, 47 allocated_frame_count.data() * MMArch::PAGE_SIZE, 48 ) 49 }; 50 return Ok(NonNull::from(slice)); 51 } 52 53 unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) { 54 // 由于buddy分配的页数量是2的幂,因此释放的时候也需要按照2的幂向上取整。 55 let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two(); 56 let page_frame_count = PageFrameCount::new(count); 57 let phy_addr = MMArch::virt_2_phys(VirtAddr::new(ptr as usize)).unwrap(); 58 LockedFrameAllocator.free(phy_addr, page_frame_count); 59 } 60 } 61 62 /// 为内核分配器实现LocalAlloc的trait 63 impl LocalAlloc for KernelAllocator { 64 unsafe fn local_alloc(&self, layout: Layout) -> *mut u8 { 65 if allocator_select_condition(layout) { 66 return self 67 .alloc_in_buddy(layout) 68 .map(|x| x.as_mut_ptr()) 69 .unwrap_or(core::ptr::null_mut()); 70 } else { 71 if let Some(ref mut slab) = SLABALLOCATOR { 72 return slab.allocate(layout); 73 }; 74 return core::ptr::null_mut(); 75 } 76 } 77 78 unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8 { 79 if allocator_select_condition(layout) { 80 return self 81 .alloc_in_buddy(layout) 82 .map(|x| { 83 let ptr: *mut u8 = x.as_mut_ptr(); 84 core::ptr::write_bytes(ptr, 0, x.len()); 85 ptr 86 }) 87 .unwrap_or(core::ptr::null_mut()); 88 } else { 89 if let Some(ref mut slab) = SLABALLOCATOR { 90 return slab.allocate(layout); 91 }; 92 return core::ptr::null_mut(); 93 } 94 } 95 96 unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) { 97 if allocator_select_condition(layout) || ((ptr as usize) % 4096) == 0 { 98 self.free_in_buddy(ptr, layout) 99 } else if let Some(ref mut slab) = SLABALLOCATOR { 100 slab.deallocate(ptr, layout).unwrap() 101 } 102 } 103 } 104 105 /// 为内核slab分配器实现GlobalAlloc特性 106 unsafe impl GlobalAlloc for KernelAllocator { 107 unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 108 let r = self.local_alloc_zeroed(layout); 109 if allocator_select_condition(layout) { 110 alloc_debug_log(klog_types::LogSource::Buddy, layout, r); 111 } else { 112 alloc_debug_log(klog_types::LogSource::Slab, layout, r); 113 } 114 return r; 115 } 116 117 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 118 let r = self.local_alloc_zeroed(layout); 119 if allocator_select_condition(layout) { 120 alloc_debug_log(klog_types::LogSource::Buddy, layout, r); 121 } else { 122 alloc_debug_log(klog_types::LogSource::Slab, layout, r); 123 } 124 return r; 125 } 126 127 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 128 if allocator_select_condition(layout) || ((ptr as usize) % 4096) == 0 { 129 dealloc_debug_log(klog_types::LogSource::Buddy, layout, ptr); 130 } else { 131 dealloc_debug_log(klog_types::LogSource::Slab, layout, ptr); 132 } 133 self.local_dealloc(ptr, layout); 134 } 135 } 136 137 /// 判断选择buddy分配器还是slab分配器 138 fn allocator_select_condition(layout: Layout) -> bool { 139 layout.size() > 2048 || !slab_init_state() 140 } 141 142 fn alloc_debug_log(source: LogSource, layout: Layout, ptr: *mut u8) { 143 mm_debug_log( 144 klog_types::AllocatorLogType::Alloc(AllocLogItem::new(layout, Some(ptr as usize), None)), 145 source, 146 ) 147 } 148 149 fn dealloc_debug_log(source: LogSource, layout: Layout, ptr: *mut u8) { 150 mm_debug_log( 151 klog_types::AllocatorLogType::Free(AllocLogItem::new(layout, Some(ptr as usize), None)), 152 source, 153 ) 154 } 155 156 /// 为内核slab分配器实现Allocator特性 157 // unsafe impl Allocator for KernelAllocator { 158 // fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 159 // let memory = unsafe {self.local_alloc(layout)}; 160 // if memory.is_null() { 161 // Err(AllocError) 162 // } else { 163 // let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) }; 164 // Ok(unsafe { NonNull::new_unchecked(slice) }) 165 // } 166 // } 167 168 // fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 169 // let memory = unsafe {self.local_alloc_zeroed(layout)}; 170 // if memory.is_null() { 171 // Err(AllocError) 172 // } else { 173 // let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) }; 174 // Ok(unsafe { NonNull::new_unchecked(slice) }) 175 // } 176 // } 177 178 // unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { 179 // self.local_dealloc(ptr.cast().as_ptr(), layout); 180 // } 181 // } 182 183 /// 内存分配错误处理函数 184 #[cfg(target_os = "none")] 185 #[alloc_error_handler] 186 pub fn global_alloc_err_handler(layout: Layout) -> ! { 187 panic!("global_alloc_error, layout: {:?}", layout); 188 } 189