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