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