xref: /DragonOS/kernel/src/mm/allocator/bump.rs (revision 40fe15e0953f989ccfeb74826d61621d43dea6bb)
1*40fe15e0SLoGin /// @Auther: Kong
2*40fe15e0SLoGin /// @Date: 2023-03-27 06:54:08
3*40fe15e0SLoGin /// @FilePath: /DragonOS/kernel/src/mm/allocator/bump.rs
4*40fe15e0SLoGin /// @Description: bump allocator线性分配器
5*40fe15e0SLoGin use super::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
6*40fe15e0SLoGin use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea};
7*40fe15e0SLoGin use core::marker::PhantomData;
8*40fe15e0SLoGin 
9*40fe15e0SLoGin /// 线性分配器
10*40fe15e0SLoGin pub struct BumpAllocator<MMA> {
11*40fe15e0SLoGin     // 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。
12*40fe15e0SLoGin     areas: &'static [PhysMemoryArea],
13*40fe15e0SLoGin     // 表示当前分配的物理内存的偏移量.
14*40fe15e0SLoGin     offset: usize,
15*40fe15e0SLoGin     // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
16*40fe15e0SLoGin     phantom: PhantomData<MMA>,
17*40fe15e0SLoGin }
18*40fe15e0SLoGin 
19*40fe15e0SLoGin /// 为BumpAllocator实现FrameAllocator
20*40fe15e0SLoGin impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
21*40fe15e0SLoGin     /// @brief: 创建一个线性分配器
22*40fe15e0SLoGin     /// @param Fareas 当前的内存区域
23*40fe15e0SLoGin     /// @param offset 当前的偏移量
24*40fe15e0SLoGin     /// @return 分配器本身
25*40fe15e0SLoGin     pub fn new(areas: &'static [PhysMemoryArea], offset: usize) -> Self {
26*40fe15e0SLoGin         Self {
27*40fe15e0SLoGin             areas,
28*40fe15e0SLoGin             offset,
29*40fe15e0SLoGin             phantom: PhantomData,
30*40fe15e0SLoGin         }
31*40fe15e0SLoGin     }
32*40fe15e0SLoGin     // @brief 获取页帧使用情况
33*40fe15e0SLoGin     pub fn areas(&self) -> &'static [PhysMemoryArea] {
34*40fe15e0SLoGin         return self.areas;
35*40fe15e0SLoGin     }
36*40fe15e0SLoGin     // @brief 获取当前分配的物理内存的偏移量
37*40fe15e0SLoGin     pub fn offset(&self) -> usize {
38*40fe15e0SLoGin         return self.offset;
39*40fe15e0SLoGin     }
40*40fe15e0SLoGin }
41*40fe15e0SLoGin 
42*40fe15e0SLoGin impl<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
43*40fe15e0SLoGin     /// @brief: 分配count个物理页帧
44*40fe15e0SLoGin     /// @param  mut self
45*40fe15e0SLoGin     /// @param  count 分配的页帧数量
46*40fe15e0SLoGin     /// @return 分配后的物理地址
47*40fe15e0SLoGin     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
48*40fe15e0SLoGin         let mut offset = self.offset();
49*40fe15e0SLoGin         // 遍历所有的物理内存区域
50*40fe15e0SLoGin         for area in self.areas().iter() {
51*40fe15e0SLoGin             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
52*40fe15e0SLoGin             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
53*40fe15e0SLoGin             let area_base = (area.base.data() + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
54*40fe15e0SLoGin             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
55*40fe15e0SLoGin             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
56*40fe15e0SLoGin             let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SIZE - 1);
57*40fe15e0SLoGin 
58*40fe15e0SLoGin             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
59*40fe15e0SLoGin             if offset >= area_end {
60*40fe15e0SLoGin                 continue;
61*40fe15e0SLoGin             }
62*40fe15e0SLoGin 
63*40fe15e0SLoGin             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
64*40fe15e0SLoGin             if offset < area_base {
65*40fe15e0SLoGin                 offset = area_base;
66*40fe15e0SLoGin             } else if offset < area_end {
67*40fe15e0SLoGin                 // 将offset对齐到PAGE_SIZE
68*40fe15e0SLoGin                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
69*40fe15e0SLoGin             }
70*40fe15e0SLoGin             // 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE,说明当前的物理内存区域足以分配count个页帧
71*40fe15e0SLoGin             if offset + count.data() * MMA::PAGE_SIZE <= area_end {
72*40fe15e0SLoGin                 let res_page_phys = offset;
73*40fe15e0SLoGin                 // 将offset增加至分配后的内存
74*40fe15e0SLoGin                 self.offset = offset + count.data() * MMA::PAGE_SIZE;
75*40fe15e0SLoGin 
76*40fe15e0SLoGin                 return Some((PhysAddr(res_page_phys), count));
77*40fe15e0SLoGin             }
78*40fe15e0SLoGin         }
79*40fe15e0SLoGin         return None;
80*40fe15e0SLoGin     }
81*40fe15e0SLoGin 
82*40fe15e0SLoGin     unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
83*40fe15e0SLoGin         // TODO: 支持释放页帧
84*40fe15e0SLoGin         unimplemented!("BumpAllocator::free not implemented");
85*40fe15e0SLoGin     }
86*40fe15e0SLoGin     /// @brief: 获取内存区域页帧的使用情况
87*40fe15e0SLoGin     /// @param  self
88*40fe15e0SLoGin     /// @return 页帧的使用情况
89*40fe15e0SLoGin     unsafe fn usage(&self) -> PageFrameUsage {
90*40fe15e0SLoGin         let mut total = 0;
91*40fe15e0SLoGin         let mut used = 0;
92*40fe15e0SLoGin         for area in self.areas().iter() {
93*40fe15e0SLoGin             // 将area的base地址与PAGE_SIZE对齐,对其时向上取整
94*40fe15e0SLoGin             let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
95*40fe15e0SLoGin             // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整
96*40fe15e0SLoGin             let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
97*40fe15e0SLoGin 
98*40fe15e0SLoGin             total += (area_end - area_base) >> MMA::PAGE_SHIFT;
99*40fe15e0SLoGin             // 如果offset大于area_end,说明当前物理区域被分配完,都需要加到used中
100*40fe15e0SLoGin             if self.offset >= area_end {
101*40fe15e0SLoGin                 used += (area_end - area_base) >> MMA::PAGE_SHIFT;
102*40fe15e0SLoGin             } else if self.offset < area_base {
103*40fe15e0SLoGin                 // 如果offset小于area_base,说明当前物理区域还没有分配过页帧,都不需要加到used中
104*40fe15e0SLoGin                 continue;
105*40fe15e0SLoGin             } else {
106*40fe15e0SLoGin                 used += (self.offset - area_base) >> MMA::PAGE_SHIFT;
107*40fe15e0SLoGin             }
108*40fe15e0SLoGin         }
109*40fe15e0SLoGin         let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total));
110*40fe15e0SLoGin         return frame;
111*40fe15e0SLoGin     }
112*40fe15e0SLoGin }
113