xref: /DragonOS/kernel/src/mm/mmio_buddy.rs (revision 370472f7288b568c7b80815f5b150daf4496446c)
1 use crate::libs::spinlock::{SpinLock, SpinLockGuard};
2 use crate::mm::kernel_mapper::KernelMapper;
3 use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
4 use crate::process::ProcessManager;
5 use crate::{
6     kdebug,
7     mm::{MMArch, MemoryManagementArch},
8 };
9 use crate::{kerror, kinfo, kwarn};
10 use alloc::{collections::LinkedList, vec::Vec};
11 use core::mem;
12 use core::mem::MaybeUninit;
13 use core::sync::atomic::{AtomicBool, Ordering};
14 use system_error::SystemError;
15 
16 use super::page::{PageFlags, PAGE_4K_SIZE};
17 use super::{PhysAddr, VirtAddr};
18 
19 // 最大的伙伴块的幂
20 const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT as u32;
21 // 最小的伙伴块的幂
22 const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT as u32;
23 // 内存池数组的范围
24 const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
25 
26 const PAGE_1G_SIZE: usize = 1 << 30;
27 
28 static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
29 
30 pub fn mmio_pool() -> &'static MmioBuddyMemPool {
31     unsafe { __MMIO_POOL.as_ref().unwrap() }
32 }
33 
34 pub enum MmioResult {
35     SUCCESS,
36     EINVAL,
37     ENOFOUND,
38     WRONGEXP,
39     ISEMPTY,
40 }
41 
42 /// @brief buddy内存池
43 #[derive(Debug)]
44 pub struct MmioBuddyMemPool {
45     pool_start_addr: VirtAddr,
46     pool_size: usize,
47     free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
48 }
49 
50 impl MmioBuddyMemPool {
51     #[inline(never)]
52     fn new() -> Self {
53         let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
54             MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
55         for i in 0..MMIO_BUDDY_REGION_COUNT {
56             free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
57         }
58         let free_regions = unsafe {
59             mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
60                 free_regions,
61             )
62         };
63 
64         let pool = MmioBuddyMemPool {
65             pool_start_addr: MMArch::MMIO_BASE,
66             pool_size: MMArch::MMIO_SIZE,
67             free_regions,
68         };
69 
70         assert!(pool.pool_start_addr.data() % PAGE_1G_SIZE == 0);
71         kdebug!("MMIO buddy pool init: created");
72 
73         let mut vaddr_base = MMArch::MMIO_BASE;
74         let mut remain_size = MMArch::MMIO_SIZE;
75         kdebug!(
76             "BASE: {:?}, TOP: {:?}, size: {:?}",
77             MMArch::MMIO_BASE,
78             MMArch::MMIO_TOP,
79             MMArch::MMIO_SIZE
80         );
81 
82         for shift in (PAGE_4K_SHIFT..=PAGE_1G_SHIFT).rev() {
83             if remain_size & (1 << shift) != 0 {
84                 let ok = pool.give_back_block(vaddr_base, shift as u32).is_ok();
85                 if ok {
86                     vaddr_base += 1 << shift;
87                     remain_size -= 1 << shift;
88                 } else {
89                     panic!("MMIO buddy pool init failed");
90                 }
91             }
92         }
93 
94         kdebug!("MMIO buddy pool init success");
95         return pool;
96     }
97 
98     /// @brief 创建新的地址区域结构体
99     ///
100     /// @param vaddr 虚拟地址
101     ///
102     /// @return 创建好的地址区域结构体
103     fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
104         // kdebug!("create_region for vaddr: {vaddr:?}");
105 
106         let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
107 
108         // kdebug!("create_region for vaddr: {vaddr:?} OK!!!");
109         return region;
110     }
111 
112     /// @brief 将内存块归还给buddy
113     ///
114     /// @param vaddr 虚拟地址
115     ///
116     /// @param exp 内存空间的大小(2^exp)
117     ///
118     /// @param list_guard 【exp】对应的链表
119     ///
120     /// @return Ok(i32) 返回0
121     ///
122     /// @return Err(SystemError) 返回错误码
123     fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
124         // 确保内存对齐,低位都要为0
125         if (vaddr.data() & ((1 << exp) - 1)) != 0 {
126             return Err(SystemError::EINVAL);
127         }
128         let region: MmioBuddyAddrRegion = self.create_region(vaddr);
129         // 加入buddy
130         let mut list_guard = self.free_regions[exp2index(exp)].lock();
131 
132         self.push_block(region, &mut list_guard);
133         return Ok(0);
134     }
135 
136     /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中
137     ///
138     /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
139     ///
140     /// @param exp 要被分割的地址区域的大小的幂
141     ///
142     /// @param list_guard 【exp-1】对应的链表
143     fn split_block(
144         &self,
145         region: MmioBuddyAddrRegion,
146         exp: u32,
147         low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
148     ) {
149         let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
150         let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
151         self.push_block(region, low_list_guard);
152         self.push_block(new_region, low_list_guard);
153     }
154 
155     /// @brief 从buddy中申请一块指定大小的内存区域
156     ///
157     /// @param exp 要申请的内存块的大小的幂(2^exp)
158     ///
159     /// @param list_guard exp对应的链表
160     ///
161     /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
162     ///
163     /// @return Err(MmioResult)
164     /// - 没有满足要求的内存块时,返回ENOFOUND
165     /// - 申请的内存块大小超过合法范围,返回WRONGEXP
166     /// - 调用函数出错时,返回出错函数对应错误码
167     fn query_addr_region(
168         &self,
169         exp: u32,
170         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
171     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
172         // 申请范围错误
173         if !(MMIO_BUDDY_MIN_EXP..=MMIO_BUDDY_MAX_EXP).contains(&exp) {
174             kdebug!("query_addr_region: exp wrong");
175             return Err(MmioResult::WRONGEXP);
176         }
177         // 没有恰好符合要求的内存块
178         // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】
179         if list_guard.num_free == 0 {
180             // 找到最小符合申请范围的内存块
181             // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp
182             for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
183                 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
184                     &mut self.free_regions[exp2index(e)].lock();
185                 if pop_list.num_free == 0 {
186                     continue;
187                 }
188 
189                 for e2 in (exp + 1..e + 1).rev() {
190                     if e2 == e {
191                         match self.pop_block(pop_list) {
192                             Ok(region) => {
193                                 if e2 != exp + 1 {
194                                     // 要将分裂后的内存块插入到更小的链表中
195                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
196                                         &mut self.free_regions[exp2index(e2 - 1)].lock();
197                                     self.split_block(region, e2, low_list_guard);
198                                 } else {
199                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
200                                     // 所以直接将list_guard传入
201                                     self.split_block(region, e2, list_guard);
202                                 }
203                             }
204                             Err(err) => {
205                                 kdebug!("buddy_pop_region get wrong");
206                                 return Err(err);
207                             }
208                         }
209                     } else {
210                         match self.pop_block(&mut self.free_regions[exp2index(e2)].lock()) {
211                             Ok(region) => {
212                                 if e2 != exp + 1 {
213                                     // 要将分裂后的内存块插入到更小的链表中
214                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
215                                         &mut self.free_regions[exp2index(e2 - 1)].lock();
216                                     self.split_block(region, e2, low_list_guard);
217                                 } else {
218                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
219                                     // 所以直接将list_guard传入
220                                     self.split_block(region, e2, list_guard);
221                                 }
222                             }
223                             Err(err) => {
224                                 kdebug!("buddy_pop_region get wrong");
225                                 return Err(err);
226                             }
227                         }
228                     }
229                 }
230                 break;
231             }
232             // 判断是否获得了exp大小的内存块
233             if list_guard.num_free > 0 {
234                 match self.pop_block(list_guard) {
235                     Ok(ret) => return Ok(ret),
236                     Err(err) => return Err(err),
237                 }
238             }
239             // 拆分大内存块无法获得exp大小内存块
240             // 尝试用小内存块合成
241             // 即将两块exp合成一块exp+1
242 
243             // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
244             // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
245             //     if let Err(err) = self.merge_all_exp(
246             //         exp,
247             //         &mut self.free_regions[exp2index(exp) as usize].lock(),
248             //         high_list_guard,
249             //     ) {
250             //         return err;
251             //     } else {
252             //         return MmioResult::SUCCESS;
253             //     }
254             // };
255             for e in MMIO_BUDDY_MIN_EXP..exp {
256                 if e != exp - 1 {
257                     match self.merge_all_exp(
258                         exp,
259                         &mut self.free_regions[exp2index(exp)].lock(),
260                         &mut self.free_regions[exp2index(exp + 1)].lock(),
261                     ) {
262                         Ok(_) => continue,
263                         Err(err) => {
264                             kdebug!("merge_all_exp get wrong");
265                             return Err(err);
266                         }
267                     }
268                 } else {
269                     match self.merge_all_exp(
270                         exp,
271                         &mut self.free_regions[exp2index(exp)].lock(),
272                         list_guard,
273                     ) {
274                         Ok(_) => continue,
275                         Err(err) => {
276                             kdebug!("merge_all_exp get wrong");
277                             return Err(err);
278                         }
279                     }
280                 }
281             }
282 
283             //判断是否获得了exp大小的内存块
284             if list_guard.num_free > 0 {
285                 match self.pop_block(list_guard) {
286                     Ok(ret) => return Ok(ret),
287                     Err(err) => return Err(err),
288                 }
289             }
290             return Err(MmioResult::ENOFOUND);
291         } else {
292             match self.pop_block(list_guard) {
293                 Ok(ret) => return Ok(ret),
294                 Err(err) => return Err(err),
295             }
296         }
297     }
298 
299     /// @brief 对query_addr_region进行封装
300     ///
301     /// @param exp 内存区域的大小(2^exp)
302     ///
303     /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
304     /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
305     fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
306         let mut list_guard: SpinLockGuard<MmioFreeRegionList> =
307             self.free_regions[exp2index(exp)].lock();
308         match self.query_addr_region(exp, &mut list_guard) {
309             Ok(ret) => return Ok(ret),
310             Err(err) => {
311                 kdebug!("mmio_buddy_query_addr_region failed");
312                 return Err(err);
313             }
314         }
315     }
316     /// @brief 往指定的地址空间链表中添加一个地址区域
317     ///
318     /// @param region 要被添加的地址结构体
319     ///
320     /// @param list_guard 目标链表
321     fn push_block(
322         &self,
323         region: MmioBuddyAddrRegion,
324         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
325     ) {
326         list_guard.list.push_back(region);
327         list_guard.num_free += 1;
328     }
329 
330     /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
331     #[inline(always)]
332     fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
333         return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
334     }
335 
336     /// @brief 寻找并弹出指定内存块的伙伴块
337     ///
338     /// @param region 对应内存块的信息
339     ///
340     /// @param exp 内存块大小
341     ///
342     /// @param list_guard 【exp】对应的链表
343     ///
344     /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
345     /// @return Err(MmioResult)
346     /// - 当链表为空,返回ISEMPTY
347     /// - 没有找到伙伴块,返回ENOFOUND
348     fn pop_buddy_block(
349         &self,
350         vaddr: VirtAddr,
351         exp: u32,
352         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
353     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
354         if list_guard.list.is_empty() {
355             return Err(MmioResult::ISEMPTY);
356         } else {
357             //计算伙伴块的地址
358             let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
359 
360             // element 只会有一个元素
361             let mut element: Vec<MmioBuddyAddrRegion> = list_guard
362                 .list
363                 .extract_if(|x| x.vaddr == buddy_vaddr)
364                 .collect();
365             if element.len() == 1 {
366                 list_guard.num_free -= 1;
367                 return Ok(element.pop().unwrap());
368             }
369 
370             //没有找到对应的伙伴块
371             return Err(MmioResult::ENOFOUND);
372         }
373     }
374 
375     /// @brief 从指定空闲链表中取出内存区域
376     ///
377     /// @param list_guard 【exp】对应的链表
378     ///
379     /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
380     ///
381     /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
382     fn pop_block(
383         &self,
384         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
385     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
386         if !list_guard.list.is_empty() {
387             list_guard.num_free -= 1;
388             return Ok(list_guard.list.pop_back().unwrap());
389         }
390         return Err(MmioResult::ISEMPTY);
391     }
392 
393     /// @brief 合并所有2^{exp}大小的内存块
394     ///
395     /// @param exp 内存块大小的幂(2^exp)
396     ///
397     /// @param list_guard exp对应的链表
398     ///
399     /// @param high_list_guard exp+1对应的链表
400     ///
401     /// @return Ok(MmioResult) 合并成功返回SUCCESS
402     /// @return Err(MmioResult)
403     /// - 内存块过少,无法合并,返回EINVAL
404     /// - pop_buddy_block调用出错,返回其错误码
405     /// - merge_blocks调用出错,返回其错误码
406     fn merge_all_exp(
407         &self,
408         exp: u32,
409         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
410         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
411     ) -> Result<MmioResult, MmioResult> {
412         // 至少要两个内存块才能合并
413         if list_guard.num_free <= 1 {
414             return Err(MmioResult::EINVAL);
415         }
416         loop {
417             if list_guard.num_free <= 1 {
418                 break;
419             }
420             // 获取内存块
421             let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
422             // 获取伙伴内存块
423             match self.pop_buddy_block(vaddr, exp, list_guard) {
424                 Err(err) => {
425                     return Err(err);
426                 }
427                 Ok(buddy_region) => {
428                     let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
429                     let copy_region = region.clone();
430                     // 在两块内存都被取出之后才进行合并
431                     match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
432                         Err(err) => {
433                             // 如果合并失败了要将取出来的元素放回去
434                             self.push_block(copy_region, list_guard);
435                             kdebug!("merge_all_exp: merge_blocks failed");
436                             return Err(err);
437                         }
438                         Ok(_) => continue,
439                     }
440                 }
441             }
442         }
443         return Ok(MmioResult::SUCCESS);
444     }
445 
446     /// @brief 合并两个【已经从链表中取出】的内存块
447     ///
448     /// @param region_1 第一个内存块
449     ///
450     /// @param region_2 第二个内存
451     ///
452     /// @return Ok(MmioResult) 成功返回SUCCESS
453     ///
454     /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
455     fn merge_blocks(
456         &self,
457         region_1: MmioBuddyAddrRegion,
458         region_2: MmioBuddyAddrRegion,
459         exp: u32,
460         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
461     ) -> Result<MmioResult, MmioResult> {
462         // 判断是否为伙伴块
463         if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
464             return Err(MmioResult::EINVAL);
465         }
466         // 将大的块放进下一级链表
467         self.push_block(region_1, high_list_guard);
468         return Ok(MmioResult::SUCCESS);
469     }
470 
471     /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
472     ///
473     /// @param size mmio区域的大小(字节)
474     ///
475     /// @param vm_flags 要把vma设置成的标志
476     ///
477     /// @param res_vaddr 返回值-分配得到的虚拟地址
478     ///
479     /// @param res_length 返回值-分配的虚拟地址空间长度
480     ///
481     /// @return Ok(i32) 成功返回0
482     ///
483     /// @return Err(SystemError) 失败返回错误码
484     pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
485         if size > PAGE_1G_SIZE || size == 0 {
486             return Err(SystemError::EPERM);
487         }
488         // 计算前导0
489         #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
490         let mut size_exp: u32 = 63 - size.leading_zeros();
491         // kdebug!("create_mmio: size_exp: {}", size_exp);
492         // 记录最终申请的空间大小
493         let mut new_size = size;
494         // 对齐要申请的空间大小
495         // 如果要申请的空间大小小于4k,则分配4k
496         if size_exp < PAGE_4K_SHIFT as u32 {
497             new_size = PAGE_4K_SIZE;
498             size_exp = PAGE_4K_SHIFT as u32;
499         } else if (new_size & (!(1 << size_exp))) != 0 {
500             // 向左对齐空间大小
501             size_exp += 1;
502             new_size = 1 << size_exp;
503         }
504         match self.mmio_buddy_query_addr_region(size_exp) {
505             Ok(region) => {
506                 let space_guard =
507                     unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) };
508                 return Ok(space_guard);
509             }
510             Err(_) => {
511                 kerror!(
512                     "failed to create mmio. pid = {:?}",
513                     ProcessManager::current_pcb().pid()
514                 );
515                 return Err(SystemError::ENOMEM);
516             }
517         }
518     }
519 
520     /// @brief 取消mmio的映射并将地址空间归还到buddy中
521     ///
522     /// @param vaddr 起始的虚拟地址
523     ///
524     /// @param length 要归还的地址空间的长度
525     ///
526     /// @return Ok(i32) 成功返回0
527     ///
528     /// @return Err(SystemError) 失败返回错误码
529     pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
530         assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
531         assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
532         if vaddr < self.pool_start_addr
533             || vaddr.data() >= self.pool_start_addr.data() + self.pool_size
534         {
535             return Err(SystemError::EINVAL);
536         }
537         // todo: 重构MMIO管理机制,创建类似全局的manager之类的,管理MMIO的空间?
538 
539         // 暂时认为传入的vaddr都是正确的
540         let page_count = length / MMArch::PAGE_SIZE;
541         // 取消映射
542         let mut bindings = KernelMapper::lock();
543         let mut kernel_mapper = bindings.as_mut();
544         if kernel_mapper.is_none() {
545             kwarn!("release_mmio: kernel_mapper is read only");
546             return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
547         }
548 
549         for i in 0..page_count {
550             unsafe {
551                 let x: Option<(
552                     PhysAddr,
553                     PageFlags<MMArch>,
554                     crate::mm::page::PageFlush<MMArch>,
555                 )> = kernel_mapper
556                     .as_mut()
557                     .unwrap()
558                     .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, false);
559                 if let Some((_, _, flush)) = x {
560                     flush.flush();
561                 }
562             };
563         }
564 
565         // 归还到buddy
566         mmio_pool()
567             .give_back_block(vaddr, length.trailing_zeros())
568             .unwrap_or_else(|err| {
569                 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
570             });
571 
572         return Ok(0);
573     }
574 }
575 
576 /// @brief mmio伙伴系统内部的地址区域结构体
577 #[derive(Debug, Clone)]
578 struct MmioBuddyAddrRegion {
579     vaddr: VirtAddr,
580 }
581 impl MmioBuddyAddrRegion {
582     pub fn new(vaddr: VirtAddr) -> Self {
583         return MmioBuddyAddrRegion { vaddr };
584     }
585 
586     #[allow(dead_code)]
587     pub fn vaddr(&self) -> VirtAddr {
588         return self.vaddr;
589     }
590 }
591 
592 /// @brief 空闲页数组结构体
593 #[derive(Debug, Default)]
594 pub struct MmioFreeRegionList {
595     /// 存储mmio_buddy的地址链表
596     list: LinkedList<MmioBuddyAddrRegion>,
597     /// 空闲块的数量
598     num_free: i64,
599 }
600 impl MmioFreeRegionList {
601     #[allow(dead_code)]
602     fn new() -> Self {
603         return MmioFreeRegionList {
604             ..Default::default()
605         };
606     }
607 }
608 
609 /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
610 ///
611 /// @param exp内存大小
612 ///
613 /// @return 内存池数组下标
614 #[inline(always)]
615 fn exp2index(exp: u32) -> usize {
616     return (exp - 12) as usize;
617 }
618 
619 #[derive(Debug)]
620 pub struct MMIOSpaceGuard {
621     vaddr: VirtAddr,
622     size: usize,
623     mapped: AtomicBool,
624 }
625 
626 impl MMIOSpaceGuard {
627     pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self {
628         // check size
629         assert!(
630             size & (MMArch::PAGE_SIZE - 1) == 0,
631             "MMIO space size must be page aligned"
632         );
633         assert!(size.is_power_of_two(), "MMIO space size must be power of 2");
634         assert!(
635             vaddr.check_aligned(size),
636             "MMIO space vaddr must be aligned with size"
637         );
638         assert!(
639             vaddr.data() >= MMArch::MMIO_BASE.data()
640                 && vaddr.data() + size <= MMArch::MMIO_TOP.data(),
641             "MMIO space must be in MMIO region"
642         );
643 
644         // 人工创建的MMIO空间,认为已经映射
645         MMIOSpaceGuard {
646             vaddr,
647             size,
648             mapped: AtomicBool::new(mapped),
649         }
650     }
651 
652     pub fn vaddr(&self) -> VirtAddr {
653         self.vaddr
654     }
655 
656     pub fn size(&self) -> usize {
657         self.size
658     }
659 
660     /// 将物理地址填写到虚拟地址空间中
661     ///
662     /// ## Safety
663     ///
664     /// 传入的物理地址【一定要是设备的物理地址】。
665     /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
666     pub unsafe fn map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError> {
667         if length > self.size {
668             return Err(SystemError::EINVAL);
669         }
670 
671         let check = self
672             .mapped
673             .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
674         if check.is_err() {
675             return Err(SystemError::EINVAL);
676         }
677 
678         let flags = PageFlags::mmio_flags();
679         let mut kernel_mapper = KernelMapper::lock();
680         let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
681         return r;
682     }
683 
684     /// 泄露一个MMIO space guard,不会释放映射的空间
685     pub unsafe fn leak(self) {
686         core::mem::forget(self);
687     }
688 }
689 
690 impl Drop for MMIOSpaceGuard {
691     fn drop(&mut self) {
692         let _ = mmio_pool()
693             .release_mmio(self.vaddr, self.size)
694             .unwrap_or_else(|err| {
695                 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
696             });
697     }
698 }
699 
700 pub fn mmio_init() {
701     kdebug!("Initializing MMIO buddy memory pool...");
702     // 初始化mmio内存池
703     unsafe {
704         __MMIO_POOL = Some(MmioBuddyMemPool::new());
705     }
706 
707     kinfo!("MMIO buddy memory pool init done");
708 }
709