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