diff --git a/kernel/src/mm/bump.rs b/kernel/src/mm/bump.rs new file mode 100644 index 000000000..9ee83a041 --- /dev/null +++ b/kernel/src/mm/bump.rs @@ -0,0 +1,103 @@ +/// @Auther: Kong +/// @Date: 2023-03-27 06:54:08 +/// @FilePath: /DragonOS/kernel/src/mm/bump.rs +/// @Description: bump allocator线性分配器 +/// +use crate::mm::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}; +use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea}; +use core::marker::PhantomData; +// 线性分配器的实现 +pub struct BumpAllocator { + // 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。 + areas: &'static [PhysMemoryArea], + // 表示当前分配的物理内存的偏移量. + offset: usize, + // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。 + phantom: PhantomData, +} +// 为BumpAllocator实现FrameAllocator +impl BumpAllocator { + /// @brief: 创建一个线性分配器 + /// @param Fareas 当前的内存区域 + /// @param offset 当前的偏移量 + /// @return 分配器本身 + pub fn new(areas: &'static [PhysMemoryArea], offset: usize) -> Self { + Self { + areas, + offset, + phantom: PhantomData, + } + } + // @brief 获取页帧使用情况 + pub fn areas(&self) -> &'static [PhysMemoryArea] { + return self.areas; + } + // @brief 获取当前分配的物理内存的偏移量 + pub fn offset(&self) -> usize { + return self.offset; + } +} + +impl FrameAllocator for BumpAllocator { + /// @brief: 分配count个物理页帧 + /// @param mut self + /// @param count 分配的页帧数量 + /// @return 分配后的物理地址 + unsafe fn allocate(&mut self, count: PageFrameCount) -> Option { + let mut offset = self.offset(); + // 遍历所有的物理内存区域 + for area in self.areas().iter() { + // 将area的base地址与PAGE_SIZE对齐,对其时向上取整 + let area_base = (area.base.data() + MMA::PAGE_SIZE - 1) & !(MMA::PAGE_SIZE - 1); + // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整 + let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SIZE - 1); + + // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域 + if offset >= area_end { + continue; + } + + // 如果offset小于area_base 或者不小于area_base但小于area_end,说明当前的物理内存区域还没有分配过页帧,需要将offset调整到area_base + if offset < area_base || offset < area_end { + offset = area_base; + } + // 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE,说明当前的物理内存区域足以分配count个页帧 + if offset + count.data() * MMA::PAGE_SIZE <= area_end { + let res_page_phys = offset; + // 将offset增加至分配后的内存 + self.offset = offset + count.data() * MMA::PAGE_SIZE; + + return Some(PhysAddr(res_page_phys)); + } + } + return None; + } + + unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) { + // TODO: 支持释放页帧 + unimplemented!("BumpAllocator::free not implemented"); + } + /// @brief: 获取内存区域页帧的使用情况 + /// @param self + /// @return 页帧的使用情况 + unsafe fn usage(&self) -> PageFrameUsage { + let mut total = 0; + let mut used = 0; + for area in self.areas().iter() { + // 将area的base地址与PAGE_SIZE对齐,对其时向上取整 + let area_base = (area.base.data() + MMA::PAGE_SIZE - 1) & !(MMA::PAGE_SIZE - 1); + // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整 + let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SIZE - 1); + + total += (area_end - area_base) >> MMA::PAGE_SHIFT; + // 如果offset大于area_end,说明当前物理区域被分配完,都需要加到used中 + if self.offset >= area_end { + used += (area_end - area_base) >> MMA::PAGE_SHIFT; + } else { + used += (self.offset - area_base) >> MMA::PAGE_SHIFT; + } + } + let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total)); + return frame; + } +} diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 64988027a..344481ece 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -5,6 +5,8 @@ use crate::include::bindings::bindings::PAGE_OFFSET; pub mod allocator; pub mod gfp; pub mod mmio_buddy; +pub mod bump; +pub mod page_frame; /// @brief 将内核空间的虚拟地址转换为物理地址 #[inline(always)] @@ -166,7 +168,6 @@ pub trait MemoryManagementArch: Clone + Copy { unsafe fn write(address: VirtAddr, value: T) { ptr::write(address.data() as *mut T, value); } - /// @brief 刷新TLB中,关于指定虚拟地址的条目 unsafe fn invalidate_page(address: VirtAddr); diff --git a/kernel/src/mm/page_frame.rs b/kernel/src/mm/page_frame.rs new file mode 100644 index 000000000..2ae7ac0b3 --- /dev/null +++ b/kernel/src/mm/page_frame.rs @@ -0,0 +1,87 @@ +/// @Auther: Kong +/// @Date: 2023-03-27 11:57:07 +/// @FilePath: /DragonOS/kernel/src/mm/page_frame.rs +/// @Description: 页帧分配器 +use crate::mm::PhysAddr; + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +// 页帧使用的数量 +pub struct PageFrameCount(usize); + +impl PageFrameCount { + // @brief 初始化PageFrameCount + pub fn new(count: usize) -> Self { + return Self(count); + } + // @brief 获取页帧数量 + pub fn data(&self) -> usize { + return self.0; + } +} +// 页帧使用情况 +#[derive(Debug)] +pub struct PageFrameUsage { + used: PageFrameCount, + total: PageFrameCount, +} + +impl PageFrameUsage { + /// @brief: 初始化FrameUsage + /// @param {PageFrameCount} used 已使用的页帧数量 + /// @param {PageFrameCount} total 总的页帧数量 + pub fn new(used: PageFrameCount, total: PageFrameCount) -> Self { + return Self { used, total }; + } + // @brief 获取已使用的页帧数量 + pub fn used(&self) -> PageFrameCount { + return self.used; + } + // @brief 获取空闲的页帧数量 + pub fn free(&self) -> PageFrameCount { + return PageFrameCount(self.total.0 - self.used.0); + } + // @brief 获取总的页帧数量 + pub fn total(&self) -> PageFrameCount { + return self.total; + } +} +// 能够分配页帧的分配器需要实现的trait +pub trait FrameAllocator { + // @brief 分配count个页帧 + unsafe fn allocate(&mut self, count: PageFrameCount) -> Option; + + // @brief 通过地址释放count个页帧 + unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount); + // @brief 分配一个页帧 + unsafe fn allocate_one(&mut self) -> Option { + return self.allocate(PageFrameCount::new(1)); + } + // @brief 通过地址释放一个页帧 + unsafe fn free_one(&mut self, address: PhysAddr) { + return self.free(address, PageFrameCount::new(1)); + } + // @brief 获取页帧使用情况 + unsafe fn usage(&self) -> PageFrameUsage; +} +// @brief 通过一个 &mut T 的引用来对一个实现了 FrameAllocator trait 的类型进行调用,使代码更加灵活 +impl FrameAllocator for &mut T +where + T: FrameAllocator, +{ + unsafe fn allocate(&mut self, count: PageFrameCount) -> Option { + return T::allocate(self, count); + } + unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) { + return T::free(self, address, count); + } + unsafe fn allocate_one(&mut self) -> Option { + return T::allocate_one(self); + } + unsafe fn free_one(&mut self, address: PhysAddr) { + return T::free_one(self, address); + } + unsafe fn usage(&self) -> PageFrameUsage { + return T::usage(self); + } +}