Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions kernel/src/mm/bump.rs
Original file line number Diff line number Diff line change
@@ -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<MMA> {
// 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。
areas: &'static [PhysMemoryArea],
// 表示当前分配的物理内存的偏移量.
offset: usize,
// 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
phantom: PhantomData<MMA>,
}
// 为BumpAllocator实现FrameAllocator
impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
/// @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<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
/// @brief: 分配count个物理页帧
/// @param mut self
/// @param count 分配的页帧数量
/// @return 分配后的物理地址
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<PhysAddr> {
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;
}
}
3 changes: 2 additions & 1 deletion kernel/src/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -166,7 +168,6 @@ pub trait MemoryManagementArch: Clone + Copy {
unsafe fn write<T>(address: VirtAddr, value: T) {
ptr::write(address.data() as *mut T, value);
}

/// @brief 刷新TLB中,关于指定虚拟地址的条目
unsafe fn invalidate_page(address: VirtAddr);

Expand Down
87 changes: 87 additions & 0 deletions kernel/src/mm/page_frame.rs
Original file line number Diff line number Diff line change
@@ -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<PhysAddr>;

// @brief 通过地址释放count个页帧
unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount);
// @brief 分配一个页帧
unsafe fn allocate_one(&mut self) -> Option<PhysAddr> {
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<T> FrameAllocator for &mut T
where
T: FrameAllocator,
{
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<PhysAddr> {
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<PhysAddr> {
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);
}
}