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