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