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