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