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 分配器本身 30 pub fn new(offset: usize) -> Self { 31 Self { 32 offset, 33 phantom: PhantomData, 34 } 35 } 36 37 // @brief 获取当前分配的物理内存的偏移量 38 pub fn offset(&self) -> usize { 39 return self.offset; 40 } 41 42 /// 返回剩余的尚未被分配的物理内存区域 43 /// 44 /// ## 返回值 45 /// 46 /// - `result_area`:剩余的尚未被分配的物理内存区域的数组 47 /// - `offset_aligned`:返回的第一个物理内存区域内,已经分配的偏移量(相对于物理内存区域的已对齐的起始地址) 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)] 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 分配后的物理地址 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 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 页帧的使用情况 178 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