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