xref: /DragonOS/kernel/src/mm/allocator/bump.rs (revision 1a72a751b18cf5bbe7b5b9e91aff530de0c18501)
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