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