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