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