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 {
default() -> Self40     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 {
new() -> Self49     fn new() -> Self {
50         return MmioBuddyMemPool {
51             ..Default::default()
52         };
53     }
54 
55     /// @brief 创建新的地址区域结构体
56     ///
57     /// @param vaddr 虚拟地址
58     ///
59     /// @return 创建好的地址区域结构体
create_region(&self, vaddr: u64) -> Box<MmioBuddyAddrRegion>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) 返回错误码
give_back_block(&self, vaddr: u64, exp: u32) -> Result<i32, 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】对应的链表
split_block( &self, region: Box<MmioBuddyAddrRegion>, exp: u32, low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, )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     /// - 调用函数出错时,返回出错函数对应错误码
query_addr_region( &self, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult>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                 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
138                     &mut self.free_regions[exp2index(e) as usize].lock();
139                 if pop_list.num_free == 0 {
140                     continue;
141                 }
142 
143                 for e2 in (exp + 1..e + 1).rev() {
144                     if e2 == e {
145                         match self.pop_block(pop_list) {
146                             Ok(region) => {
147                                 if e2 != exp + 1 {
148                                     // 要将分裂后的内存块插入到更小的链表中
149                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
150                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
151                                     self.split_block(region, e2, low_list_guard);
152                                 } else {
153                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
154                                     // 所以直接将list_guard传入
155                                     self.split_block(region, e2, list_guard);
156                                 }
157                             }
158                             Err(err) => {
159                                 kdebug!("buddy_pop_region get wrong");
160                                 return Err(err);
161                             }
162                         }
163                     } else {
164                         match self.pop_block(&mut self.free_regions[exp2index(e2) as usize].lock())
165                         {
166                             Ok(region) => {
167                                 if e2 != exp + 1 {
168                                     // 要将分裂后的内存块插入到更小的链表中
169                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
170                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
171                                     self.split_block(region, e2, low_list_guard);
172                                 } else {
173                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
174                                     // 所以直接将list_guard传入
175                                     self.split_block(region, e2, list_guard);
176                                 }
177                             }
178                             Err(err) => {
179                                 kdebug!("buddy_pop_region get wrong");
180                                 return Err(err);
181                             }
182                         }
183                     }
184                 }
185                 break;
186             }
187             // 判断是否获得了exp大小的内存块
188             if list_guard.num_free > 0 {
189                 match self.pop_block(list_guard) {
190                     Ok(ret) => return Ok(ret),
191                     Err(err) => return Err(err),
192                 }
193             }
194             // 拆分大内存块无法获得exp大小内存块
195             // 尝试用小内存块合成
196             // 即将两块exp合成一块exp+1
197 
198             // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
199             // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
200             //     if let Err(err) = self.merge_all_exp(
201             //         exp,
202             //         &mut self.free_regions[exp2index(exp) as usize].lock(),
203             //         high_list_guard,
204             //     ) {
205             //         return err;
206             //     } else {
207             //         return MmioResult::SUCCESS;
208             //     }
209             // };
210             for e in MMIO_BUDDY_MIN_EXP..exp {
211                 if e != exp - 1 {
212                     match self.merge_all_exp(
213                         exp,
214                         &mut self.free_regions[exp2index(exp) as usize].lock(),
215                         &mut self.free_regions[exp2index(exp + 1)].lock(),
216                     ) {
217                         Ok(_) => continue,
218                         Err(err) => {
219                             kdebug!("merge_all_exp get wrong");
220                             return Err(err);
221                         }
222                     }
223                 } else {
224                     match self.merge_all_exp(
225                         exp,
226                         &mut self.free_regions[exp2index(exp) as usize].lock(),
227                         list_guard,
228                     ) {
229                         Ok(_) => continue,
230                         Err(err) => {
231                             kdebug!("merge_all_exp get wrong");
232                             return Err(err);
233                         }
234                     }
235                 }
236             }
237 
238             //判断是否获得了exp大小的内存块
239             if list_guard.num_free > 0 {
240                 match self.pop_block(list_guard) {
241                     Ok(ret) => return Ok(ret),
242                     Err(err) => return Err(err),
243                 }
244             }
245             return Err(MmioResult::ENOFOUND);
246         } else {
247             match self.pop_block(list_guard) {
248                 Ok(ret) => return Ok(ret),
249                 Err(err) => return Err(err),
250             }
251         }
252     }
253 
254     /// @brief 对query_addr_region进行封装
255     ///
256     /// @param exp 内存区域的大小(2^exp)
257     ///
258     /// @return Ok(Box<MmioBuddyAddrRegion>)符合要求的内存块信息结构体。
259     /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
mmio_buddy_query_addr_region( &self, exp: u32, ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult>260     fn mmio_buddy_query_addr_region(
261         &self,
262         exp: u32,
263     ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
264         let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
265             &mut self.free_regions[exp2index(exp)].lock();
266         match self.query_addr_region(exp, list_guard) {
267             Ok(ret) => return Ok(ret),
268             Err(err) => {
269                 kdebug!("mmio_buddy_query_addr_region failed");
270                 return Err(err);
271             }
272         }
273     }
274     /// @brief 往指定的地址空间链表中添加一个地址区域
275     ///
276     /// @param region 要被添加的地址结构体
277     ///
278     /// @param list_guard 目标链表
push_block( &self, region: Box<MmioBuddyAddrRegion>, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, )279     fn push_block(
280         &self,
281         region: Box<MmioBuddyAddrRegion>,
282         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
283     ) {
284         list_guard.list.push_back(region);
285         list_guard.num_free += 1;
286     }
287 
288     /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
289     #[inline(always)]
calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64290     fn calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 {
291         return vaddr ^ (1 << exp);
292     }
293 
294     /// @brief 寻找并弹出指定内存块的伙伴块
295     ///
296     /// @param region 对应内存块的信息
297     ///
298     /// @param exp 内存块大小
299     ///
300     /// @param list_guard 【exp】对应的链表
301     ///
302     /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
303     /// @return Err(MmioResult)
304     /// - 当链表为空,返回ISEMPTY
305     /// - 没有找到伙伴块,返回ENOFOUND
pop_buddy_block( &self, vaddr: u64, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult>306     fn pop_buddy_block(
307         &self,
308         vaddr: u64,
309         exp: u32,
310         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
311     ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
312         if list_guard.list.len() == 0 {
313             return Err(MmioResult::ISEMPTY);
314         } else {
315             //计算伙伴块的地址
316             let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
317 
318             // element 只会有一个元素
319             let mut element: Vec<Box<MmioBuddyAddrRegion>> = list_guard
320                 .list
321                 .drain_filter(|x| x.vaddr == buddy_vaddr)
322                 .collect();
323             if element.len() == 1 {
324                 list_guard.num_free -= 1;
325                 return Ok(element.pop().unwrap());
326             }
327 
328             //没有找到对应的伙伴块
329             return Err(MmioResult::ENOFOUND);
330         }
331     }
332 
333     /// @brief 从指定空闲链表中取出内存区域
334     ///
335     /// @param list_guard 【exp】对应的链表
336     ///
337     /// @return Ok(Box<MmioBuddyAddrRegion>) 内存块信息结构体的引用。
338     ///
339     /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
pop_block( &self, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult>340     fn pop_block(
341         &self,
342         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
343     ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
344         if !list_guard.list.is_empty() {
345             list_guard.num_free -= 1;
346             return Ok(list_guard.list.pop_back().unwrap());
347         }
348         return Err(MmioResult::ISEMPTY);
349     }
350 
351     /// @brief 合并所有2^{exp}大小的内存块
352     ///
353     /// @param exp 内存块大小的幂(2^exp)
354     ///
355     /// @param list_guard exp对应的链表
356     ///
357     /// @param high_list_guard exp+1对应的链表
358     ///
359     /// @return Ok(MmioResult) 合并成功返回SUCCESS
360     /// @return Err(MmioResult)
361     /// - 内存块过少,无法合并,返回EINVAL
362     /// - pop_buddy_block调用出错,返回其错误码
363     /// - merge_blocks调用出错,返回其错误码
merge_all_exp( &self, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioResult, MmioResult>364     fn merge_all_exp(
365         &self,
366         exp: u32,
367         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
368         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
369     ) -> Result<MmioResult, MmioResult> {
370         // 至少要两个内存块才能合并
371         if list_guard.num_free <= 1 {
372             return Err(MmioResult::EINVAL);
373         }
374         loop {
375             if list_guard.num_free <= 1 {
376                 break;
377             }
378             // 获取内存块
379             let vaddr: u64 = list_guard.list.back().unwrap().vaddr;
380             // 获取伙伴内存块
381             match self.pop_buddy_block(vaddr, exp, list_guard) {
382                 Err(err) => {
383                     return Err(err);
384                 }
385                 Ok(buddy_region) => {
386                     let region: Box<MmioBuddyAddrRegion> = list_guard.list.pop_back().unwrap();
387                     let copy_region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion {
388                         vaddr: region.vaddr,
389                     });
390                     // 在两块内存都被取出之后才进行合并
391                     match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
392                         Err(err) => {
393                             // 如果合并失败了要将取出来的元素放回去
394                             self.push_block(copy_region, list_guard);
395                             kdebug!("merge_all_exp: merge_blocks failed");
396                             return Err(err);
397                         }
398                         Ok(_) => continue,
399                     }
400                 }
401             }
402         }
403         return Ok(MmioResult::SUCCESS);
404     }
405 
406     /// @brief 合并两个【已经从链表中取出】的内存块
407     ///
408     /// @param region_1 第一个内存块
409     ///
410     /// @param region_2 第二个内存
411     ///
412     /// @return Ok(MmioResult) 成功返回SUCCESS
413     ///
414     /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
merge_blocks( &self, region_1: Box<MmioBuddyAddrRegion>, region_2: Box<MmioBuddyAddrRegion>, exp: u32, high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioResult, MmioResult>415     fn merge_blocks(
416         &self,
417         region_1: Box<MmioBuddyAddrRegion>,
418         region_2: Box<MmioBuddyAddrRegion>,
419         exp: u32,
420         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
421     ) -> Result<MmioResult, MmioResult> {
422         // 判断是否为伙伴块
423         if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
424             return Err(MmioResult::EINVAL);
425         }
426         // 将大的块放进下一级链表
427         self.push_block(region_1, high_list_guard);
428         return Ok(MmioResult::SUCCESS);
429     }
430 
431     /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
432     ///
433     /// @param size mmio区域的大小(字节)
434     ///
435     /// @param vm_flags 要把vma设置成的标志
436     ///
437     /// @param res_vaddr 返回值-分配得到的虚拟地址
438     ///
439     /// @param res_length 返回值-分配的虚拟地址空间长度
440     ///
441     /// @return Ok(i32) 成功返回0
442     ///
443     /// @return Err(i32) 失败返回错误码
create_mmio( &self, size: u32, vm_flags: vm_flags_t, res_vaddr: *mut u64, res_length: *mut u64, ) -> Result<i32, i32>444     pub fn create_mmio(
445         &self,
446         size: u32,
447         vm_flags: vm_flags_t,
448         res_vaddr: *mut u64,
449         res_length: *mut u64,
450     ) -> Result<i32, i32> {
451         if size > PAGE_1G_SIZE || size == 0 {
452             return Err(-(EPERM as i32));
453         }
454         let mut retval: i32 = 0;
455         // 计算前导0
456         let mut size_exp: u32 = 31 - size.leading_zeros();
457         // 记录最终申请的空间大小
458         let mut new_size: u32 = size;
459         // 对齐要申请的空间大小
460         // 如果要申请的空间大小小于4k,则分配4k
461         if size_exp < PAGE_4K_SHIFT {
462             new_size = PAGE_4K_SIZE;
463             size_exp = PAGE_4K_SHIFT;
464         } else if (new_size & (!(1 << size_exp))) != 0 {
465             // 向左对齐空间大小
466             size_exp += 1;
467             new_size = 1 << size_exp;
468         }
469         match MMIO_POOL.mmio_buddy_query_addr_region(size_exp) {
470             Ok(region) => {
471                 unsafe {
472                     *res_vaddr = region.vaddr;
473                     *res_length = new_size as u64;
474                 }
475                 // 创建vma
476                 let flags: u64 = vm_flags | (VM_IO | VM_DONTCOPY) as u64;
477                 let len_4k: u64 = (new_size % PAGE_2M_SIZE) as u64;
478                 let len_2m: u64 = new_size as u64 - len_4k;
479                 let mut loop_i: u64 = 0;
480                 // 先分配2M的vma
481                 loop {
482                     if loop_i >= len_2m {
483                         break;
484                     }
485                     let vma: *mut *mut vm_area_struct = null_mut();
486                     retval = unsafe {
487                         mm_create_vma(
488                             &mut initial_mm,
489                             region.vaddr + loop_i,
490                             PAGE_2M_SIZE.into(),
491                             flags,
492                             null_mut(),
493                             vma,
494                         )
495                     };
496                     if retval != 0 {
497                         kdebug!(
498                             "failed to create mmio 2m vma. pid = {:?}",
499                             current_pcb().pid
500                         );
501                         unsafe {
502                             vm_area_del(*vma);
503                             vm_area_free(*vma);
504                         }
505                         return Err(retval);
506                     }
507                     loop_i += PAGE_2M_SIZE as u64;
508                 }
509                 // 分配4K的vma
510                 loop_i = len_2m;
511                 loop {
512                     if loop_i >= size as u64 {
513                         break;
514                     }
515                     let vma: *mut *mut vm_area_struct = null_mut();
516                     retval = unsafe {
517                         mm_create_vma(
518                             &mut initial_mm,
519                             region.vaddr + loop_i,
520                             PAGE_4K_SIZE.into(),
521                             flags,
522                             null_mut(),
523                             vma,
524                         )
525                     };
526                     if retval != 0 {
527                         kdebug!(
528                             "failed to create mmio 4k vma. pid = {:?}",
529                             current_pcb().pid
530                         );
531                         unsafe {
532                             vm_area_del(*vma);
533                             vm_area_free(*vma);
534                         }
535                         return Err(retval);
536                     }
537                     loop_i += PAGE_4K_SIZE as u64;
538                 }
539             }
540             Err(_) => {
541                 kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid);
542                 return Err(-(ENOMEM as i32));
543             }
544         }
545         return Ok(retval);
546     }
547 
548     /// @brief 取消mmio的映射并将地址空间归还到buddy中
549     ///
550     /// @param vaddr 起始的虚拟地址
551     ///
552     /// @param length 要归还的地址空间的长度
553     ///
554     /// @return Ok(i32) 成功返回0
555     ///
556     /// @return Err(i32) 失败返回错误码
release_mmio(&self, vaddr: u64, length: u64) -> Result<i32, i32>557     pub fn release_mmio(&self, vaddr: u64, length: u64) -> Result<i32, i32> {
558         //先将要释放的空间取消映射
559         unsafe {
560             mm_unmap(&mut initial_mm, vaddr, length, false);
561         }
562         let mut loop_i: u64 = 0;
563         loop {
564             if loop_i >= length {
565                 break;
566             }
567             // 获取要释放的vma的结构体
568             let vma: *mut vm_area_struct = unsafe { vma_find(&mut initial_mm, vaddr + loop_i) };
569             if vma == null_mut() {
570                 kdebug!(
571                     "mmio_release failed: vma not found. At address: {:?}, pid = {:?}",
572                     vaddr + loop_i,
573                     current_pcb().pid
574                 );
575                 return Err(-(EINVAL as i32));
576             }
577             // 检查vma起始地址是否正确
578             if unsafe { (*vma).vm_start != (vaddr + loop_i) } {
579                 kdebug!(
580                     "mmio_release failed: addr_start is not equal to current: {:?}. pid = {:?}",
581                     vaddr + loop_i,
582                     current_pcb().pid
583                 );
584                 return Err(-(EINVAL as i32));
585             }
586             // 将vma对应空间归还
587             match MMIO_POOL.give_back_block(unsafe { (*vma).vm_start }, unsafe {
588                 31 - ((*vma).vm_end - (*vma).vm_start).leading_zeros()
589             }) {
590                 Ok(_) => {
591                     loop_i += unsafe { (*vma).vm_end - (*vma).vm_start };
592                     unsafe {
593                         vm_area_del(vma);
594                         vm_area_free(vma);
595                     }
596                 }
597                 Err(err) => {
598                     // vma对应空间没有成功归还的话,就不删除vma
599                     kdebug!(
600                         "mmio_release give_back failed: pid = {:?}",
601                         current_pcb().pid
602                     );
603                     return Err(err);
604                 }
605             }
606         }
607         return Ok(0);
608     }
609 }
610 
611 /// @brief mmio伙伴系统内部的地址区域结构体
612 pub struct MmioBuddyAddrRegion {
613     vaddr: u64,
614 }
615 impl MmioBuddyAddrRegion {
new() -> Self616     pub fn new() -> Self {
617         return MmioBuddyAddrRegion {
618             ..Default::default()
619         };
620     }
621 }
622 impl Default for MmioBuddyAddrRegion {
default() -> Self623     fn default() -> Self {
624         MmioBuddyAddrRegion {
625             vaddr: Default::default(),
626         }
627     }
628 }
629 
630 /// @brief 空闲页数组结构体
631 pub struct MmioFreeRegionList {
632     /// 存储mmio_buddy的地址链表
633     list: LinkedList<Box<MmioBuddyAddrRegion>>,
634     /// 空闲块的数量
635     num_free: i64,
636 }
637 impl MmioFreeRegionList {
new() -> Self638     fn new() -> Self {
639         return MmioFreeRegionList {
640             ..Default::default()
641         };
642     }
643 }
644 impl Default for MmioFreeRegionList {
default() -> Self645     fn default() -> Self {
646         MmioFreeRegionList {
647             list: Default::default(),
648             num_free: 0,
649         }
650     }
651 }
652 
653 /// @brief 初始化mmio的伙伴系统
654 #[no_mangle]
__mmio_buddy_init()655 pub extern "C" fn __mmio_buddy_init() {
656     // 创建一堆1GB的地址块
657     let cnt_1g_blocks: u32 = ((MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE as i64) as u32;
658     let mut vaddr_base: u64 = MMIO_BASE as u64;
659     for _ in 0..cnt_1g_blocks {
660         match MMIO_POOL.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
661             Ok(_) => {
662                 vaddr_base += PAGE_1G_SIZE as u64;
663             }
664             Err(_) => {
665                 kerror!("__mmio_buddy_init failed");
666                 return;
667             }
668         }
669     }
670 }
671 
672 /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
673 ///
674 /// @param exp内存大小
675 ///
676 /// @return 内存池数组下标
677 #[inline(always)]
exp2index(exp: u32) -> usize678 fn exp2index(exp: u32) -> usize {
679     return (exp - 12) as usize;
680 }
681 
682 /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
683 ///
684 /// @param size mmio区域的大小(字节)
685 ///
686 /// @param vm_flags 要把vma设置成的标志
687 ///
688 /// @param res_vaddr 返回值-分配得到的虚拟地址
689 ///
690 /// @param res_length 返回值-分配的虚拟地址空间长度
691 ///
692 /// @return int 错误码
693 #[no_mangle]
mmio_create( size: u32, vm_flags: vm_flags_t, res_vaddr: *mut u64, res_length: *mut u64, ) -> i32694 pub extern "C" fn mmio_create(
695     size: u32,
696     vm_flags: vm_flags_t,
697     res_vaddr: *mut u64,
698     res_length: *mut u64,
699 ) -> i32 {
700     if let Err(err) = MMIO_POOL.create_mmio(size, vm_flags, res_vaddr, res_length) {
701         return err;
702     } else {
703         return 0;
704     }
705 }
706 
707 /// @brief 取消mmio的映射并将地址空间归还到buddy中
708 ///
709 /// @param vaddr 起始的虚拟地址
710 ///
711 /// @param length 要归还的地址空间的长度
712 ///
713 /// @return Ok(i32) 成功返回0
714 ///
715 /// @return Err(i32) 失败返回错误码
716 #[no_mangle]
mmio_release(vaddr: u64, length: u64) -> i32717 pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
718     if let Err(err) = MMIO_POOL.release_mmio(vaddr, length) {
719         return err;
720     } else {
721         return 0;
722     }
723 }
724