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