xref: /DragonOS/kernel/src/mm/allocator/kernel_allocator.rs (revision 40fe15e0953f989ccfeb74826d61621d43dea6bb)
1 use crate::{
2     arch::mm::LockedFrameAllocator,
3     libs::align::page_align_up,
4     mm::{MMArch, MemoryManagementArch, VirtAddr},
5 };
6 
7 use core::{
8     alloc::{AllocError, GlobalAlloc, Layout},
9     intrinsics::unlikely,
10     ptr::NonNull,
11 };
12 
13 use super::page_frame::{FrameAllocator, PageFrameCount};
14 
15 /// 类kmalloc的分配器应当实现的trait
16 pub trait LocalAlloc {
17     unsafe fn local_alloc(&self, layout: Layout) -> *mut u8;
18     unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8;
19     unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout);
20 }
21 
22 pub struct KernelAllocator;
23 
24 impl KernelAllocator {
25     unsafe fn alloc_in_buddy(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
26         // 计算需要申请的页数,向上取整
27         let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
28         let page_frame_count = PageFrameCount::new(count);
29         let (phy_addr, allocated_frame_count) = LockedFrameAllocator
30             .allocate(page_frame_count)
31             .ok_or(AllocError)?;
32 
33         let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr).ok_or(AllocError)? };
34         if unlikely(virt_addr.is_null()) {
35             return Err(AllocError);
36         }
37 
38         let slice = unsafe {
39             core::slice::from_raw_parts_mut(
40                 virt_addr.data() as *mut u8,
41                 allocated_frame_count.data() * MMArch::PAGE_SIZE,
42             )
43         };
44         return Ok(NonNull::from(slice));
45     }
46 
47     unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
48         // 由于buddy分配的页数量是2的幂,因此释放的时候也需要按照2的幂向上取整。
49         let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
50         let page_frame_count = PageFrameCount::new(count);
51         let phy_addr = MMArch::virt_2_phys(VirtAddr::new(ptr as usize)).unwrap();
52         LockedFrameAllocator.free(phy_addr, page_frame_count);
53     }
54 }
55 
56 /// 为内核SLAB分配器实现LocalAlloc的trait
57 impl LocalAlloc for KernelAllocator {
58     unsafe fn local_alloc(&self, layout: Layout) -> *mut u8 {
59         return self
60             .alloc_in_buddy(layout)
61             .map(|x| x.as_mut_ptr() as *mut u8)
62             .unwrap_or(core::ptr::null_mut() as *mut u8);
63     }
64 
65     unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8 {
66         return self
67             .alloc_in_buddy(layout)
68             .map(|x| {
69                 let ptr: *mut u8 = x.as_mut_ptr();
70                 core::ptr::write_bytes(ptr, 0, x.len());
71                 ptr
72             })
73             .unwrap_or(core::ptr::null_mut() as *mut u8);
74     }
75 
76     unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) {
77         self.free_in_buddy(ptr, layout);
78     }
79 }
80 
81 /// 为内核slab分配器实现GlobalAlloc特性
82 unsafe impl GlobalAlloc for KernelAllocator {
83     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
84         return self.local_alloc(layout);
85         // self.local_alloc_zeroed(layout, 0)
86     }
87 
88     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
89         self.local_alloc_zeroed(layout)
90     }
91 
92     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
93         self.local_dealloc(ptr, layout);
94     }
95 }
96 
97 /// 内存分配错误处理函数
98 #[alloc_error_handler]
99 pub fn global_alloc_err_handler(layout: Layout) -> ! {
100     panic!("global_alloc_error, layout: {:?}", layout);
101 }
102