xref: /DragonOS/kernel/src/mm/allocator/bump.rs (revision 99dbf38d2e279ea70e9e186753fd37001dbb749f)
140fe15e0SLoGin /// @Auther: Kong
240fe15e0SLoGin /// @Date: 2023-03-27 06:54:08
340fe15e0SLoGin /// @FilePath: /DragonOS/kernel/src/mm/allocator/bump.rs
440fe15e0SLoGin /// @Description: bump allocator线性分配器
540fe15e0SLoGin use super::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
640fe15e0SLoGin use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea};
740fe15e0SLoGin use core::marker::PhantomData;
840fe15e0SLoGin 
940fe15e0SLoGin /// 线性分配器
1040fe15e0SLoGin pub struct BumpAllocator<MMA> {
1140fe15e0SLoGin     // 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。
1240fe15e0SLoGin     areas: &'static [PhysMemoryArea],
1340fe15e0SLoGin     // 表示当前分配的物理内存的偏移量.
1440fe15e0SLoGin     offset: usize,
1540fe15e0SLoGin     // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
1640fe15e0SLoGin     phantom: PhantomData<MMA>,
1740fe15e0SLoGin }
1840fe15e0SLoGin 
1940fe15e0SLoGin /// 为BumpAllocator实现FrameAllocator
2040fe15e0SLoGin impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
2140fe15e0SLoGin     /// @brief: 创建一个线性分配器
2240fe15e0SLoGin     /// @param Fareas 当前的内存区域
2340fe15e0SLoGin     /// @param offset 当前的偏移量
2440fe15e0SLoGin     /// @return 分配器本身
2540fe15e0SLoGin     pub fn new(areas: &'static [PhysMemoryArea], offset: usize) -> Self {
2640fe15e0SLoGin         Self {
2740fe15e0SLoGin             areas,
2840fe15e0SLoGin             offset,
2940fe15e0SLoGin             phantom: PhantomData,
3040fe15e0SLoGin         }
3140fe15e0SLoGin     }
3240fe15e0SLoGin     // @brief 获取页帧使用情况
3340fe15e0SLoGin     pub fn areas(&self) -> &'static [PhysMemoryArea] {
3440fe15e0SLoGin         return self.areas;
3540fe15e0SLoGin     }
3640fe15e0SLoGin     // @brief 获取当前分配的物理内存的偏移量
3740fe15e0SLoGin     pub fn offset(&self) -> usize {
3840fe15e0SLoGin         return self.offset;
3940fe15e0SLoGin     }
40*99dbf38dSLoGin 
41*99dbf38dSLoGin     /// 返回剩余的尚未被分配的物理内存区域
42*99dbf38dSLoGin     ///
43*99dbf38dSLoGin     /// ## 返回值
44*99dbf38dSLoGin     ///
45*99dbf38dSLoGin     /// - `result_area`:剩余的尚未被分配的物理内存区域的数组
46*99dbf38dSLoGin     /// - `offset_aligned`:返回的第一个物理内存区域内,已经分配的偏移量(相对于物理内存区域的已对齐的起始地址)
47*99dbf38dSLoGin     pub fn remain_areas(&self, result_area: &mut [PhysMemoryArea]) -> Option<usize> {
48*99dbf38dSLoGin         let mut offset = self.offset();
49*99dbf38dSLoGin 
50*99dbf38dSLoGin         let mut ret_offset_aligned = 0;
51*99dbf38dSLoGin 
52*99dbf38dSLoGin         let mut res_cnt = 0;
53*99dbf38dSLoGin 
54*99dbf38dSLoGin         // 遍历所有的物理内存区域
55*99dbf38dSLoGin         for i in 0..self.areas().len() {
56*99dbf38dSLoGin             let area = &self.areas()[i];
57*99dbf38dSLoGin             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
58*99dbf38dSLoGin             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
59*99dbf38dSLoGin             let area_base = area.area_base_aligned().data();
60*99dbf38dSLoGin             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
61*99dbf38dSLoGin             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
62*99dbf38dSLoGin             let area_end = area.area_end_aligned().data();
63*99dbf38dSLoGin 
64*99dbf38dSLoGin             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
65*99dbf38dSLoGin             if offset >= area_end {
66*99dbf38dSLoGin                 continue;
67*99dbf38dSLoGin             }
68*99dbf38dSLoGin 
69*99dbf38dSLoGin             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
70*99dbf38dSLoGin             if offset < area_base {
71*99dbf38dSLoGin                 offset = area_base;
72*99dbf38dSLoGin             } else if offset < area_end {
73*99dbf38dSLoGin                 // 将offset对齐到PAGE_SIZE
74*99dbf38dSLoGin                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
75*99dbf38dSLoGin             }
76*99dbf38dSLoGin             // found
77*99dbf38dSLoGin             if offset + 1 * MMA::PAGE_SIZE <= area_end {
78*99dbf38dSLoGin                 for j in i..self.areas().len() {
79*99dbf38dSLoGin                     if self.areas()[j].area_base_aligned() < self.areas()[j].area_end_aligned() {
80*99dbf38dSLoGin                         result_area[res_cnt] = self.areas()[j];
81*99dbf38dSLoGin                         res_cnt += 1;
82*99dbf38dSLoGin                     }
83*99dbf38dSLoGin                 }
84*99dbf38dSLoGin                 ret_offset_aligned = offset;
85*99dbf38dSLoGin                 break;
86*99dbf38dSLoGin             }
87*99dbf38dSLoGin         }
88*99dbf38dSLoGin 
89*99dbf38dSLoGin         let res_cnt = unsafe { Self::arch_remain_areas(result_area, res_cnt) };
90*99dbf38dSLoGin         if res_cnt == 0 {
91*99dbf38dSLoGin             return None;
92*99dbf38dSLoGin         } else {
93*99dbf38dSLoGin             return Some(ret_offset_aligned);
94*99dbf38dSLoGin         }
95*99dbf38dSLoGin     }
9640fe15e0SLoGin }
9740fe15e0SLoGin 
9840fe15e0SLoGin impl<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
9940fe15e0SLoGin     /// @brief: 分配count个物理页帧
10040fe15e0SLoGin     /// @param  mut self
10140fe15e0SLoGin     /// @param  count 分配的页帧数量
10240fe15e0SLoGin     /// @return 分配后的物理地址
10340fe15e0SLoGin     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
10440fe15e0SLoGin         let mut offset = self.offset();
10540fe15e0SLoGin         // 遍历所有的物理内存区域
10640fe15e0SLoGin         for area in self.areas().iter() {
10740fe15e0SLoGin             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
10840fe15e0SLoGin             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
109*99dbf38dSLoGin             let area_base = area.area_base_aligned().data();
11040fe15e0SLoGin             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
11140fe15e0SLoGin             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
112*99dbf38dSLoGin             let area_end = area.area_end_aligned().data();
11340fe15e0SLoGin 
11440fe15e0SLoGin             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
11540fe15e0SLoGin             if offset >= area_end {
11640fe15e0SLoGin                 continue;
11740fe15e0SLoGin             }
11840fe15e0SLoGin 
11940fe15e0SLoGin             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
12040fe15e0SLoGin             if offset < area_base {
12140fe15e0SLoGin                 offset = area_base;
12240fe15e0SLoGin             } else if offset < area_end {
12340fe15e0SLoGin                 // 将offset对齐到PAGE_SIZE
12440fe15e0SLoGin                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
12540fe15e0SLoGin             }
12640fe15e0SLoGin             // 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE,说明当前的物理内存区域足以分配count个页帧
12740fe15e0SLoGin             if offset + count.data() * MMA::PAGE_SIZE <= area_end {
12840fe15e0SLoGin                 let res_page_phys = offset;
12940fe15e0SLoGin                 // 将offset增加至分配后的内存
13040fe15e0SLoGin                 self.offset = offset + count.data() * MMA::PAGE_SIZE;
13140fe15e0SLoGin 
13240fe15e0SLoGin                 return Some((PhysAddr(res_page_phys), count));
13340fe15e0SLoGin             }
13440fe15e0SLoGin         }
13540fe15e0SLoGin         return None;
13640fe15e0SLoGin     }
13740fe15e0SLoGin 
13840fe15e0SLoGin     unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
13940fe15e0SLoGin         // TODO: 支持释放页帧
14040fe15e0SLoGin         unimplemented!("BumpAllocator::free not implemented");
14140fe15e0SLoGin     }
14240fe15e0SLoGin     /// @brief: 获取内存区域页帧的使用情况
14340fe15e0SLoGin     /// @param  self
14440fe15e0SLoGin     /// @return 页帧的使用情况
14540fe15e0SLoGin     unsafe fn usage(&self) -> PageFrameUsage {
14640fe15e0SLoGin         let mut total = 0;
14740fe15e0SLoGin         let mut used = 0;
14840fe15e0SLoGin         for area in self.areas().iter() {
14940fe15e0SLoGin             // 将area的base地址与PAGE_SIZE对齐,对其时向上取整
15040fe15e0SLoGin             let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
15140fe15e0SLoGin             // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整
15240fe15e0SLoGin             let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
15340fe15e0SLoGin 
15440fe15e0SLoGin             total += (area_end - area_base) >> MMA::PAGE_SHIFT;
15540fe15e0SLoGin             // 如果offset大于area_end,说明当前物理区域被分配完,都需要加到used中
15640fe15e0SLoGin             if self.offset >= area_end {
15740fe15e0SLoGin                 used += (area_end - area_base) >> MMA::PAGE_SHIFT;
15840fe15e0SLoGin             } else if self.offset < area_base {
15940fe15e0SLoGin                 // 如果offset小于area_base,说明当前物理区域还没有分配过页帧,都不需要加到used中
16040fe15e0SLoGin                 continue;
16140fe15e0SLoGin             } else {
16240fe15e0SLoGin                 used += (self.offset - area_base) >> MMA::PAGE_SHIFT;
16340fe15e0SLoGin             }
16440fe15e0SLoGin         }
16540fe15e0SLoGin         let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total));
16640fe15e0SLoGin         return frame;
16740fe15e0SLoGin     }
16840fe15e0SLoGin }
169