xref: /DragonOS/kernel/src/mm/allocator/kernel_allocator.rs (revision b5b571e02693d91eb6918d3b7561e088c3e7ee81)
1 use klog_types::AllocLogItem;
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::page_frame::{FrameAllocator, PageFrameCount};
17 
18 /// 类kmalloc的分配器应当实现的trait
19 pub trait LocalAlloc {
20     unsafe fn local_alloc(&self, layout: Layout) -> *mut u8;
21     unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8;
22     unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout);
23 }
24 
25 pub struct KernelAllocator;
26 
27 impl KernelAllocator {
28     unsafe fn alloc_in_buddy(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
29         // 计算需要申请的页数,向上取整
30         let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
31         let page_frame_count = PageFrameCount::new(count);
32         let (phy_addr, allocated_frame_count) = LockedFrameAllocator
33             .allocate(page_frame_count)
34             .ok_or(AllocError)?;
35 
36         let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr).ok_or(AllocError)? };
37         if unlikely(virt_addr.is_null()) {
38             return Err(AllocError);
39         }
40 
41         let slice = unsafe {
42             core::slice::from_raw_parts_mut(
43                 virt_addr.data() as *mut u8,
44                 allocated_frame_count.data() * MMArch::PAGE_SIZE,
45             )
46         };
47         return Ok(NonNull::from(slice));
48     }
49 
50     unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
51         // 由于buddy分配的页数量是2的幂,因此释放的时候也需要按照2的幂向上取整。
52         let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
53         let page_frame_count = PageFrameCount::new(count);
54         let phy_addr = MMArch::virt_2_phys(VirtAddr::new(ptr as usize)).unwrap();
55         LockedFrameAllocator.free(phy_addr, page_frame_count);
56     }
57 }
58 
59 /// 为内核分配器实现LocalAlloc的trait
60 impl LocalAlloc for KernelAllocator {
61     unsafe fn local_alloc(&self, layout: Layout) -> *mut u8 {
62         return self
63             .alloc_in_buddy(layout)
64             .map(|x| x.as_mut_ptr())
65             .unwrap_or(core::ptr::null_mut());
66     }
67 
68     unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8 {
69         return self
70             .alloc_in_buddy(layout)
71             .map(|x| {
72                 let ptr: *mut u8 = x.as_mut_ptr();
73                 core::ptr::write_bytes(ptr, 0, x.len());
74                 ptr
75             })
76             .unwrap_or(core::ptr::null_mut());
77     }
78 
79     unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) {
80         self.free_in_buddy(ptr, layout);
81     }
82 }
83 
84 /// 为内核slab分配器实现GlobalAlloc特性
85 unsafe impl GlobalAlloc for KernelAllocator {
86     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
87         let r = self.local_alloc_zeroed(layout);
88         mm_debug_log(
89             klog_types::AllocatorLogType::Alloc(AllocLogItem::new(layout, Some(r as usize), None)),
90             klog_types::LogSource::Buddy,
91         );
92 
93         return r;
94 
95         // self.local_alloc_zeroed(layout, 0)
96     }
97 
98     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
99         let r = self.local_alloc_zeroed(layout);
100 
101         mm_debug_log(
102             klog_types::AllocatorLogType::AllocZeroed(AllocLogItem::new(
103                 layout,
104                 Some(r as usize),
105                 None,
106             )),
107             klog_types::LogSource::Buddy,
108         );
109 
110         return r;
111     }
112 
113     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
114         mm_debug_log(
115             klog_types::AllocatorLogType::Free(AllocLogItem::new(layout, Some(ptr as usize), None)),
116             klog_types::LogSource::Buddy,
117         );
118 
119         self.local_dealloc(ptr, layout);
120     }
121 }
122 
123 /// 为内核slab分配器实现Allocator特性
124 // unsafe impl Allocator for KernelAllocator {
125 //     fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
126 //         let memory = unsafe {self.local_alloc(layout)};
127 //         if memory.is_null() {
128 //             Err(AllocError)
129 //         } else {
130 //             let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) };
131 //             Ok(unsafe { NonNull::new_unchecked(slice) })
132 //         }
133 //     }
134 
135 //     fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
136 //         let memory = unsafe {self.local_alloc_zeroed(layout)};
137 //         if memory.is_null() {
138 //             Err(AllocError)
139 //         } else {
140 //             let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) };
141 //             Ok(unsafe { NonNull::new_unchecked(slice) })
142 //         }
143 //     }
144 
145 //     unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
146 //         self.local_dealloc(ptr.cast().as_ptr(), layout);
147 //     }
148 // }
149 
150 /// 内存分配错误处理函数
151 #[cfg(target_os = "none")]
152 #[alloc_error_handler]
153 pub fn global_alloc_err_handler(layout: Layout) -> ! {
154     panic!("global_alloc_error, layout: {:?}", layout);
155 }
156