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