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