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