xref: /DragonOS/kernel/src/mm/mmio_buddy.rs (revision 2dd9f0c7503d1a325713764fedbce06fcab3a06b)
1a7eb62a4Shoumkh use crate::libs::spinlock::{SpinLock, SpinLockGuard};
240fe15e0SLoGin use crate::mm::kernel_mapper::KernelMapper;
3676b8ef6SMork use crate::syscall::SystemError;
4c2481452Shoumkh use crate::{
5c2481452Shoumkh     arch::asm::current::current_pcb,
640fe15e0SLoGin     include::bindings::bindings::{vm_flags_t, PAGE_1G_SHIFT, PAGE_4K_SHIFT, PAGE_4K_SIZE},
740fe15e0SLoGin     kdebug,
840fe15e0SLoGin     mm::{MMArch, MemoryManagementArch},
9c2481452Shoumkh };
1040fe15e0SLoGin use crate::{kerror, kinfo, kwarn};
1140fe15e0SLoGin use alloc::{collections::LinkedList, vec::Vec};
1240fe15e0SLoGin use core::mem;
1340fe15e0SLoGin use core::mem::MaybeUninit;
14*2dd9f0c7SLoGin use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
1540fe15e0SLoGin 
16*2dd9f0c7SLoGin use super::page::PageFlags;
17*2dd9f0c7SLoGin use super::{PhysAddr, VirtAddr};
18c2481452Shoumkh 
19c2481452Shoumkh // 最大的伙伴块的幂
20c2481452Shoumkh const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT;
21c2481452Shoumkh // 最小的伙伴块的幂
22c2481452Shoumkh const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT;
23c2481452Shoumkh // 内存池数组的范围
24c2481452Shoumkh const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
25c2481452Shoumkh 
2640fe15e0SLoGin const MMIO_BASE: VirtAddr = VirtAddr::new(0xffffa10000000000);
2740fe15e0SLoGin const MMIO_TOP: VirtAddr = VirtAddr::new(0xffffa20000000000);
2840fe15e0SLoGin 
2940fe15e0SLoGin const PAGE_1G_SIZE: usize = 1 << 30;
3040fe15e0SLoGin 
3140fe15e0SLoGin static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
3240fe15e0SLoGin 
3340fe15e0SLoGin pub fn mmio_pool() -> &'static mut MmioBuddyMemPool {
3440fe15e0SLoGin     unsafe { __MMIO_POOL.as_mut().unwrap() }
35c2481452Shoumkh }
36c2481452Shoumkh 
37c2481452Shoumkh pub enum MmioResult {
38c2481452Shoumkh     SUCCESS,
39c2481452Shoumkh     EINVAL,
40c2481452Shoumkh     ENOFOUND,
41c2481452Shoumkh     WRONGEXP,
42c2481452Shoumkh     ISEMPTY,
43c2481452Shoumkh }
44c2481452Shoumkh 
45c2481452Shoumkh /// @brief buddy内存池
4640fe15e0SLoGin #[derive(Debug)]
47c2481452Shoumkh pub struct MmioBuddyMemPool {
4840fe15e0SLoGin     pool_start_addr: VirtAddr,
4940fe15e0SLoGin     pool_size: usize,
50c2481452Shoumkh     free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
51c2481452Shoumkh }
5240fe15e0SLoGin 
53c2481452Shoumkh impl MmioBuddyMemPool {
54c2481452Shoumkh     fn new() -> Self {
5540fe15e0SLoGin         let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
5640fe15e0SLoGin             MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
5740fe15e0SLoGin         for i in 0..MMIO_BUDDY_REGION_COUNT {
5840fe15e0SLoGin             free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
5940fe15e0SLoGin         }
6040fe15e0SLoGin         let free_regions = unsafe {
6140fe15e0SLoGin             mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
6240fe15e0SLoGin                 free_regions,
6340fe15e0SLoGin             )
64c2481452Shoumkh         };
6540fe15e0SLoGin 
6640fe15e0SLoGin         let pool = MmioBuddyMemPool {
6740fe15e0SLoGin             pool_start_addr: MMIO_BASE,
6840fe15e0SLoGin             pool_size: MMIO_TOP - MMIO_BASE,
6940fe15e0SLoGin             free_regions,
7040fe15e0SLoGin         };
7140fe15e0SLoGin         kdebug!("MMIO buddy pool init: created");
7240fe15e0SLoGin 
7340fe15e0SLoGin         let cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) >> 30;
7440fe15e0SLoGin         let mut vaddr_base = MMIO_BASE;
7540fe15e0SLoGin         kdebug!("total 1G blocks: {cnt_1g_blocks}");
7640fe15e0SLoGin         for _i in 0..cnt_1g_blocks {
7740fe15e0SLoGin             compiler_fence(Ordering::SeqCst);
7840fe15e0SLoGin             match pool.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
7940fe15e0SLoGin                 Ok(_) => {
8040fe15e0SLoGin                     vaddr_base += PAGE_1G_SIZE;
8140fe15e0SLoGin                 }
8240fe15e0SLoGin                 Err(_) => {
8340fe15e0SLoGin                     panic!("MMIO buddy pool init failed");
8440fe15e0SLoGin                 }
8540fe15e0SLoGin             }
8640fe15e0SLoGin         }
8740fe15e0SLoGin         kdebug!("MMIO buddy pool init success");
8840fe15e0SLoGin         return pool;
89c2481452Shoumkh     }
90c2481452Shoumkh 
91c2481452Shoumkh     /// @brief 创建新的地址区域结构体
92c2481452Shoumkh     ///
93c2481452Shoumkh     /// @param vaddr 虚拟地址
94c2481452Shoumkh     ///
95c2481452Shoumkh     /// @return 创建好的地址区域结构体
9640fe15e0SLoGin     fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
9740fe15e0SLoGin         // kdebug!("create_region for vaddr: {vaddr:?}");
9840fe15e0SLoGin 
9940fe15e0SLoGin         let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
10040fe15e0SLoGin 
10140fe15e0SLoGin         // kdebug!("create_region for vaddr: {vaddr:?} OK!!!");
102c2481452Shoumkh         return region;
103c2481452Shoumkh     }
104c2481452Shoumkh 
105c2481452Shoumkh     /// @brief 将内存块归还给buddy
106c2481452Shoumkh     ///
107c2481452Shoumkh     /// @param vaddr 虚拟地址
108c2481452Shoumkh     ///
109c2481452Shoumkh     /// @param exp 内存空间的大小(2^exp)
110c2481452Shoumkh     ///
111c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
112c2481452Shoumkh     ///
113c2481452Shoumkh     /// @return Ok(i32) 返回0
114c2481452Shoumkh     ///
115676b8ef6SMork     /// @return Err(SystemError) 返回错误码
11640fe15e0SLoGin     fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
117c2481452Shoumkh         // 确保内存对齐,低位都要为0
11840fe15e0SLoGin         if (vaddr.data() & ((1 << exp) - 1)) != 0 {
119676b8ef6SMork             return Err(SystemError::EINVAL);
120c2481452Shoumkh         }
12140fe15e0SLoGin         let region: MmioBuddyAddrRegion = self.create_region(vaddr);
122c2481452Shoumkh         // 加入buddy
12340fe15e0SLoGin         let mut list_guard = self.free_regions[exp2index(exp)].lock();
12440fe15e0SLoGin 
12540fe15e0SLoGin         self.push_block(region, &mut list_guard);
126c2481452Shoumkh         return Ok(0);
127c2481452Shoumkh     }
128c2481452Shoumkh 
129c2481452Shoumkh     /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中
130c2481452Shoumkh     ///
131c2481452Shoumkh     /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
132c2481452Shoumkh     ///
133c2481452Shoumkh     /// @param exp 要被分割的地址区域的大小的幂
134c2481452Shoumkh     ///
135c2481452Shoumkh     /// @param list_guard 【exp-1】对应的链表
136a7eb62a4Shoumkh     fn split_block(
137c2481452Shoumkh         &self,
13840fe15e0SLoGin         region: MmioBuddyAddrRegion,
139c2481452Shoumkh         exp: u32,
140c2481452Shoumkh         low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
141c2481452Shoumkh     ) {
14240fe15e0SLoGin         let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
14340fe15e0SLoGin         let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
144a7eb62a4Shoumkh         self.push_block(region, low_list_guard);
145a7eb62a4Shoumkh         self.push_block(new_region, low_list_guard);
146c2481452Shoumkh     }
147c2481452Shoumkh 
148c2481452Shoumkh     /// @brief 从buddy中申请一块指定大小的内存区域
149c2481452Shoumkh     ///
150c2481452Shoumkh     /// @param exp 要申请的内存块的大小的幂(2^exp)
151c2481452Shoumkh     ///
152c2481452Shoumkh     /// @param list_guard exp对应的链表
153c2481452Shoumkh     ///
15440fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
155c2481452Shoumkh     ///
156c2481452Shoumkh     /// @return Err(MmioResult)
157c2481452Shoumkh     /// - 没有满足要求的内存块时,返回ENOFOUND
158c2481452Shoumkh     /// - 申请的内存块大小超过合法范围,返回WRONGEXP
159c2481452Shoumkh     /// - 调用函数出错时,返回出错函数对应错误码
160a7eb62a4Shoumkh     fn query_addr_region(
161c2481452Shoumkh         &self,
162c2481452Shoumkh         exp: u32,
163c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
16440fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
165c2481452Shoumkh         // 申请范围错误
166c2481452Shoumkh         if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP {
167a7eb62a4Shoumkh             kdebug!("query_addr_region: exp wrong");
168c2481452Shoumkh             return Err(MmioResult::WRONGEXP);
169c2481452Shoumkh         }
170c2481452Shoumkh         // 没有恰好符合要求的内存块
171c2481452Shoumkh         // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】
172c2481452Shoumkh         if list_guard.num_free == 0 {
173c2481452Shoumkh             // 找到最小符合申请范围的内存块
174c2481452Shoumkh             // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp
175c2481452Shoumkh             for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
176ef9f9732Shoumkh                 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
177ef9f9732Shoumkh                     &mut self.free_regions[exp2index(e) as usize].lock();
178ef9f9732Shoumkh                 if pop_list.num_free == 0 {
179c2481452Shoumkh                     continue;
180c2481452Shoumkh                 }
181ef9f9732Shoumkh 
182c2481452Shoumkh                 for e2 in (exp + 1..e + 1).rev() {
183ef9f9732Shoumkh                     if e2 == e {
184ef9f9732Shoumkh                         match self.pop_block(pop_list) {
185ef9f9732Shoumkh                             Ok(region) => {
186ef9f9732Shoumkh                                 if e2 != exp + 1 {
187ef9f9732Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
188ef9f9732Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
189ef9f9732Shoumkh                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
190ef9f9732Shoumkh                                     self.split_block(region, e2, low_list_guard);
191ef9f9732Shoumkh                                 } else {
192ef9f9732Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
193ef9f9732Shoumkh                                     // 所以直接将list_guard传入
194ef9f9732Shoumkh                                     self.split_block(region, e2, list_guard);
195ef9f9732Shoumkh                                 }
196ef9f9732Shoumkh                             }
197ef9f9732Shoumkh                             Err(err) => {
198ef9f9732Shoumkh                                 kdebug!("buddy_pop_region get wrong");
199ef9f9732Shoumkh                                 return Err(err);
200ef9f9732Shoumkh                             }
201ef9f9732Shoumkh                         }
202ef9f9732Shoumkh                     } else {
203ef9f9732Shoumkh                         match self.pop_block(&mut self.free_regions[exp2index(e2) as usize].lock())
204ef9f9732Shoumkh                         {
205c2481452Shoumkh                             Ok(region) => {
206c2481452Shoumkh                                 if e2 != exp + 1 {
207c2481452Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
208c2481452Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
209a7eb62a4Shoumkh                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
210a7eb62a4Shoumkh                                     self.split_block(region, e2, low_list_guard);
211c2481452Shoumkh                                 } else {
212c2481452Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
213c2481452Shoumkh                                     // 所以直接将list_guard传入
214a7eb62a4Shoumkh                                     self.split_block(region, e2, list_guard);
215c2481452Shoumkh                                 }
216c2481452Shoumkh                             }
217c2481452Shoumkh                             Err(err) => {
218c2481452Shoumkh                                 kdebug!("buddy_pop_region get wrong");
219c2481452Shoumkh                                 return Err(err);
220c2481452Shoumkh                             }
221c2481452Shoumkh                         }
222c2481452Shoumkh                     }
223ef9f9732Shoumkh                 }
224c2481452Shoumkh                 break;
225c2481452Shoumkh             }
226c2481452Shoumkh             // 判断是否获得了exp大小的内存块
227c2481452Shoumkh             if list_guard.num_free > 0 {
228ef9f9732Shoumkh                 match self.pop_block(list_guard) {
229ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
230ef9f9732Shoumkh                     Err(err) => return Err(err),
231ef9f9732Shoumkh                 }
232c2481452Shoumkh             }
233c2481452Shoumkh             // 拆分大内存块无法获得exp大小内存块
234c2481452Shoumkh             // 尝试用小内存块合成
235c2481452Shoumkh             // 即将两块exp合成一块exp+1
236ef9f9732Shoumkh 
237ef9f9732Shoumkh             // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
238ef9f9732Shoumkh             // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
239ef9f9732Shoumkh             //     if let Err(err) = self.merge_all_exp(
240ef9f9732Shoumkh             //         exp,
241ef9f9732Shoumkh             //         &mut self.free_regions[exp2index(exp) as usize].lock(),
242ef9f9732Shoumkh             //         high_list_guard,
243ef9f9732Shoumkh             //     ) {
244ef9f9732Shoumkh             //         return err;
245ef9f9732Shoumkh             //     } else {
246ef9f9732Shoumkh             //         return MmioResult::SUCCESS;
247ef9f9732Shoumkh             //     }
248ef9f9732Shoumkh             // };
249c2481452Shoumkh             for e in MMIO_BUDDY_MIN_EXP..exp {
250c2481452Shoumkh                 if e != exp - 1 {
251a7eb62a4Shoumkh                     match self.merge_all_exp(
252ef9f9732Shoumkh                         exp,
253ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp) as usize].lock(),
254ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp + 1)].lock(),
255c2481452Shoumkh                     ) {
256c2481452Shoumkh                         Ok(_) => continue,
257c2481452Shoumkh                         Err(err) => {
258ef9f9732Shoumkh                             kdebug!("merge_all_exp get wrong");
259c2481452Shoumkh                             return Err(err);
260c2481452Shoumkh                         }
261c2481452Shoumkh                     }
262c2481452Shoumkh                 } else {
263a7eb62a4Shoumkh                     match self.merge_all_exp(
264ef9f9732Shoumkh                         exp,
265ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp) as usize].lock(),
266c2481452Shoumkh                         list_guard,
267c2481452Shoumkh                     ) {
268c2481452Shoumkh                         Ok(_) => continue,
269c2481452Shoumkh                         Err(err) => {
270ef9f9732Shoumkh                             kdebug!("merge_all_exp get wrong");
271c2481452Shoumkh                             return Err(err);
272c2481452Shoumkh                         }
273c2481452Shoumkh                     }
274c2481452Shoumkh                 }
275c2481452Shoumkh             }
276c2481452Shoumkh 
277c2481452Shoumkh             //判断是否获得了exp大小的内存块
278c2481452Shoumkh             if list_guard.num_free > 0 {
279ef9f9732Shoumkh                 match self.pop_block(list_guard) {
280ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
281ef9f9732Shoumkh                     Err(err) => return Err(err),
282ef9f9732Shoumkh                 }
283c2481452Shoumkh             }
284c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
285c2481452Shoumkh         } else {
286ef9f9732Shoumkh             match self.pop_block(list_guard) {
287ef9f9732Shoumkh                 Ok(ret) => return Ok(ret),
288ef9f9732Shoumkh                 Err(err) => return Err(err),
289ef9f9732Shoumkh             }
290c2481452Shoumkh         }
291c2481452Shoumkh     }
292c2481452Shoumkh 
293c2481452Shoumkh     /// @brief 对query_addr_region进行封装
294c2481452Shoumkh     ///
295c2481452Shoumkh     /// @param exp 内存区域的大小(2^exp)
296c2481452Shoumkh     ///
29740fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
298c2481452Shoumkh     /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
29940fe15e0SLoGin     fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
300c2481452Shoumkh         let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
301a7eb62a4Shoumkh             &mut self.free_regions[exp2index(exp)].lock();
302a7eb62a4Shoumkh         match self.query_addr_region(exp, list_guard) {
303c2481452Shoumkh             Ok(ret) => return Ok(ret),
304c2481452Shoumkh             Err(err) => {
305c2481452Shoumkh                 kdebug!("mmio_buddy_query_addr_region failed");
306c2481452Shoumkh                 return Err(err);
307c2481452Shoumkh             }
308c2481452Shoumkh         }
309c2481452Shoumkh     }
310c2481452Shoumkh     /// @brief 往指定的地址空间链表中添加一个地址区域
311c2481452Shoumkh     ///
312c2481452Shoumkh     /// @param region 要被添加的地址结构体
313c2481452Shoumkh     ///
314c2481452Shoumkh     /// @param list_guard 目标链表
315a7eb62a4Shoumkh     fn push_block(
316c2481452Shoumkh         &self,
31740fe15e0SLoGin         region: MmioBuddyAddrRegion,
318c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
319c2481452Shoumkh     ) {
320c2481452Shoumkh         list_guard.list.push_back(region);
321c2481452Shoumkh         list_guard.num_free += 1;
322c2481452Shoumkh     }
323c2481452Shoumkh 
324c2481452Shoumkh     /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
325c2481452Shoumkh     #[inline(always)]
32640fe15e0SLoGin     fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
32740fe15e0SLoGin         return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
328c2481452Shoumkh     }
329c2481452Shoumkh 
330c2481452Shoumkh     /// @brief 寻找并弹出指定内存块的伙伴块
331c2481452Shoumkh     ///
332c2481452Shoumkh     /// @param region 对应内存块的信息
333c2481452Shoumkh     ///
334c2481452Shoumkh     /// @param exp 内存块大小
335c2481452Shoumkh     ///
336c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
337c2481452Shoumkh     ///
338c2481452Shoumkh     /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
339c2481452Shoumkh     /// @return Err(MmioResult)
340c2481452Shoumkh     /// - 当链表为空,返回ISEMPTY
341c2481452Shoumkh     /// - 没有找到伙伴块,返回ENOFOUND
342a7eb62a4Shoumkh     fn pop_buddy_block(
343c2481452Shoumkh         &self,
34440fe15e0SLoGin         vaddr: VirtAddr,
345c2481452Shoumkh         exp: u32,
346c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
34740fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
348c2481452Shoumkh         if list_guard.list.len() == 0 {
349c2481452Shoumkh             return Err(MmioResult::ISEMPTY);
350c2481452Shoumkh         } else {
351c2481452Shoumkh             //计算伙伴块的地址
352a7eb62a4Shoumkh             let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
353c2481452Shoumkh 
354c2481452Shoumkh             // element 只会有一个元素
35540fe15e0SLoGin             let mut element: Vec<MmioBuddyAddrRegion> = list_guard
356c2481452Shoumkh                 .list
357c2481452Shoumkh                 .drain_filter(|x| x.vaddr == buddy_vaddr)
358c2481452Shoumkh                 .collect();
359c2481452Shoumkh             if element.len() == 1 {
360c2481452Shoumkh                 list_guard.num_free -= 1;
361c2481452Shoumkh                 return Ok(element.pop().unwrap());
362c2481452Shoumkh             }
363c2481452Shoumkh 
364c2481452Shoumkh             //没有找到对应的伙伴块
365c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
366c2481452Shoumkh         }
367c2481452Shoumkh     }
368c2481452Shoumkh 
369c2481452Shoumkh     /// @brief 从指定空闲链表中取出内存区域
370c2481452Shoumkh     ///
371c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
372c2481452Shoumkh     ///
37340fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
374c2481452Shoumkh     ///
375c2481452Shoumkh     /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
376a7eb62a4Shoumkh     fn pop_block(
377c2481452Shoumkh         &self,
378c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
37940fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
380c2481452Shoumkh         if !list_guard.list.is_empty() {
381c2481452Shoumkh             list_guard.num_free -= 1;
382c2481452Shoumkh             return Ok(list_guard.list.pop_back().unwrap());
383c2481452Shoumkh         }
384c2481452Shoumkh         return Err(MmioResult::ISEMPTY);
385c2481452Shoumkh     }
386c2481452Shoumkh 
387c2481452Shoumkh     /// @brief 合并所有2^{exp}大小的内存块
388c2481452Shoumkh     ///
389c2481452Shoumkh     /// @param exp 内存块大小的幂(2^exp)
390c2481452Shoumkh     ///
391c2481452Shoumkh     /// @param list_guard exp对应的链表
392c2481452Shoumkh     ///
393c2481452Shoumkh     /// @param high_list_guard exp+1对应的链表
394c2481452Shoumkh     ///
395c2481452Shoumkh     /// @return Ok(MmioResult) 合并成功返回SUCCESS
396c2481452Shoumkh     /// @return Err(MmioResult)
397c2481452Shoumkh     /// - 内存块过少,无法合并,返回EINVAL
398a7eb62a4Shoumkh     /// - pop_buddy_block调用出错,返回其错误码
399a7eb62a4Shoumkh     /// - merge_blocks调用出错,返回其错误码
400a7eb62a4Shoumkh     fn merge_all_exp(
401c2481452Shoumkh         &self,
402c2481452Shoumkh         exp: u32,
403c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
404c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
405c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
406c2481452Shoumkh         // 至少要两个内存块才能合并
407c2481452Shoumkh         if list_guard.num_free <= 1 {
408c2481452Shoumkh             return Err(MmioResult::EINVAL);
409c2481452Shoumkh         }
410c2481452Shoumkh         loop {
411c2481452Shoumkh             if list_guard.num_free <= 1 {
412c2481452Shoumkh                 break;
413c2481452Shoumkh             }
414c2481452Shoumkh             // 获取内存块
41540fe15e0SLoGin             let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
416c2481452Shoumkh             // 获取伙伴内存块
417a7eb62a4Shoumkh             match self.pop_buddy_block(vaddr, exp, list_guard) {
418c2481452Shoumkh                 Err(err) => {
419c2481452Shoumkh                     return Err(err);
420c2481452Shoumkh                 }
421c2481452Shoumkh                 Ok(buddy_region) => {
42240fe15e0SLoGin                     let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
42340fe15e0SLoGin                     let copy_region = region.clone();
424c2481452Shoumkh                     // 在两块内存都被取出之后才进行合并
425a7eb62a4Shoumkh                     match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
426c2481452Shoumkh                         Err(err) => {
427c2481452Shoumkh                             // 如果合并失败了要将取出来的元素放回去
428a7eb62a4Shoumkh                             self.push_block(copy_region, list_guard);
429a7eb62a4Shoumkh                             kdebug!("merge_all_exp: merge_blocks failed");
430c2481452Shoumkh                             return Err(err);
431c2481452Shoumkh                         }
432c2481452Shoumkh                         Ok(_) => continue,
433c2481452Shoumkh                     }
434c2481452Shoumkh                 }
435c2481452Shoumkh             }
436c2481452Shoumkh         }
437c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
438c2481452Shoumkh     }
439c2481452Shoumkh 
440c2481452Shoumkh     /// @brief 合并两个【已经从链表中取出】的内存块
441c2481452Shoumkh     ///
442c2481452Shoumkh     /// @param region_1 第一个内存块
443c2481452Shoumkh     ///
444c2481452Shoumkh     /// @param region_2 第二个内存
445c2481452Shoumkh     ///
446c2481452Shoumkh     /// @return Ok(MmioResult) 成功返回SUCCESS
447c2481452Shoumkh     ///
448c2481452Shoumkh     /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
449a7eb62a4Shoumkh     fn merge_blocks(
450c2481452Shoumkh         &self,
45140fe15e0SLoGin         region_1: MmioBuddyAddrRegion,
45240fe15e0SLoGin         region_2: MmioBuddyAddrRegion,
453c2481452Shoumkh         exp: u32,
454c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
455c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
456c2481452Shoumkh         // 判断是否为伙伴块
457a7eb62a4Shoumkh         if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
458c2481452Shoumkh             return Err(MmioResult::EINVAL);
459c2481452Shoumkh         }
460c2481452Shoumkh         // 将大的块放进下一级链表
461a7eb62a4Shoumkh         self.push_block(region_1, high_list_guard);
462c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
463c2481452Shoumkh     }
464c2481452Shoumkh 
465c2481452Shoumkh     /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
466c2481452Shoumkh     ///
467c2481452Shoumkh     /// @param size mmio区域的大小(字节)
468c2481452Shoumkh     ///
469c2481452Shoumkh     /// @param vm_flags 要把vma设置成的标志
470c2481452Shoumkh     ///
471c2481452Shoumkh     /// @param res_vaddr 返回值-分配得到的虚拟地址
472c2481452Shoumkh     ///
473c2481452Shoumkh     /// @param res_length 返回值-分配的虚拟地址空间长度
474c2481452Shoumkh     ///
475a7eb62a4Shoumkh     /// @return Ok(i32) 成功返回0
476a7eb62a4Shoumkh     ///
477676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
478*2dd9f0c7SLoGin     pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
479c2481452Shoumkh         if size > PAGE_1G_SIZE || size == 0 {
480676b8ef6SMork             return Err(SystemError::EPERM);
481c2481452Shoumkh         }
482c2481452Shoumkh         // 计算前导0
48340fe15e0SLoGin         #[cfg(target_arch = "x86_64")]
48440fe15e0SLoGin         let mut size_exp: u32 = 63 - size.leading_zeros();
485*2dd9f0c7SLoGin 
486c2481452Shoumkh         // 记录最终申请的空间大小
48740fe15e0SLoGin         let mut new_size = size;
488c2481452Shoumkh         // 对齐要申请的空间大小
489c2481452Shoumkh         // 如果要申请的空间大小小于4k,则分配4k
490c2481452Shoumkh         if size_exp < PAGE_4K_SHIFT {
49140fe15e0SLoGin             new_size = PAGE_4K_SIZE as usize;
492c2481452Shoumkh             size_exp = PAGE_4K_SHIFT;
493c2481452Shoumkh         } else if (new_size & (!(1 << size_exp))) != 0 {
494c2481452Shoumkh             // 向左对齐空间大小
495c2481452Shoumkh             size_exp += 1;
496c2481452Shoumkh             new_size = 1 << size_exp;
497c2481452Shoumkh         }
49840fe15e0SLoGin         match self.mmio_buddy_query_addr_region(size_exp) {
499c2481452Shoumkh             Ok(region) => {
500*2dd9f0c7SLoGin                 let space_guard =
501*2dd9f0c7SLoGin                     unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) };
502*2dd9f0c7SLoGin                 return Ok(space_guard);
503c2481452Shoumkh             }
504c2481452Shoumkh             Err(_) => {
50540fe15e0SLoGin                 kerror!("failed to create mmio. pid = {:?}", current_pcb().pid);
506676b8ef6SMork                 return Err(SystemError::ENOMEM);
507c2481452Shoumkh             }
508c2481452Shoumkh         }
509c2481452Shoumkh     }
510c2481452Shoumkh 
511c2481452Shoumkh     /// @brief 取消mmio的映射并将地址空间归还到buddy中
512c2481452Shoumkh     ///
513c2481452Shoumkh     /// @param vaddr 起始的虚拟地址
514c2481452Shoumkh     ///
515c2481452Shoumkh     /// @param length 要归还的地址空间的长度
516c2481452Shoumkh     ///
517c2481452Shoumkh     /// @return Ok(i32) 成功返回0
518c2481452Shoumkh     ///
519676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
520*2dd9f0c7SLoGin     fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
52140fe15e0SLoGin         assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
52240fe15e0SLoGin         assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
52340fe15e0SLoGin         if vaddr < self.pool_start_addr
52440fe15e0SLoGin             || vaddr.data() >= self.pool_start_addr.data() + self.pool_size
52540fe15e0SLoGin         {
526676b8ef6SMork             return Err(SystemError::EINVAL);
527c2481452Shoumkh         }
52840fe15e0SLoGin         // todo: 重构MMIO管理机制,创建类似全局的manager之类的,管理MMIO的空间?
52940fe15e0SLoGin 
53040fe15e0SLoGin         // 暂时认为传入的vaddr都是正确的
53140fe15e0SLoGin         let page_count = length / MMArch::PAGE_SIZE;
53240fe15e0SLoGin         // 取消映射
53340fe15e0SLoGin         let mut bindings = KernelMapper::lock();
53440fe15e0SLoGin         let mut kernel_mapper = bindings.as_mut();
53540fe15e0SLoGin         if kernel_mapper.is_none() {
53640fe15e0SLoGin             kwarn!("release_mmio: kernel_mapper is read only");
53740fe15e0SLoGin             return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
538c2481452Shoumkh         }
53940fe15e0SLoGin 
54040fe15e0SLoGin         for i in 0..page_count {
541c2481452Shoumkh             unsafe {
54240fe15e0SLoGin                 kernel_mapper
54340fe15e0SLoGin                     .as_mut()
54440fe15e0SLoGin                     .unwrap()
545*2dd9f0c7SLoGin                     .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, true)
54640fe15e0SLoGin             };
547c2481452Shoumkh         }
54840fe15e0SLoGin 
54940fe15e0SLoGin         // todo: 归还到buddy
55040fe15e0SLoGin 
551a7eb62a4Shoumkh         return Ok(0);
552a7eb62a4Shoumkh     }
553a7eb62a4Shoumkh }
554a7eb62a4Shoumkh 
555a7eb62a4Shoumkh /// @brief mmio伙伴系统内部的地址区域结构体
55640fe15e0SLoGin #[derive(Debug, Clone)]
55740fe15e0SLoGin struct MmioBuddyAddrRegion {
55840fe15e0SLoGin     vaddr: VirtAddr,
559a7eb62a4Shoumkh }
560a7eb62a4Shoumkh impl MmioBuddyAddrRegion {
56140fe15e0SLoGin     pub fn new(vaddr: VirtAddr) -> Self {
56240fe15e0SLoGin         return MmioBuddyAddrRegion { vaddr };
563a7eb62a4Shoumkh     }
56440fe15e0SLoGin 
56540fe15e0SLoGin     #[allow(dead_code)]
56640fe15e0SLoGin     pub fn vaddr(&self) -> VirtAddr {
56740fe15e0SLoGin         return self.vaddr;
568a7eb62a4Shoumkh     }
569a7eb62a4Shoumkh }
570a7eb62a4Shoumkh 
571a7eb62a4Shoumkh /// @brief 空闲页数组结构体
57240fe15e0SLoGin #[derive(Debug)]
573a7eb62a4Shoumkh pub struct MmioFreeRegionList {
574a7eb62a4Shoumkh     /// 存储mmio_buddy的地址链表
57540fe15e0SLoGin     list: LinkedList<MmioBuddyAddrRegion>,
576a7eb62a4Shoumkh     /// 空闲块的数量
577a7eb62a4Shoumkh     num_free: i64,
578a7eb62a4Shoumkh }
579a7eb62a4Shoumkh impl MmioFreeRegionList {
58064aea4b3SGou Ngai     #[allow(dead_code)]
581a7eb62a4Shoumkh     fn new() -> Self {
582a7eb62a4Shoumkh         return MmioFreeRegionList {
583a7eb62a4Shoumkh             ..Default::default()
584a7eb62a4Shoumkh         };
585a7eb62a4Shoumkh     }
586a7eb62a4Shoumkh }
587a7eb62a4Shoumkh impl Default for MmioFreeRegionList {
588a7eb62a4Shoumkh     fn default() -> Self {
589a7eb62a4Shoumkh         MmioFreeRegionList {
590a7eb62a4Shoumkh             list: Default::default(),
591a7eb62a4Shoumkh             num_free: 0,
592a7eb62a4Shoumkh         }
593a7eb62a4Shoumkh     }
594a7eb62a4Shoumkh }
595a7eb62a4Shoumkh 
596a7eb62a4Shoumkh /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
597a7eb62a4Shoumkh ///
598a7eb62a4Shoumkh /// @param exp内存大小
599a7eb62a4Shoumkh ///
600a7eb62a4Shoumkh /// @return 内存池数组下标
601a7eb62a4Shoumkh #[inline(always)]
602a7eb62a4Shoumkh fn exp2index(exp: u32) -> usize {
603a7eb62a4Shoumkh     return (exp - 12) as usize;
604a7eb62a4Shoumkh }
605a7eb62a4Shoumkh 
606*2dd9f0c7SLoGin #[derive(Debug)]
607*2dd9f0c7SLoGin pub struct MMIOSpaceGuard {
608*2dd9f0c7SLoGin     vaddr: VirtAddr,
609*2dd9f0c7SLoGin     size: usize,
610*2dd9f0c7SLoGin     mapped: AtomicBool,
611*2dd9f0c7SLoGin }
612*2dd9f0c7SLoGin 
613*2dd9f0c7SLoGin impl MMIOSpaceGuard {
614*2dd9f0c7SLoGin     pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self {
615*2dd9f0c7SLoGin         // check size
616*2dd9f0c7SLoGin         assert!(
617*2dd9f0c7SLoGin             size & (MMArch::PAGE_SIZE - 1) == 0,
618*2dd9f0c7SLoGin             "MMIO space size must be page aligned"
619*2dd9f0c7SLoGin         );
620*2dd9f0c7SLoGin         assert!(size.is_power_of_two(), "MMIO space size must be power of 2");
621*2dd9f0c7SLoGin         assert!(
622*2dd9f0c7SLoGin             vaddr.check_aligned(size),
623*2dd9f0c7SLoGin             "MMIO space vaddr must be aligned with size"
624*2dd9f0c7SLoGin         );
625*2dd9f0c7SLoGin         assert!(
626*2dd9f0c7SLoGin             vaddr.data() >= MMIO_BASE.data() && vaddr.data() + size <= MMIO_TOP.data(),
627*2dd9f0c7SLoGin             "MMIO space must be in MMIO region"
628*2dd9f0c7SLoGin         );
629*2dd9f0c7SLoGin 
630*2dd9f0c7SLoGin         // 人工创建的MMIO空间,认为已经映射
631*2dd9f0c7SLoGin         MMIOSpaceGuard {
632*2dd9f0c7SLoGin             vaddr,
633*2dd9f0c7SLoGin             size,
634*2dd9f0c7SLoGin             mapped: AtomicBool::new(mapped),
635*2dd9f0c7SLoGin         }
636*2dd9f0c7SLoGin     }
637*2dd9f0c7SLoGin 
638*2dd9f0c7SLoGin     pub fn vaddr(&self) -> VirtAddr {
639*2dd9f0c7SLoGin         self.vaddr
640*2dd9f0c7SLoGin     }
641*2dd9f0c7SLoGin 
642*2dd9f0c7SLoGin     pub fn size(&self) -> usize {
643*2dd9f0c7SLoGin         self.size
644*2dd9f0c7SLoGin     }
645*2dd9f0c7SLoGin 
646*2dd9f0c7SLoGin     /// 将物理地址填写到虚拟地址空间中
647*2dd9f0c7SLoGin     ///
648*2dd9f0c7SLoGin     /// ## Safety
649*2dd9f0c7SLoGin     ///
650*2dd9f0c7SLoGin     /// 传入的物理地址【一定要是设备的物理地址】。
651*2dd9f0c7SLoGin     /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
652*2dd9f0c7SLoGin     pub unsafe fn map_phys<Arch: MemoryManagementArch>(
653*2dd9f0c7SLoGin         &self,
654*2dd9f0c7SLoGin         paddr: PhysAddr,
655*2dd9f0c7SLoGin         length: usize,
656*2dd9f0c7SLoGin     ) -> bool {
657*2dd9f0c7SLoGin         if length > self.size {
658*2dd9f0c7SLoGin             return false;
659*2dd9f0c7SLoGin         }
660*2dd9f0c7SLoGin 
661*2dd9f0c7SLoGin         let check = self
662*2dd9f0c7SLoGin             .mapped
663*2dd9f0c7SLoGin             .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
664*2dd9f0c7SLoGin         if check.is_err() {
665*2dd9f0c7SLoGin             return false;
666*2dd9f0c7SLoGin         }
667*2dd9f0c7SLoGin 
668*2dd9f0c7SLoGin         let flags = PageFlags::mmio_flags();
669*2dd9f0c7SLoGin         let mut kernel_mapper = KernelMapper::lock();
670*2dd9f0c7SLoGin         let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
671*2dd9f0c7SLoGin         if r.is_err() {
672*2dd9f0c7SLoGin             return false;
673*2dd9f0c7SLoGin         }
674*2dd9f0c7SLoGin         return true;
675*2dd9f0c7SLoGin     }
676*2dd9f0c7SLoGin }
677*2dd9f0c7SLoGin 
678*2dd9f0c7SLoGin impl Drop for MMIOSpaceGuard {
679*2dd9f0c7SLoGin     fn drop(&mut self) {
680*2dd9f0c7SLoGin         let _ = mmio_pool()
681*2dd9f0c7SLoGin             .release_mmio(self.vaddr, self.size)
682*2dd9f0c7SLoGin             .unwrap_or_else(|err| {
683*2dd9f0c7SLoGin                 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
684*2dd9f0c7SLoGin             });
685*2dd9f0c7SLoGin     }
686*2dd9f0c7SLoGin }
687*2dd9f0c7SLoGin 
68840fe15e0SLoGin pub fn mmio_init() {
68940fe15e0SLoGin     kdebug!("Initializing MMIO buddy memory pool...");
69040fe15e0SLoGin     // 初始化mmio内存池
69140fe15e0SLoGin     unsafe {
69240fe15e0SLoGin         __MMIO_POOL = Some(MmioBuddyMemPool::new());
69340fe15e0SLoGin     }
69440fe15e0SLoGin 
69540fe15e0SLoGin     kinfo!("MMIO buddy memory pool init done");
69640fe15e0SLoGin }
697a7eb62a4Shoumkh /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
698a7eb62a4Shoumkh ///
699a7eb62a4Shoumkh /// @param size mmio区域的大小(字节)
700a7eb62a4Shoumkh ///
701a7eb62a4Shoumkh /// @param vm_flags 要把vma设置成的标志
702a7eb62a4Shoumkh ///
703a7eb62a4Shoumkh /// @param res_vaddr 返回值-分配得到的虚拟地址
704a7eb62a4Shoumkh ///
705a7eb62a4Shoumkh /// @param res_length 返回值-分配的虚拟地址空间长度
706a7eb62a4Shoumkh ///
707a7eb62a4Shoumkh /// @return int 错误码
708a7eb62a4Shoumkh #[no_mangle]
709*2dd9f0c7SLoGin pub unsafe extern "C" fn mmio_create(
710a7eb62a4Shoumkh     size: u32,
711*2dd9f0c7SLoGin     _vm_flags: vm_flags_t,
712a7eb62a4Shoumkh     res_vaddr: *mut u64,
713a7eb62a4Shoumkh     res_length: *mut u64,
714a7eb62a4Shoumkh ) -> i32 {
71540fe15e0SLoGin     // kdebug!("mmio_create");
716*2dd9f0c7SLoGin     let r = mmio_pool().create_mmio(size as usize);
717*2dd9f0c7SLoGin     if r.is_err() {
718*2dd9f0c7SLoGin         return r.unwrap_err().to_posix_errno();
719c2481452Shoumkh     }
720*2dd9f0c7SLoGin     let space_guard = r.unwrap();
721*2dd9f0c7SLoGin     *res_vaddr = space_guard.vaddr().data() as u64;
722*2dd9f0c7SLoGin     *res_length = space_guard.size() as u64;
723*2dd9f0c7SLoGin     // 由于space_guard drop的时候会自动释放内存,所以这里要忽略它的释放
724*2dd9f0c7SLoGin     core::mem::forget(space_guard);
725*2dd9f0c7SLoGin     return 0;
726a7eb62a4Shoumkh }
727a7eb62a4Shoumkh 
728a7eb62a4Shoumkh /// @brief 取消mmio的映射并将地址空间归还到buddy中
729a7eb62a4Shoumkh ///
730a7eb62a4Shoumkh /// @param vaddr 起始的虚拟地址
731a7eb62a4Shoumkh ///
732a7eb62a4Shoumkh /// @param length 要归还的地址空间的长度
733a7eb62a4Shoumkh ///
734a7eb62a4Shoumkh /// @return Ok(i32) 成功返回0
735a7eb62a4Shoumkh ///
736a7eb62a4Shoumkh /// @return Err(i32) 失败返回错误码
737a7eb62a4Shoumkh #[no_mangle]
738*2dd9f0c7SLoGin pub unsafe extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
73940fe15e0SLoGin     return mmio_pool()
74040fe15e0SLoGin         .release_mmio(VirtAddr::new(vaddr as usize), length as usize)
74140fe15e0SLoGin         .unwrap_or_else(|err| err.to_posix_errno());
742a7eb62a4Shoumkh }
743