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, 8 PAGE_2M_SIZE, PAGE_4K_SHIFT, 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 { 41 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 { 50 fn new() -> Self { 51 return MmioBuddyMemPool { 52 ..Default::default() 53 }; 54 } 55 56 /// @brief 创建新的地址区域结构体 57 /// 58 /// @param vaddr 虚拟地址 59 /// 60 /// @return 创建好的地址区域结构体 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) 返回错误码 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】对应的链表 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 /// - 调用函数出错时,返回出错函数对应错误码 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的错误码。 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 目标链表 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)] 291 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 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 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调用出错,返回其错误码 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 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) 失败返回错误码 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) 失败返回错误码 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 { 617 pub fn new() -> Self { 618 return MmioBuddyAddrRegion { 619 ..Default::default() 620 }; 621 } 622 } 623 impl Default for MmioBuddyAddrRegion { 624 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)] 640 fn new() -> Self { 641 return MmioFreeRegionList { 642 ..Default::default() 643 }; 644 } 645 } 646 impl Default for MmioFreeRegionList { 647 fn default() -> Self { 648 MmioFreeRegionList { 649 list: Default::default(), 650 num_free: 0, 651 } 652 } 653 } 654 655 /// @brief 初始化mmio的伙伴系统 656 #[no_mangle] 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)] 680 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] 696 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] 719 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