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