1 use core::{ 2 fmt::{self, Debug, Error, Formatter}, 3 marker::PhantomData, 4 mem, 5 ops::Add, 6 sync::atomic::{compiler_fence, Ordering}, 7 }; 8 9 use alloc::sync::Arc; 10 use hashbrown::{HashMap, HashSet}; 11 12 use crate::{ 13 arch::{interrupt::ipi::send_ipi, MMArch}, 14 exception::ipi::{IpiKind, IpiTarget}, 15 ipc::shm::ShmId, 16 kerror, kwarn, 17 libs::spinlock::{SpinLock, SpinLockGuard}, 18 }; 19 20 use super::{ 21 allocator::page_frame::FrameAllocator, syscall::ProtFlags, ucontext::LockedVMA, 22 MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, 23 }; 24 25 pub const PAGE_4K_SHIFT: usize = 12; 26 #[allow(dead_code)] 27 pub const PAGE_2M_SHIFT: usize = 21; 28 pub const PAGE_1G_SHIFT: usize = 30; 29 30 /// 全局物理页信息管理器 31 pub static mut PAGE_MANAGER: Option<SpinLock<PageManager>> = None; 32 33 /// 初始化PAGE_MANAGER 34 pub fn page_manager_init() { 35 kinfo!("page_manager_init"); 36 let page_manager = SpinLock::new(PageManager::new()); 37 38 compiler_fence(Ordering::SeqCst); 39 unsafe { PAGE_MANAGER = Some(page_manager) }; 40 compiler_fence(Ordering::SeqCst); 41 42 kinfo!("page_manager_init done"); 43 } 44 45 pub fn page_manager_lock_irqsave() -> SpinLockGuard<'static, PageManager> { 46 unsafe { PAGE_MANAGER.as_ref().unwrap().lock_irqsave() } 47 } 48 49 // 物理页管理器 50 pub struct PageManager { 51 phys2page: HashMap<PhysAddr, Page>, 52 } 53 54 impl PageManager { 55 pub fn new() -> Self { 56 Self { 57 phys2page: HashMap::new(), 58 } 59 } 60 61 pub fn contains(&self, paddr: &PhysAddr) -> bool { 62 self.phys2page.contains_key(paddr) 63 } 64 65 pub fn get(&self, paddr: &PhysAddr) -> Option<&Page> { 66 self.phys2page.get(paddr) 67 } 68 69 pub fn get_mut(&mut self, paddr: &PhysAddr) -> &mut Page { 70 self.phys2page.get_mut(paddr).unwrap() 71 } 72 73 pub fn insert(&mut self, paddr: PhysAddr, page: Page) { 74 self.phys2page.insert(paddr, page); 75 } 76 77 pub fn remove_page(&mut self, paddr: &PhysAddr) { 78 self.phys2page.remove(paddr); 79 } 80 } 81 82 /// 物理页面信息 83 pub struct Page { 84 /// 映射计数 85 map_count: usize, 86 /// 是否为共享页 87 shared: bool, 88 /// 映射计数为0时,是否可回收 89 free_when_zero: bool, 90 /// 共享页id(如果是共享页) 91 shm_id: Option<ShmId>, 92 /// 映射到当前page的VMA 93 anon_vma: HashSet<Arc<LockedVMA>>, 94 } 95 96 impl Page { 97 pub fn new(shared: bool) -> Self { 98 let dealloc_when_zero = !shared; 99 Self { 100 map_count: 0, 101 shared, 102 free_when_zero: dealloc_when_zero, 103 shm_id: None, 104 anon_vma: HashSet::new(), 105 } 106 } 107 108 /// 将vma加入anon_vma 109 pub fn insert_vma(&mut self, vma: Arc<LockedVMA>) { 110 self.anon_vma.insert(vma); 111 self.map_count += 1; 112 } 113 114 /// 将vma从anon_vma中删去 115 pub fn remove_vma(&mut self, vma: &LockedVMA) { 116 self.anon_vma.remove(vma); 117 self.map_count -= 1; 118 } 119 120 /// 判断当前物理页是否能被回 121 pub fn can_deallocate(&self) -> bool { 122 self.map_count == 0 && self.free_when_zero 123 } 124 125 pub fn shared(&self) -> bool { 126 self.shared 127 } 128 129 pub fn shm_id(&self) -> Option<ShmId> { 130 self.shm_id 131 } 132 133 pub fn set_shm_id(&mut self, shm_id: ShmId) { 134 self.shm_id = Some(shm_id); 135 } 136 137 pub fn set_dealloc_when_zero(&mut self, dealloc_when_zero: bool) { 138 self.free_when_zero = dealloc_when_zero; 139 } 140 141 pub fn anon_vma(&self) -> &HashSet<Arc<LockedVMA>> { 142 &self.anon_vma 143 } 144 } 145 146 #[derive(Debug)] 147 pub struct PageTable<Arch> { 148 /// 当前页表表示的虚拟地址空间的起始地址 149 base: VirtAddr, 150 /// 当前页表所在的物理地址 151 phys: PhysAddr, 152 /// 当前页表的层级(请注意,最顶级页表的level为[Arch::PAGE_LEVELS - 1]) 153 level: usize, 154 phantom: PhantomData<Arch>, 155 } 156 157 #[allow(dead_code)] 158 impl<Arch: MemoryManagementArch> PageTable<Arch> { 159 pub unsafe fn new(base: VirtAddr, phys: PhysAddr, level: usize) -> Self { 160 Self { 161 base, 162 phys, 163 level, 164 phantom: PhantomData, 165 } 166 } 167 168 /// 获取顶级页表 169 /// 170 /// ## 参数 171 /// 172 /// - table_kind 页表类型 173 /// 174 /// ## 返回值 175 /// 176 /// 返回顶级页表 177 pub unsafe fn top_level_table(table_kind: PageTableKind) -> Self { 178 return Self::new( 179 VirtAddr::new(0), 180 Arch::table(table_kind), 181 Arch::PAGE_LEVELS - 1, 182 ); 183 } 184 185 /// 获取当前页表的物理地址 186 #[inline(always)] 187 pub fn phys(&self) -> PhysAddr { 188 self.phys 189 } 190 191 /// 当前页表表示的虚拟地址空间的起始地址 192 #[inline(always)] 193 pub fn base(&self) -> VirtAddr { 194 self.base 195 } 196 197 /// 获取当前页表的层级 198 #[inline(always)] 199 pub fn level(&self) -> usize { 200 self.level 201 } 202 203 /// 获取当前页表自身所在的虚拟地址 204 #[inline(always)] 205 pub unsafe fn virt(&self) -> VirtAddr { 206 return Arch::phys_2_virt(self.phys).unwrap(); 207 } 208 209 /// 获取第i个页表项所表示的虚拟内存空间的起始地址 210 pub fn entry_base(&self, i: usize) -> Option<VirtAddr> { 211 if i < Arch::PAGE_ENTRY_NUM { 212 let shift = self.level * Arch::PAGE_ENTRY_SHIFT + Arch::PAGE_SHIFT; 213 return Some(self.base.add(i << shift)); 214 } else { 215 return None; 216 } 217 } 218 219 /// 获取当前页表的第i个页表项所在的虚拟地址(注意与entry_base进行区分) 220 pub unsafe fn entry_virt(&self, i: usize) -> Option<VirtAddr> { 221 if i < Arch::PAGE_ENTRY_NUM { 222 return Some(self.virt().add(i * Arch::PAGE_ENTRY_SIZE)); 223 } else { 224 return None; 225 } 226 } 227 228 /// 获取当前页表的第i个页表项 229 pub unsafe fn entry(&self, i: usize) -> Option<PageEntry<Arch>> { 230 let entry_virt = self.entry_virt(i)?; 231 return Some(PageEntry::from_usize(Arch::read::<usize>(entry_virt))); 232 } 233 234 /// 设置当前页表的第i个页表项 235 pub unsafe fn set_entry(&self, i: usize, entry: PageEntry<Arch>) -> Option<()> { 236 let entry_virt = self.entry_virt(i)?; 237 Arch::write::<usize>(entry_virt, entry.data()); 238 return Some(()); 239 } 240 241 /// 判断当前页表的第i个页表项是否已经填写了值 242 /// 243 /// ## 参数 244 /// - Some(true) 如果已经填写了值 245 /// - Some(false) 如果未填写值 246 /// - None 如果i超出了页表项的范围 247 pub fn entry_mapped(&self, i: usize) -> Option<bool> { 248 let etv = unsafe { self.entry_virt(i) }?; 249 if unsafe { Arch::read::<usize>(etv) } != 0 { 250 return Some(true); 251 } else { 252 return Some(false); 253 } 254 } 255 256 /// 根据虚拟地址,获取对应的页表项在页表中的下标 257 /// 258 /// ## 参数 259 /// 260 /// - addr: 虚拟地址 261 /// 262 /// ## 返回值 263 /// 264 /// 页表项在页表中的下标。如果addr不在当前页表所表示的虚拟地址空间中,则返回None 265 pub unsafe fn index_of(&self, addr: VirtAddr) -> Option<usize> { 266 let addr = VirtAddr::new(addr.data() & Arch::PAGE_ADDRESS_MASK); 267 let shift = self.level * Arch::PAGE_ENTRY_SHIFT + Arch::PAGE_SHIFT; 268 269 let mask = (MMArch::PAGE_ENTRY_NUM << shift) - 1; 270 if addr < self.base || addr >= self.base.add(mask) { 271 return None; 272 } else { 273 return Some((addr.data() >> shift) & MMArch::PAGE_ENTRY_MASK); 274 } 275 } 276 277 /// 获取第i个页表项指向的下一级页表 278 pub unsafe fn next_level_table(&self, index: usize) -> Option<Self> { 279 if self.level == 0 { 280 return None; 281 } 282 283 // 返回下一级页表 284 return Some(PageTable::new( 285 self.entry_base(index)?, 286 self.entry(index)?.address().ok()?, 287 self.level - 1, 288 )); 289 } 290 } 291 292 /// 页表项 293 #[derive(Copy, Clone)] 294 pub struct PageEntry<Arch> { 295 data: usize, 296 phantom: PhantomData<Arch>, 297 } 298 299 impl<Arch> Debug for PageEntry<Arch> { 300 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 301 f.write_fmt(format_args!("PageEntry({:#x})", self.data)) 302 } 303 } 304 305 impl<Arch: MemoryManagementArch> PageEntry<Arch> { 306 #[inline(always)] 307 pub fn new(paddr: PhysAddr, flags: PageFlags<Arch>) -> Self { 308 Self { 309 data: MMArch::make_entry(paddr, flags.data()), 310 phantom: PhantomData, 311 } 312 } 313 #[inline(always)] 314 pub fn from_usize(data: usize) -> Self { 315 Self { 316 data, 317 phantom: PhantomData, 318 } 319 } 320 321 #[inline(always)] 322 pub fn data(&self) -> usize { 323 self.data 324 } 325 326 /// 获取当前页表项指向的物理地址 327 /// 328 /// ## 返回值 329 /// 330 /// - Ok(PhysAddr) 如果当前页面存在于物理内存中, 返回物理地址 331 /// - Err(PhysAddr) 如果当前页表项不存在, 返回物理地址 332 #[inline(always)] 333 pub fn address(&self) -> Result<PhysAddr, PhysAddr> { 334 let paddr: PhysAddr = { 335 #[cfg(target_arch = "x86_64")] 336 { 337 PhysAddr::new(self.data & Arch::PAGE_ADDRESS_MASK) 338 } 339 340 #[cfg(target_arch = "riscv64")] 341 { 342 let ppn = ((self.data & (!((1 << 10) - 1))) >> 10) & ((1 << 54) - 1); 343 super::allocator::page_frame::PhysPageFrame::from_ppn(ppn).phys_address() 344 } 345 }; 346 347 if self.present() { 348 Ok(paddr) 349 } else { 350 Err(paddr) 351 } 352 } 353 354 #[inline(always)] 355 pub fn flags(&self) -> PageFlags<Arch> { 356 unsafe { PageFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) } 357 } 358 359 #[inline(always)] 360 pub fn set_flags(&mut self, flags: PageFlags<Arch>) { 361 self.data = (self.data & !Arch::ENTRY_FLAGS_MASK) | flags.data(); 362 } 363 364 #[inline(always)] 365 pub fn present(&self) -> bool { 366 return self.data & Arch::ENTRY_FLAG_PRESENT != 0; 367 } 368 } 369 370 /// 页表项的标志位 371 #[derive(Copy, Clone, Hash)] 372 pub struct PageFlags<Arch> { 373 data: usize, 374 phantom: PhantomData<Arch>, 375 } 376 377 #[allow(dead_code)] 378 impl<Arch: MemoryManagementArch> PageFlags<Arch> { 379 #[inline(always)] 380 pub fn new() -> Self { 381 let mut r = unsafe { 382 Self::from_data( 383 Arch::ENTRY_FLAG_DEFAULT_PAGE 384 | Arch::ENTRY_FLAG_READONLY 385 | Arch::ENTRY_FLAG_NO_EXEC, 386 ) 387 }; 388 389 #[cfg(target_arch = "x86_64")] 390 { 391 if crate::arch::mm::X86_64MMArch::is_xd_reserved() { 392 r = r.set_execute(true); 393 } 394 } 395 396 return r; 397 } 398 399 /// 根据ProtFlags生成PageFlags 400 /// 401 /// ## 参数 402 /// 403 /// - prot_flags: 页的保护标志 404 /// - user: 用户空间是否可访问 405 pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> PageFlags<Arch> { 406 let flags: PageFlags<Arch> = PageFlags::new() 407 .set_user(user) 408 .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC)) 409 .set_write(prot_flags.contains(ProtFlags::PROT_WRITE)); 410 411 return flags; 412 } 413 414 #[inline(always)] 415 pub fn data(&self) -> usize { 416 self.data 417 } 418 419 #[inline(always)] 420 pub const unsafe fn from_data(data: usize) -> Self { 421 return Self { 422 data, 423 phantom: PhantomData, 424 }; 425 } 426 427 /// 为新页表的页表项设置默认值 428 /// 429 /// 默认值为: 430 /// - present 431 /// - read only 432 /// - kernel space 433 /// - no exec 434 #[inline(always)] 435 pub fn new_page_table(user: bool) -> Self { 436 return unsafe { 437 let r = { 438 #[cfg(target_arch = "x86_64")] 439 { 440 Self::from_data(Arch::ENTRY_FLAG_DEFAULT_TABLE | Arch::ENTRY_FLAG_READWRITE) 441 } 442 443 #[cfg(target_arch = "riscv64")] 444 { 445 // riscv64指向下一级页表的页表项,不应设置R/W/X权限位 446 Self::from_data(Arch::ENTRY_FLAG_DEFAULT_TABLE) 447 } 448 }; 449 if user { 450 r.set_user(true) 451 } else { 452 r 453 } 454 }; 455 } 456 457 /// 取得当前页表项的所有权,更新当前页表项的标志位,并返回更新后的页表项。 458 /// 459 /// ## 参数 460 /// - flag 要更新的标志位的值 461 /// - value 如果为true,那么将flag对应的位设置为1,否则设置为0 462 /// 463 /// ## 返回值 464 /// 465 /// 更新后的页表项 466 #[inline(always)] 467 #[must_use] 468 pub fn update_flags(mut self, flag: usize, value: bool) -> Self { 469 if value { 470 self.data |= flag; 471 } else { 472 self.data &= !flag; 473 } 474 return self; 475 } 476 477 /// 判断当前页表项是否存在指定的flag(只有全部flag都存在才返回true) 478 #[inline(always)] 479 pub fn has_flag(&self, flag: usize) -> bool { 480 return self.data & flag == flag; 481 } 482 483 #[inline(always)] 484 pub fn present(&self) -> bool { 485 return self.has_flag(Arch::ENTRY_FLAG_PRESENT); 486 } 487 488 /// 设置当前页表项的权限 489 /// 490 /// @param value 如果为true,那么将当前页表项的权限设置为用户态可访问 491 #[must_use] 492 #[inline(always)] 493 pub fn set_user(self, value: bool) -> Self { 494 return self.update_flags(Arch::ENTRY_FLAG_USER, value); 495 } 496 497 /// 用户态是否可以访问当前页表项 498 #[inline(always)] 499 pub fn has_user(&self) -> bool { 500 return self.has_flag(Arch::ENTRY_FLAG_USER); 501 } 502 503 /// 设置当前页表项的可写性, 如果为true,那么将当前页表项的权限设置为可写, 否则设置为只读 504 /// 505 /// ## 返回值 506 /// 507 /// 更新后的页表项. 508 /// 509 /// **请注意,**本函数会取得当前页表项的所有权,因此返回的页表项不是原来的页表项 510 #[must_use] 511 #[inline(always)] 512 pub fn set_write(self, value: bool) -> Self { 513 #[cfg(target_arch = "x86_64")] 514 { 515 // 有的架构同时具有可写和不可写的标志位,因此需要同时更新 516 return self 517 .update_flags(Arch::ENTRY_FLAG_READONLY, !value) 518 .update_flags(Arch::ENTRY_FLAG_READWRITE, value); 519 } 520 521 #[cfg(target_arch = "riscv64")] 522 { 523 if value { 524 return self.update_flags(Arch::ENTRY_FLAG_READWRITE, true); 525 } else { 526 return self.update_flags(Arch::ENTRY_FLAG_READONLY, true); 527 } 528 } 529 } 530 531 /// 当前页表项是否可写 532 #[inline(always)] 533 pub fn has_write(&self) -> bool { 534 // 有的架构同时具有可写和不可写的标志位,因此需要同时判断 535 return self.data & (Arch::ENTRY_FLAG_READWRITE | Arch::ENTRY_FLAG_READONLY) 536 == Arch::ENTRY_FLAG_READWRITE; 537 } 538 539 /// 设置当前页表项的可执行性, 如果为true,那么将当前页表项的权限设置为可执行, 否则设置为不可执行 540 #[must_use] 541 #[inline(always)] 542 pub fn set_execute(self, mut value: bool) -> Self { 543 #[cfg(target_arch = "x86_64")] 544 { 545 // 如果xd位被保留,那么将可执行性设置为true 546 if crate::arch::mm::X86_64MMArch::is_xd_reserved() { 547 value = true; 548 } 549 } 550 551 // 有的架构同时具有可执行和不可执行的标志位,因此需要同时更新 552 return self 553 .update_flags(Arch::ENTRY_FLAG_NO_EXEC, !value) 554 .update_flags(Arch::ENTRY_FLAG_EXEC, value); 555 } 556 557 /// 当前页表项是否可执行 558 #[inline(always)] 559 pub fn has_execute(&self) -> bool { 560 // 有的架构同时具有可执行和不可执行的标志位,因此需要同时判断 561 return self.data & (Arch::ENTRY_FLAG_EXEC | Arch::ENTRY_FLAG_NO_EXEC) 562 == Arch::ENTRY_FLAG_EXEC; 563 } 564 565 /// 设置当前页表项的缓存策略 566 /// 567 /// ## 参数 568 /// 569 /// - value: 如果为true,那么将当前页表项的缓存策略设置为不缓存。 570 #[inline(always)] 571 pub fn set_page_cache_disable(self, value: bool) -> Self { 572 return self.update_flags(Arch::ENTRY_FLAG_CACHE_DISABLE, value); 573 } 574 575 /// 获取当前页表项的缓存策略 576 /// 577 /// ## 返回值 578 /// 579 /// 如果当前页表项的缓存策略为不缓存,那么返回true,否则返回false。 580 #[inline(always)] 581 pub fn has_page_cache_disable(&self) -> bool { 582 return self.has_flag(Arch::ENTRY_FLAG_CACHE_DISABLE); 583 } 584 585 /// 设置当前页表项的写穿策略 586 /// 587 /// ## 参数 588 /// 589 /// - value: 如果为true,那么将当前页表项的写穿策略设置为写穿。 590 #[inline(always)] 591 pub fn set_page_write_through(self, value: bool) -> Self { 592 return self.update_flags(Arch::ENTRY_FLAG_WRITE_THROUGH, value); 593 } 594 595 /// 获取当前页表项的写穿策略 596 /// 597 /// ## 返回值 598 /// 599 /// 如果当前页表项的写穿策略为写穿,那么返回true,否则返回false。 600 #[inline(always)] 601 pub fn has_page_write_through(&self) -> bool { 602 return self.has_flag(Arch::ENTRY_FLAG_WRITE_THROUGH); 603 } 604 605 /// MMIO内存的页表项标志 606 #[inline(always)] 607 pub fn mmio_flags() -> Self { 608 return Self::new() 609 .set_user(false) 610 .set_write(true) 611 .set_execute(true) 612 .set_page_cache_disable(true) 613 .set_page_write_through(true); 614 } 615 } 616 617 impl<Arch: MemoryManagementArch> fmt::Debug for PageFlags<Arch> { 618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 619 f.debug_struct("PageFlags") 620 .field("bits", &format_args!("{:#0x}", self.data)) 621 .field("present", &self.present()) 622 .field("has_write", &self.has_write()) 623 .field("has_execute", &self.has_execute()) 624 .field("has_user", &self.has_user()) 625 .finish() 626 } 627 } 628 629 /// 页表映射器 630 #[derive(Hash)] 631 pub struct PageMapper<Arch, F> { 632 /// 页表类型 633 table_kind: PageTableKind, 634 /// 根页表物理地址 635 table_paddr: PhysAddr, 636 /// 页分配器 637 frame_allocator: F, 638 phantom: PhantomData<fn() -> Arch>, 639 } 640 641 impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> { 642 /// 创建新的页面映射器 643 /// 644 /// ## 参数 645 /// - table_kind 页表类型 646 /// - table_paddr 根页表物理地址 647 /// - allocator 页分配器 648 /// 649 /// ## 返回值 650 /// 651 /// 页面映射器 652 pub unsafe fn new(table_kind: PageTableKind, table_paddr: PhysAddr, allocator: F) -> Self { 653 return Self { 654 table_kind, 655 table_paddr, 656 frame_allocator: allocator, 657 phantom: PhantomData, 658 }; 659 } 660 661 /// 创建页表,并为这个页表创建页面映射器 662 pub unsafe fn create(table_kind: PageTableKind, mut allocator: F) -> Option<Self> { 663 let table_paddr = allocator.allocate_one()?; 664 // 清空页表 665 let table_vaddr = Arch::phys_2_virt(table_paddr)?; 666 Arch::write_bytes(table_vaddr, 0, Arch::PAGE_SIZE); 667 return Some(Self::new(table_kind, table_paddr, allocator)); 668 } 669 670 /// 获取当前页表的页面映射器 671 #[inline(always)] 672 pub unsafe fn current(table_kind: PageTableKind, allocator: F) -> Self { 673 let table_paddr = Arch::table(table_kind); 674 return Self::new(table_kind, table_paddr, allocator); 675 } 676 677 /// 判断当前页表分配器所属的页表是否是当前页表 678 #[inline(always)] 679 pub fn is_current(&self) -> bool { 680 return unsafe { self.table().phys() == Arch::table(self.table_kind) }; 681 } 682 683 /// 将当前页表分配器所属的页表设置为当前页表 684 #[inline(always)] 685 pub unsafe fn make_current(&self) { 686 Arch::set_table(self.table_kind, self.table_paddr); 687 } 688 689 /// 获取当前页表分配器所属的根页表的结构体 690 #[inline(always)] 691 pub fn table(&self) -> PageTable<Arch> { 692 // 由于只能通过new方法创建PageMapper,因此这里假定table_paddr是有效的 693 return unsafe { 694 PageTable::new(VirtAddr::new(0), self.table_paddr, Arch::PAGE_LEVELS - 1) 695 }; 696 } 697 698 /// 获取当前PageMapper所对应的页分配器实例的引用 699 #[inline(always)] 700 #[allow(dead_code)] 701 pub fn allocator_ref(&self) -> &F { 702 return &self.frame_allocator; 703 } 704 705 /// 获取当前PageMapper所对应的页分配器实例的可变引用 706 #[inline(always)] 707 pub fn allocator_mut(&mut self) -> &mut F { 708 return &mut self.frame_allocator; 709 } 710 711 /// 从当前PageMapper的页分配器中分配一个物理页,并将其映射到指定的虚拟地址 712 pub unsafe fn map( 713 &mut self, 714 virt: VirtAddr, 715 flags: PageFlags<Arch>, 716 ) -> Option<PageFlush<Arch>> { 717 compiler_fence(Ordering::SeqCst); 718 let phys: PhysAddr = self.frame_allocator.allocate_one()?; 719 compiler_fence(Ordering::SeqCst); 720 721 let mut page_manager_guard: SpinLockGuard<'static, PageManager> = 722 page_manager_lock_irqsave(); 723 if !page_manager_guard.contains(&phys) { 724 page_manager_guard.insert(phys, Page::new(false)) 725 } 726 727 return self.map_phys(virt, phys, flags); 728 } 729 730 /// 映射一个物理页到指定的虚拟地址 731 pub unsafe fn map_phys( 732 &mut self, 733 virt: VirtAddr, 734 phys: PhysAddr, 735 flags: PageFlags<Arch>, 736 ) -> Option<PageFlush<Arch>> { 737 // 验证虚拟地址和物理地址是否对齐 738 if !(virt.check_aligned(Arch::PAGE_SIZE) && phys.check_aligned(Arch::PAGE_SIZE)) { 739 kerror!( 740 "Try to map unaligned page: virt={:?}, phys={:?}", 741 virt, 742 phys 743 ); 744 return None; 745 } 746 747 let virt = VirtAddr::new(virt.data() & (!Arch::PAGE_NEGATIVE_MASK)); 748 749 // TODO: 验证flags是否合法 750 751 // 创建页表项 752 let entry = PageEntry::new(phys, flags); 753 let mut table = self.table(); 754 loop { 755 let i = table.index_of(virt)?; 756 assert!(i < Arch::PAGE_ENTRY_NUM); 757 if table.level() == 0 { 758 // todo: 检查是否已经映射 759 // 现在不检查的原因是,刚刚启动系统时,内核会映射一些页。 760 if table.entry_mapped(i)? { 761 kwarn!("Page {:?} already mapped", virt); 762 } 763 764 compiler_fence(Ordering::SeqCst); 765 766 table.set_entry(i, entry); 767 compiler_fence(Ordering::SeqCst); 768 return Some(PageFlush::new(virt)); 769 } else { 770 let next_table = table.next_level_table(i); 771 if let Some(next_table) = next_table { 772 table = next_table; 773 // kdebug!("Mapping {:?} to next level table...", virt); 774 } else { 775 // 分配下一级页表 776 let frame = self.frame_allocator.allocate_one()?; 777 778 // 清空这个页帧 779 MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE); 780 781 // 设置页表项的flags 782 let flags: PageFlags<Arch> = 783 PageFlags::new_page_table(virt.kind() == PageTableKind::User); 784 785 // kdebug!("Flags: {:?}", flags); 786 787 // 把新分配的页表映射到当前页表 788 table.set_entry(i, PageEntry::new(frame, flags)); 789 790 // 获取新分配的页表 791 table = table.next_level_table(i)?; 792 } 793 } 794 } 795 } 796 797 /// 将物理地址映射到具有线性偏移量的虚拟地址 798 #[allow(dead_code)] 799 pub unsafe fn map_linearly( 800 &mut self, 801 phys: PhysAddr, 802 flags: PageFlags<Arch>, 803 ) -> Option<(VirtAddr, PageFlush<Arch>)> { 804 let virt: VirtAddr = Arch::phys_2_virt(phys)?; 805 return self.map_phys(virt, phys, flags).map(|flush| (virt, flush)); 806 } 807 808 /// 修改虚拟地址的页表项的flags,并返回页表项刷新器 809 /// 810 /// 请注意,需要在修改完flags后,调用刷新器的flush方法,才能使修改生效 811 /// 812 /// ## 参数 813 /// - virt 虚拟地址 814 /// - flags 新的页表项的flags 815 /// 816 /// ## 返回值 817 /// 818 /// 如果修改成功,返回刷新器,否则返回None 819 pub unsafe fn remap( 820 &mut self, 821 virt: VirtAddr, 822 flags: PageFlags<Arch>, 823 ) -> Option<PageFlush<Arch>> { 824 return self 825 .visit(virt, |p1, i| { 826 let mut entry = p1.entry(i)?; 827 entry.set_flags(flags); 828 p1.set_entry(i, entry); 829 Some(PageFlush::new(virt)) 830 }) 831 .flatten(); 832 } 833 834 /// 根据虚拟地址,查找页表,获取对应的物理地址和页表项的flags 835 /// 836 /// ## 参数 837 /// 838 /// - virt 虚拟地址 839 /// 840 /// ## 返回值 841 /// 842 /// 如果查找成功,返回物理地址和页表项的flags,否则返回None 843 pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, PageFlags<Arch>)> { 844 let entry: PageEntry<Arch> = self.visit(virt, |p1, i| unsafe { p1.entry(i) })??; 845 let paddr = entry.address().ok()?; 846 let flags = entry.flags(); 847 return Some((paddr, flags)); 848 } 849 850 /// 取消虚拟地址的映射,释放页面,并返回页表项刷新器 851 /// 852 /// 请注意,需要在取消映射后,调用刷新器的flush方法,才能使修改生效 853 /// 854 /// ## 参数 855 /// 856 /// - virt 虚拟地址 857 /// - unmap_parents 是否在父页表内,取消空闲子页表的映射 858 /// 859 /// ## 返回值 860 /// 如果取消成功,返回刷新器,否则返回None 861 #[allow(dead_code)] 862 pub unsafe fn unmap(&mut self, virt: VirtAddr, unmap_parents: bool) -> Option<PageFlush<Arch>> { 863 let (paddr, _, flusher) = self.unmap_phys(virt, unmap_parents)?; 864 self.frame_allocator.free_one(paddr); 865 return Some(flusher); 866 } 867 868 /// 取消虚拟地址的映射,并返回物理地址和页表项的flags 869 /// 870 /// ## 参数 871 /// 872 /// - vaddr 虚拟地址 873 /// - unmap_parents 是否在父页表内,取消空闲子页表的映射 874 /// 875 /// ## 返回值 876 /// 877 /// 如果取消成功,返回物理地址和页表项的flags,否则返回None 878 pub unsafe fn unmap_phys( 879 &mut self, 880 virt: VirtAddr, 881 unmap_parents: bool, 882 ) -> Option<(PhysAddr, PageFlags<Arch>, PageFlush<Arch>)> { 883 if !virt.check_aligned(Arch::PAGE_SIZE) { 884 kerror!("Try to unmap unaligned page: virt={:?}", virt); 885 return None; 886 } 887 888 let table = self.table(); 889 return unmap_phys_inner(virt, &table, unmap_parents, self.allocator_mut()) 890 .map(|(paddr, flags)| (paddr, flags, PageFlush::<Arch>::new(virt))); 891 } 892 893 /// 在页表中,访问虚拟地址对应的页表项,并调用传入的函数F 894 fn visit<T>( 895 &self, 896 virt: VirtAddr, 897 f: impl FnOnce(&mut PageTable<Arch>, usize) -> T, 898 ) -> Option<T> { 899 let mut table = self.table(); 900 unsafe { 901 loop { 902 let i = table.index_of(virt)?; 903 if table.level() == 0 { 904 return Some(f(&mut table, i)); 905 } else { 906 table = table.next_level_table(i)?; 907 } 908 } 909 } 910 } 911 } 912 913 /// 取消页面映射,返回被取消映射的页表项的:【物理地址】和【flags】 914 /// 915 /// ## 参数 916 /// 917 /// - vaddr 虚拟地址 918 /// - table 页表 919 /// - unmap_parents 是否在父页表内,取消空闲子页表的映射 920 /// - allocator 页面分配器(如果页表从这个分配器分配,那么在取消映射时,也需要归还到这个分配器内) 921 /// 922 /// ## 返回值 923 /// 924 /// 如果取消成功,返回被取消映射的页表项的:【物理地址】和【flags】,否则返回None 925 unsafe fn unmap_phys_inner<Arch: MemoryManagementArch>( 926 vaddr: VirtAddr, 927 table: &PageTable<Arch>, 928 unmap_parents: bool, 929 allocator: &mut impl FrameAllocator, 930 ) -> Option<(PhysAddr, PageFlags<Arch>)> { 931 // 获取页表项的索引 932 let i = table.index_of(vaddr)?; 933 934 // 如果当前是最后一级页表,直接取消页面映射 935 if table.level() == 0 { 936 let entry = table.entry(i)?; 937 table.set_entry(i, PageEntry::from_usize(0)); 938 return Some((entry.address().ok()?, entry.flags())); 939 } 940 941 let subtable = table.next_level_table(i)?; 942 // 递归地取消映射 943 let result = unmap_phys_inner(vaddr, &subtable, unmap_parents, allocator)?; 944 945 // TODO: This is a bad idea for architectures where the kernel mappings are done in the process tables, 946 // as these mappings may become out of sync 947 if unmap_parents { 948 // 如果子页表已经没有映射的页面了,就取消子页表的映射 949 950 // 检查子页表中是否还有映射的页面 951 let x = (0..Arch::PAGE_ENTRY_NUM) 952 .map(|k| subtable.entry(k).expect("invalid page entry")) 953 .any(|e| e.present()); 954 if !x { 955 // 如果没有,就取消子页表的映射 956 table.set_entry(i, PageEntry::from_usize(0)); 957 // 释放子页表 958 allocator.free_one(subtable.phys()); 959 } 960 } 961 962 return Some(result); 963 } 964 965 impl<Arch, F: Debug> Debug for PageMapper<Arch, F> { 966 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 967 f.debug_struct("PageMapper") 968 .field("table_paddr", &self.table_paddr) 969 .field("frame_allocator", &self.frame_allocator) 970 .finish() 971 } 972 } 973 974 /// 页表刷新器的trait 975 pub trait Flusher<Arch: MemoryManagementArch> { 976 /// 取消对指定的page flusher的刷新 977 fn consume(&mut self, flush: PageFlush<Arch>); 978 } 979 980 /// 用于刷新某个虚拟地址的刷新器。这个刷新器一经产生,就必须调用flush()方法, 981 /// 否则会造成对页表的更改被忽略,这是不安全的 982 #[must_use = "The flusher must call the 'flush()', or the changes to page table will be unsafely ignored."] 983 pub struct PageFlush<Arch: MemoryManagementArch> { 984 virt: VirtAddr, 985 phantom: PhantomData<Arch>, 986 } 987 988 impl<Arch: MemoryManagementArch> PageFlush<Arch> { 989 pub fn new(virt: VirtAddr) -> Self { 990 return Self { 991 virt, 992 phantom: PhantomData, 993 }; 994 } 995 996 pub fn flush(self) { 997 unsafe { Arch::invalidate_page(self.virt) }; 998 } 999 1000 /// 忽略掉这个刷新器 1001 pub unsafe fn ignore(self) { 1002 mem::forget(self); 1003 } 1004 } 1005 1006 impl<Arch: MemoryManagementArch> Drop for PageFlush<Arch> { 1007 fn drop(&mut self) { 1008 unsafe { 1009 MMArch::invalidate_page(self.virt); 1010 } 1011 } 1012 } 1013 1014 /// 用于刷新整个页表的刷新器。这个刷新器一经产生,就必须调用flush()方法, 1015 /// 否则会造成对页表的更改被忽略,这是不安全的 1016 #[must_use = "The flusher must call the 'flush()', or the changes to page table will be unsafely ignored."] 1017 pub struct PageFlushAll<Arch: MemoryManagementArch> { 1018 phantom: PhantomData<fn() -> Arch>, 1019 } 1020 1021 #[allow(dead_code)] 1022 impl<Arch: MemoryManagementArch> PageFlushAll<Arch> { 1023 pub fn new() -> Self { 1024 return Self { 1025 phantom: PhantomData, 1026 }; 1027 } 1028 1029 pub fn flush(self) { 1030 unsafe { Arch::invalidate_all() }; 1031 } 1032 1033 /// 忽略掉这个刷新器 1034 pub unsafe fn ignore(self) { 1035 mem::forget(self); 1036 } 1037 } 1038 1039 impl<Arch: MemoryManagementArch> Flusher<Arch> for PageFlushAll<Arch> { 1040 /// 为page flush all 实现consume,消除对单个页面的刷新。(刷新整个页表了就不需要刷新单个页面了) 1041 fn consume(&mut self, flush: PageFlush<Arch>) { 1042 unsafe { flush.ignore() }; 1043 } 1044 } 1045 1046 impl<Arch: MemoryManagementArch, T: Flusher<Arch> + ?Sized> Flusher<Arch> for &mut T { 1047 /// 允许一个flusher consume掉另一个flusher 1048 fn consume(&mut self, flush: PageFlush<Arch>) { 1049 <T as Flusher<Arch>>::consume(self, flush); 1050 } 1051 } 1052 1053 impl<Arch: MemoryManagementArch> Flusher<Arch> for () { 1054 fn consume(&mut self, _flush: PageFlush<Arch>) {} 1055 } 1056 1057 impl<Arch: MemoryManagementArch> Drop for PageFlushAll<Arch> { 1058 fn drop(&mut self) { 1059 unsafe { 1060 Arch::invalidate_all(); 1061 } 1062 } 1063 } 1064 1065 /// 未在当前CPU上激活的页表的刷新器 1066 /// 1067 /// 如果页表没有在当前cpu上激活,那么需要发送ipi到其他核心,尝试在其他核心上刷新页表 1068 /// 1069 /// TODO: 这个方式很暴力,也许把它改成在指定的核心上刷新页表会更好。(可以测试一下开销) 1070 #[derive(Debug)] 1071 pub struct InactiveFlusher; 1072 1073 impl InactiveFlusher { 1074 pub fn new() -> Self { 1075 return Self {}; 1076 } 1077 } 1078 1079 impl Flusher<MMArch> for InactiveFlusher { 1080 fn consume(&mut self, flush: PageFlush<MMArch>) { 1081 unsafe { 1082 flush.ignore(); 1083 } 1084 } 1085 } 1086 1087 impl Drop for InactiveFlusher { 1088 fn drop(&mut self) { 1089 // 发送刷新页表的IPI 1090 send_ipi(IpiKind::FlushTLB, IpiTarget::Other); 1091 } 1092 } 1093 1094 /// # 把一个地址向下对齐到页大小 1095 pub fn round_down_to_page_size(addr: usize) -> usize { 1096 addr & !(MMArch::PAGE_SIZE - 1) 1097 } 1098 1099 /// # 把一个地址向上对齐到页大小 1100 pub fn round_up_to_page_size(addr: usize) -> usize { 1101 round_down_to_page_size(addr + MMArch::PAGE_SIZE - 1) 1102 } 1103