xref: /DragonOS/kernel/src/mm/allocator/bump.rs (revision 7a29d4fcbcd89a226289c7bf541c2c78623de3ad)
1 /// @Auther: Kong
2 /// @Date: 2023-03-27 06:54:08
3 /// @FilePath: /DragonOS/kernel/src/mm/allocator/bump.rs
4 /// @Description: bump allocator线性分配器
5 use super::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
6 use crate::mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr, PhysMemoryArea};
7 use core::marker::PhantomData;
8 
9 /// 线性分配器
10 pub struct BumpAllocator<MMA> {
11     // 表示当前分配的物理内存的偏移量.
12     offset: usize,
13     // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
14     phantom: PhantomData<MMA>,
15 }
16 
17 /// 为BumpAllocator实现FrameAllocator
18 impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
19     /// @brief: 创建一个线性分配器
20     /// @param Fareas 当前的内存区域
21     /// @param offset 当前的偏移量
22     /// @return 分配器本身
23     pub fn new(offset: usize) -> Self {
24         Self {
25             offset,
26             phantom: PhantomData,
27         }
28     }
29 
30     // @brief 获取当前分配的物理内存的偏移量
31     pub fn offset(&self) -> usize {
32         return self.offset;
33     }
34 
35     /// 返回剩余的尚未被分配的物理内存区域
36     ///
37     /// ## 返回值
38     ///
39     /// - `result_area`:剩余的尚未被分配的物理内存区域的数组
40     /// - `offset_aligned`:返回的第一个物理内存区域内,已经分配的偏移量(相对于物理内存区域的已对齐的起始地址)
41     pub fn remain_areas(&self, result_area: &mut [PhysMemoryArea]) -> Option<usize> {
42         let mut offset = self.offset();
43 
44         let mut ret_offset_aligned = 0;
45 
46         let mut res_cnt = 0;
47 
48         let total_num = mem_block_manager().total_initial_memory_regions();
49         // 遍历所有的物理内存区域
50         for i in 0..total_num {
51             let area = mem_block_manager().get_initial_memory_region(i).unwrap();
52             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
53             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
54             let area_base = area.area_base_aligned().data();
55             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
56             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
57             let area_end = area.area_end_aligned().data();
58 
59             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
60             if offset >= area_end {
61                 continue;
62             }
63 
64             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
65             if offset < area_base {
66                 offset = area_base;
67             } else if offset < area_end {
68                 // 将offset对齐到PAGE_SIZE
69                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
70             }
71             // found
72             if offset + 1 * MMA::PAGE_SIZE <= area_end {
73                 for j in i..total_num {
74                     let aj = mem_block_manager().get_initial_memory_region(j).unwrap();
75                     if aj.area_base_aligned() < aj.area_end_aligned() {
76                         result_area[res_cnt] = aj;
77                         res_cnt += 1;
78                     }
79                 }
80                 ret_offset_aligned = offset;
81                 break;
82             }
83         }
84 
85         let res_cnt = unsafe { Self::arch_remain_areas(result_area, res_cnt) };
86         if res_cnt == 0 {
87             return None;
88         } else {
89             return Some(ret_offset_aligned);
90         }
91     }
92 }
93 
94 impl<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
95     /// @brief: 分配count个物理页帧
96     /// @param  mut self
97     /// @param  count 分配的页帧数量
98     /// @return 分配后的物理地址
99     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
100         let mut offset = self.offset();
101 
102         let iter = mem_block_manager().to_iter();
103 
104         // 遍历所有的物理内存区域
105         for area in iter {
106             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
107             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
108             let area_base = area.area_base_aligned().data();
109             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
110             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
111             let area_end = area.area_end_aligned().data();
112 
113             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
114             if offset >= area_end {
115                 continue;
116             }
117 
118             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
119             if offset < area_base {
120                 offset = area_base;
121             } else if offset < area_end {
122                 // 将offset对齐到PAGE_SIZE
123                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
124             }
125             // 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE,说明当前的物理内存区域足以分配count个页帧
126             if offset + count.data() * MMA::PAGE_SIZE <= area_end {
127                 let res_page_phys = offset;
128                 // 将offset增加至分配后的内存
129                 self.offset = offset + count.data() * MMA::PAGE_SIZE;
130 
131                 return Some((PhysAddr(res_page_phys), count));
132             }
133         }
134         return None;
135     }
136 
137     unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
138         // TODO: 支持释放页帧
139         unimplemented!("BumpAllocator::free not implemented");
140     }
141     /// @brief: 获取内存区域页帧的使用情况
142     /// @param  self
143     /// @return 页帧的使用情况
144     unsafe fn usage(&self) -> PageFrameUsage {
145         let mut total = 0;
146         let mut used = 0;
147         let iter = mem_block_manager().to_iter();
148         for area in iter {
149             // 将area的base地址与PAGE_SIZE对齐,对其时向上取整
150             let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
151             // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整
152             let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
153 
154             total += (area_end - area_base) >> MMA::PAGE_SHIFT;
155             // 如果offset大于area_end,说明当前物理区域被分配完,都需要加到used中
156             if self.offset >= area_end {
157                 used += (area_end - area_base) >> MMA::PAGE_SHIFT;
158             } else if self.offset < area_base {
159                 // 如果offset小于area_base,说明当前物理区域还没有分配过页帧,都不需要加到used中
160                 continue;
161             } else {
162                 used += (self.offset - area_base) >> MMA::PAGE_SHIFT;
163             }
164         }
165         let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total));
166         return frame;
167     }
168 }
169