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