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