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