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