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