DragonOS/kernel/src/mm/allocator/kernel_allocator.rs
LoGin fba5623183
引入intertrait库,支持trait之间的互相转换 (#395)
* 能过编译(test还没法跑)

* 初始化intertrait转换库

* update license of intertrait
2023-10-02 20:46:19 +08:00

103 lines
3.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::{
arch::mm::LockedFrameAllocator,
libs::align::page_align_up,
mm::{MMArch, MemoryManagementArch, VirtAddr},
};
use core::{
alloc::{AllocError, GlobalAlloc, Layout},
intrinsics::unlikely,
ptr::NonNull,
};
use super::page_frame::{FrameAllocator, PageFrameCount};
/// 类kmalloc的分配器应当实现的trait
pub trait LocalAlloc {
unsafe fn local_alloc(&self, layout: Layout) -> *mut u8;
unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8;
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout);
}
pub struct KernelAllocator;
impl KernelAllocator {
unsafe fn alloc_in_buddy(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
// 计算需要申请的页数,向上取整
let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
let page_frame_count = PageFrameCount::new(count);
let (phy_addr, allocated_frame_count) = LockedFrameAllocator
.allocate(page_frame_count)
.ok_or(AllocError)?;
let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr).ok_or(AllocError)? };
if unlikely(virt_addr.is_null()) {
return Err(AllocError);
}
let slice = unsafe {
core::slice::from_raw_parts_mut(
virt_addr.data() as *mut u8,
allocated_frame_count.data() * MMArch::PAGE_SIZE,
)
};
return Ok(NonNull::from(slice));
}
unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
// 由于buddy分配的页数量是2的幂因此释放的时候也需要按照2的幂向上取整。
let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
let page_frame_count = PageFrameCount::new(count);
let phy_addr = MMArch::virt_2_phys(VirtAddr::new(ptr as usize)).unwrap();
LockedFrameAllocator.free(phy_addr, page_frame_count);
}
}
/// 为内核SLAB分配器实现LocalAlloc的trait
impl LocalAlloc for KernelAllocator {
unsafe fn local_alloc(&self, layout: Layout) -> *mut u8 {
return self
.alloc_in_buddy(layout)
.map(|x| x.as_mut_ptr() as *mut u8)
.unwrap_or(core::ptr::null_mut() as *mut u8);
}
unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8 {
return self
.alloc_in_buddy(layout)
.map(|x| {
let ptr: *mut u8 = x.as_mut_ptr();
core::ptr::write_bytes(ptr, 0, x.len());
ptr
})
.unwrap_or(core::ptr::null_mut() as *mut u8);
}
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) {
self.free_in_buddy(ptr, layout);
}
}
/// 为内核slab分配器实现GlobalAlloc特性
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
return self.local_alloc(layout);
// self.local_alloc_zeroed(layout, 0)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.local_alloc_zeroed(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.local_dealloc(ptr, layout);
}
}
/// 内存分配错误处理函数
#[cfg(target_os = "none")]
#[alloc_error_handler]
pub fn global_alloc_err_handler(layout: Layout) -> ! {
panic!("global_alloc_error, layout: {:?}", layout);
}