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