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::{
7     allocator::page_frame::{PhysPageFrame, PhysPageFrameIter},
8     init::{mm_init_status, MMInitStatus},
9     memblock::mem_block_manager,
10     no_init::pseudo_map_phys,
11     page::PageMapper,
12     MemoryManagementArch, PageTableKind, PhysAddr, PhysMemoryArea,
13 };
14 use core::marker::PhantomData;
15 
16 /// 线性分配器
17 pub struct BumpAllocator<MMA> {
18     // 表示当前分配的物理内存的偏移量.
19     offset: usize,
20     // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
21     phantom: PhantomData<MMA>,
22 }
23 
24 /// 为BumpAllocator实现FrameAllocator
25 impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
26     /// @brief: 创建一个线性分配器
27     /// @param Fareas 当前的内存区域
28     /// @param offset 当前的偏移量
29     /// @return 分配器本身
new(offset: usize) -> Self30     pub fn new(offset: usize) -> Self {
31         Self {
32             offset,
33             phantom: PhantomData,
34         }
35     }
36 
37     // @brief 获取当前分配的物理内存的偏移量
offset(&self) -> usize38     pub fn offset(&self) -> usize {
39         return self.offset;
40     }
41 
42     /// 返回剩余的尚未被分配的物理内存区域
43     ///
44     /// ## 返回值
45     ///
46     /// - `result_area`:剩余的尚未被分配的物理内存区域的数组
47     /// - `offset_aligned`:返回的第一个物理内存区域内,已经分配的偏移量(相对于物理内存区域的已对齐的起始地址)
remain_areas(&self, result_area: &mut [PhysMemoryArea]) -> Option<usize>48     pub fn remain_areas(&self, result_area: &mut [PhysMemoryArea]) -> Option<usize> {
49         let mut offset = self.offset();
50 
51         let iter = mem_block_manager().to_iter_available();
52 
53         let mut ret_offset_aligned = 0;
54 
55         let mut res_cnt = 0;
56 
57         let mut found_start = false;
58         // 遍历所有的物理内存区域
59         for area in iter {
60             if found_start == false {
61                 // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
62                 // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
63                 let area_base = area.area_base_aligned().data();
64                 // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
65                 // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
66                 let area_end = area.area_end_aligned().data();
67 
68                 // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
69                 if offset >= area_end {
70                     continue;
71                 }
72 
73                 // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
74                 if offset < area_base {
75                     offset = area_base;
76                 } else if offset < area_end {
77                     // 将offset对齐到PAGE_SIZE
78                     offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
79                 }
80                 // found
81                 if offset + 1 * MMA::PAGE_SIZE <= area_end {
82                     ret_offset_aligned = offset - area.area_base_aligned().data();
83                     found_start = true;
84                 }
85             }
86 
87             if found_start {
88                 if area.area_base_aligned() < area.area_end_aligned() {
89                     result_area[res_cnt] = area;
90                     res_cnt += 1;
91                 }
92             }
93         }
94 
95         let res_cnt = unsafe { Self::arch_remain_areas(result_area, res_cnt) };
96         if res_cnt == 0 {
97             return None;
98         } else {
99             return Some(ret_offset_aligned);
100         }
101     }
102 
103     #[inline(never)]
ensure_early_mapping(&self, start_paddr: PhysAddr, count: PageFrameCount)104     unsafe fn ensure_early_mapping(&self, start_paddr: PhysAddr, count: PageFrameCount) {
105         // 确保在内存管理未被初始化时,这地址已经被映射了
106         if mm_init_status() != MMInitStatus::Initialized {
107             // 映射涉及的页
108 
109             let iter = PhysPageFrameIter::new(
110                 PhysPageFrame::new(start_paddr),
111                 PhysPageFrame::new(start_paddr + count.bytes()),
112             );
113             let mapper =
114                 PageMapper::<MMA, _>::current(PageTableKind::Kernel, BumpAllocator::<MMA>::new(0));
115 
116             for p in iter {
117                 if let None = mapper.translate(MMA::phys_2_virt(p.phys_address()).unwrap()) {
118                     let vaddr = MMA::phys_2_virt(p.phys_address()).unwrap();
119                     pseudo_map_phys(vaddr, p.phys_address(), PageFrameCount::new(1));
120                 }
121             }
122         }
123     }
124 }
125 
126 impl<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
127     /// @brief: 分配count个物理页帧
128     /// @param  mut self
129     /// @param  count 分配的页帧数量
130     /// @return 分配后的物理地址
allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)>131     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
132         let mut offset = self.offset();
133 
134         let iter = mem_block_manager().to_iter_available();
135 
136         // 遍历所有的物理内存区域
137         for area in iter {
138             // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整
139             // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
140             let area_base = area.area_base_aligned().data();
141             // 将area的末尾地址与PAGE_SIZE对齐,对齐时向下取整
142             // let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
143             let area_end = area.area_end_aligned().data();
144 
145             // 如果offset大于area_end,说明当前的物理内存区域已经分配完了,需要跳到下一个物理内存区域
146             if offset >= area_end {
147                 continue;
148             }
149 
150             // 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧,将offset设置为area_base
151             if offset < area_base {
152                 offset = area_base;
153             } else if offset < area_end {
154                 // 将offset对齐到PAGE_SIZE
155                 offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
156             }
157             // 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE,说明当前的物理内存区域足以分配count个页帧
158             if offset + count.data() * MMA::PAGE_SIZE <= area_end {
159                 let res_page_phys = offset;
160                 // 将offset增加至分配后的内存
161                 self.offset = offset + count.data() * MMA::PAGE_SIZE;
162 
163                 let r = (PhysAddr(res_page_phys), count);
164                 self.ensure_early_mapping(r.0, r.1);
165                 return Some(r);
166             }
167         }
168         return None;
169     }
170 
free(&mut self, _address: PhysAddr, _count: PageFrameCount)171     unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
172         // TODO: 支持释放页帧
173         unimplemented!("BumpAllocator::free not implemented");
174     }
175     /// @brief: 获取内存区域页帧的使用情况
176     /// @param  self
177     /// @return 页帧的使用情况
usage(&self) -> PageFrameUsage178     unsafe fn usage(&self) -> PageFrameUsage {
179         let mut total = 0;
180         let mut used = 0;
181         let iter = mem_block_manager().to_iter_available();
182         for area in iter {
183             // 将area的base地址与PAGE_SIZE对齐,对其时向上取整
184             let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
185             // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整
186             let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
187 
188             total += (area_end - area_base) >> MMA::PAGE_SHIFT;
189             // 如果offset大于area_end,说明当前物理区域被分配完,都需要加到used中
190             if self.offset >= area_end {
191                 used += (area_end - area_base) >> MMA::PAGE_SHIFT;
192             } else if self.offset < area_base {
193                 // 如果offset小于area_base,说明当前物理区域还没有分配过页帧,都不需要加到used中
194                 continue;
195             } else {
196                 used += (self.offset - area_base) >> MMA::PAGE_SHIFT;
197             }
198         }
199         let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total));
200         return frame;
201     }
202 }
203