xref: /DragonOS/kernel/src/mm/allocator/kernel_allocator.rs (revision f2022a8a1cc4a8e2a85e9061e036e9c491a2fa00)
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() as *mut u8)
65             .unwrap_or(core::ptr::null_mut() as *mut u8);
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() as *mut u8);
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(
90                 layout.clone(),
91                 Some(r as usize),
92                 None,
93             )),
94             klog_types::LogSource::Buddy,
95         );
96 
97         return r;
98 
99         // self.local_alloc_zeroed(layout, 0)
100     }
101 
102     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
103         let r = self.local_alloc_zeroed(layout);
104 
105         mm_debug_log(
106             klog_types::AllocatorLogType::AllocZeroed(AllocLogItem::new(
107                 layout.clone(),
108                 Some(r as usize),
109                 None,
110             )),
111             klog_types::LogSource::Buddy,
112         );
113 
114         return r;
115     }
116 
117     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
118         mm_debug_log(
119             klog_types::AllocatorLogType::Free(AllocLogItem::new(
120                 layout.clone(),
121                 Some(ptr as usize),
122                 None,
123             )),
124             klog_types::LogSource::Buddy,
125         );
126 
127         self.local_dealloc(ptr, layout);
128     }
129 }
130 
131 /// 为内核slab分配器实现Allocator特性
132 // unsafe impl Allocator for KernelAllocator {
133 //     fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
134 //         let memory = unsafe {self.local_alloc(layout)};
135 //         if memory.is_null() {
136 //             Err(AllocError)
137 //         } else {
138 //             let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) };
139 //             Ok(unsafe { NonNull::new_unchecked(slice) })
140 //         }
141 //     }
142 
143 //     fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
144 //         let memory = unsafe {self.local_alloc_zeroed(layout)};
145 //         if memory.is_null() {
146 //             Err(AllocError)
147 //         } else {
148 //             let slice = unsafe { core::slice::from_raw_parts_mut(memory, layout.size()) };
149 //             Ok(unsafe { NonNull::new_unchecked(slice) })
150 //         }
151 //     }
152 
153 //     unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
154 //         self.local_dealloc(ptr.cast().as_ptr(), layout);
155 //     }
156 // }
157 
158 /// 内存分配错误处理函数
159 #[cfg(target_os = "none")]
160 #[alloc_error_handler]
161 pub fn global_alloc_err_handler(layout: Layout) -> ! {
162     panic!("global_alloc_error, layout: {:?}", layout);
163 }
164