xref: /DragonOS/kernel/src/mm/allocator/kernel_allocator.rs (revision 1ea2daad8121b77ed704e6d7c3a09f478147441d)
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