xref: /DragonOS/kernel/src/mm/fault.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 use core::{
2     alloc::Layout,
3     cmp::{max, min},
4     intrinsics::unlikely,
5     panic,
6 };
7 
8 use alloc::sync::Arc;
9 
10 use crate::{
11     arch::{mm::PageMapper, MMArch},
12     libs::align::align_down,
13     mm::{
14         page::{page_manager_lock_irqsave, EntryFlags},
15         ucontext::LockedVMA,
16         VirtAddr, VmFaultReason, VmFlags,
17     },
18     process::{ProcessManager, ProcessState},
19 };
20 
21 use crate::mm::MemoryManagementArch;
22 
23 use super::{
24     allocator::page_frame::FrameAllocator,
25     page::{page_reclaimer_lock_irqsave, Page, PageFlags},
26 };
27 
28 bitflags! {
29     pub struct FaultFlags: u64{
30         const FAULT_FLAG_WRITE = 1 << 0;
31         const FAULT_FLAG_MKWRITE = 1 << 1;
32         const FAULT_FLAG_ALLOW_RETRY = 1 << 2;
33         const FAULT_FLAG_RETRY_NOWAIT = 1 << 3;
34         const FAULT_FLAG_KILLABLE = 1 << 4;
35         const FAULT_FLAG_TRIED = 1 << 5;
36         const FAULT_FLAG_USER = 1 << 6;
37         const FAULT_FLAG_REMOTE = 1 << 7;
38         const FAULT_FLAG_INSTRUCTION = 1 << 8;
39         const FAULT_FLAG_INTERRUPTIBLE =1 << 9;
40         const FAULT_FLAG_UNSHARE = 1 << 10;
41         const FAULT_FLAG_ORIG_PTE_VALID = 1 << 11;
42         const FAULT_FLAG_VMA_LOCK = 1 << 12;
43     }
44 }
45 
46 /// # 缺页异常信息结构体
47 /// 包含了页面错误处理的相关信息,例如出错的地址、VMA等
48 #[derive(Debug)]
49 pub struct PageFaultMessage<'a> {
50     /// 产生缺页的VMA结构体
51     vma: Arc<LockedVMA>,
52     /// 缺页地址
53     address: VirtAddr,
54     /// 异常处理标志
55     flags: FaultFlags,
56     /// 页表映射器
57     mapper: &'a mut PageMapper,
58     /// 缺页的文件页在文件中的偏移量
59     file_pgoff: Option<usize>,
60     /// 缺页对应PageCache中的文件页
61     page: Option<Arc<Page>>,
62     /// 写时拷贝需要的页面
63     cow_page: Option<Arc<Page>>,
64 }
65 
66 impl<'a> PageFaultMessage<'a> {
new( vma: Arc<LockedVMA>, address: VirtAddr, flags: FaultFlags, mapper: &'a mut PageMapper, ) -> Self67     pub fn new(
68         vma: Arc<LockedVMA>,
69         address: VirtAddr,
70         flags: FaultFlags,
71         mapper: &'a mut PageMapper,
72     ) -> Self {
73         let guard = vma.lock_irqsave();
74         let file_pgoff = guard.file_page_offset().map(|file_page_offset| {
75             ((address - guard.region().start()) >> MMArch::PAGE_SHIFT) + file_page_offset
76         });
77         Self {
78             vma: vma.clone(),
79             address: VirtAddr::new(crate::libs::align::page_align_down(address.data())),
80             flags,
81             file_pgoff,
82             page: None,
83             mapper,
84             cow_page: None,
85         }
86     }
87 
88     #[inline(always)]
89     #[allow(dead_code)]
vma(&self) -> Arc<LockedVMA>90     pub fn vma(&self) -> Arc<LockedVMA> {
91         self.vma.clone()
92     }
93 
94     #[inline(always)]
95     #[allow(dead_code)]
address(&self) -> VirtAddr96     pub fn address(&self) -> VirtAddr {
97         self.address
98     }
99 
100     #[inline(always)]
101     #[allow(dead_code)]
address_aligned_down(&self) -> VirtAddr102     pub fn address_aligned_down(&self) -> VirtAddr {
103         VirtAddr::new(crate::libs::align::page_align_down(self.address.data()))
104     }
105 
106     #[inline(always)]
107     #[allow(dead_code)]
flags(&self) -> FaultFlags108     pub fn flags(&self) -> FaultFlags {
109         self.flags
110     }
111 }
112 
113 /// 缺页中断处理结构体
114 pub struct PageFaultHandler;
115 
116 impl PageFaultHandler {
117     /// 处理缺页异常
118     /// ## 参数
119     ///
120     /// - `pfm`: 缺页异常信息
121     /// - `mapper`: 页表映射器
122     ///
123     /// ## 返回值
124     /// - VmFaultReason: 页面错误处理信息标志
handle_mm_fault(mut pfm: PageFaultMessage) -> VmFaultReason125     pub unsafe fn handle_mm_fault(mut pfm: PageFaultMessage) -> VmFaultReason {
126         let flags = pfm.flags();
127         let vma = pfm.vma();
128         let current_pcb = ProcessManager::current_pcb();
129         let mut guard = current_pcb.sched_info().inner_lock_write_irqsave();
130         guard.set_state(ProcessState::Runnable);
131 
132         if !MMArch::vma_access_permitted(
133             vma.clone(),
134             flags.contains(FaultFlags::FAULT_FLAG_WRITE),
135             flags.contains(FaultFlags::FAULT_FLAG_INSTRUCTION),
136             flags.contains(FaultFlags::FAULT_FLAG_REMOTE),
137         ) {
138             return VmFaultReason::VM_FAULT_SIGSEGV;
139         }
140 
141         let guard = vma.lock_irqsave();
142         let vm_flags = *guard.vm_flags();
143         drop(guard);
144         if unlikely(vm_flags.contains(VmFlags::VM_HUGETLB)) {
145             //TODO: 添加handle_hugetlb_fault处理大页缺页异常
146         } else {
147             Self::handle_normal_fault(&mut pfm);
148         }
149 
150         VmFaultReason::VM_FAULT_COMPLETED
151     }
152 
153     /// 处理普通页缺页异常
154     /// ## 参数
155     ///
156     /// - `pfm`: 缺页异常信息
157     /// - `mapper`: 页表映射器
158     ///
159     /// ## 返回值
160     /// - VmFaultReason: 页面错误处理信息标志
handle_normal_fault(pfm: &mut PageFaultMessage) -> VmFaultReason161     pub unsafe fn handle_normal_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
162         let address = pfm.address_aligned_down();
163         let vma = pfm.vma.clone();
164         let mapper = &mut pfm.mapper;
165         if mapper.get_entry(address, 3).is_none() {
166             mapper
167                 .allocate_table(address, 2)
168                 .expect("failed to allocate PUD table");
169         }
170         let page_flags = vma.lock_irqsave().flags();
171 
172         for level in 2..=3 {
173             let level = MMArch::PAGE_LEVELS - level;
174             if mapper.get_entry(address, level).is_none() {
175                 if vma.is_hugepage() {
176                     if vma.is_anonymous() {
177                         mapper.map_huge_page(address, page_flags);
178                     }
179                 } else if mapper.allocate_table(address, level - 1).is_none() {
180                     return VmFaultReason::VM_FAULT_OOM;
181                 }
182             }
183         }
184 
185         Self::handle_pte_fault(pfm)
186     }
187 
188     /// 处理页表项异常
189     /// ## 参数
190     ///
191     /// - `pfm`: 缺页异常信息
192     /// - `mapper`: 页表映射器
193     ///
194     /// ## 返回值
195     /// - VmFaultReason: 页面错误处理信息标志
handle_pte_fault(pfm: &mut PageFaultMessage) -> VmFaultReason196     pub unsafe fn handle_pte_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
197         let address = pfm.address_aligned_down();
198         let flags = pfm.flags;
199         let vma = pfm.vma.clone();
200         let mut ret = VmFaultReason::VM_FAULT_COMPLETED;
201         let mapper = &pfm.mapper;
202 
203         // pte存在
204         if let Some(mut entry) = mapper.get_entry(address, 0) {
205             if !entry.present() {
206                 ret = Self::do_swap_page(pfm);
207             }
208 
209             if entry.protnone() && vma.is_accessible() {
210                 ret = Self::do_numa_page(pfm);
211             }
212 
213             if flags.intersects(FaultFlags::FAULT_FLAG_WRITE | FaultFlags::FAULT_FLAG_UNSHARE) {
214                 if !entry.write() {
215                     ret = Self::do_wp_page(pfm);
216                 } else {
217                     entry.set_flags(EntryFlags::from_data(MMArch::ENTRY_FLAG_DIRTY));
218                 }
219             }
220         } else if vma.is_anonymous() {
221             ret = Self::do_anonymous_page(pfm);
222         } else {
223             ret = Self::do_fault(pfm);
224         }
225 
226         vma.lock_irqsave().set_mapped(true);
227 
228         return ret;
229     }
230 
231     /// 处理匿名映射页缺页异常
232     /// ## 参数
233     ///
234     /// - `pfm`: 缺页异常信息
235     /// - `mapper`: 页表映射器
236     ///
237     /// ## 返回值
238     /// - VmFaultReason: 页面错误处理信息标志
do_anonymous_page(pfm: &mut PageFaultMessage) -> VmFaultReason239     pub unsafe fn do_anonymous_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
240         let address = pfm.address_aligned_down();
241         let vma = pfm.vma.clone();
242         let guard = vma.lock_irqsave();
243         let mapper = &mut pfm.mapper;
244 
245         if let Some(flush) = mapper.map(address, guard.flags()) {
246             flush.flush();
247             crate::debug::klog::mm::mm_debug_log(
248                 klog_types::AllocatorLogType::LazyAlloc(klog_types::AllocLogItem::new(
249                     Layout::from_size_align(MMArch::PAGE_SIZE, MMArch::PAGE_SIZE).unwrap(),
250                     Some(address.data()),
251                     Some(mapper.translate(address).unwrap().0.data()),
252                 )),
253                 klog_types::LogSource::Buddy,
254             );
255             let paddr = mapper.translate(address).unwrap().0;
256             let mut page_manager_guard = page_manager_lock_irqsave();
257             let page = page_manager_guard.get_unwrap(&paddr);
258             page.write_irqsave().insert_vma(vma.clone());
259             VmFaultReason::VM_FAULT_COMPLETED
260         } else {
261             VmFaultReason::VM_FAULT_OOM
262         }
263     }
264 
265     /// 处理文件映射页的缺页异常
266     /// ## 参数
267     ///
268     /// - `pfm`: 缺页异常信息
269     /// - `mapper`: 页表映射器
270     ///
271     /// ## 返回值
272     /// - VmFaultReason: 页面错误处理信息标志
do_fault(pfm: &mut PageFaultMessage) -> VmFaultReason273     pub unsafe fn do_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
274         if !pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE) {
275             Self::do_read_fault(pfm)
276         } else if !pfm
277             .vma()
278             .lock_irqsave()
279             .vm_flags()
280             .contains(VmFlags::VM_SHARED)
281         {
282             Self::do_cow_fault(pfm)
283         } else {
284             Self::do_shared_fault(pfm)
285         }
286     }
287 
288     /// 处理私有文件映射的写时复制
289     /// ## 参数
290     ///
291     /// - `pfm`: 缺页异常信息
292     /// - `mapper`: 页表映射器
293     ///
294     /// ## 返回值
295     /// - VmFaultReason: 页面错误处理信息标志
do_cow_fault(pfm: &mut PageFaultMessage) -> VmFaultReason296     pub unsafe fn do_cow_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
297         let mut ret = Self::filemap_fault(pfm);
298 
299         if unlikely(ret.intersects(
300             VmFaultReason::VM_FAULT_ERROR
301                 | VmFaultReason::VM_FAULT_NOPAGE
302                 | VmFaultReason::VM_FAULT_RETRY
303                 | VmFaultReason::VM_FAULT_DONE_COW,
304         )) {
305             return ret;
306         }
307 
308         let cache_page = pfm.page.clone().unwrap();
309         let mapper = &mut pfm.mapper;
310 
311         let cow_page_phys = mapper.allocator_mut().allocate_one();
312         if cow_page_phys.is_none() {
313             return VmFaultReason::VM_FAULT_OOM;
314         }
315         let cow_page_phys = cow_page_phys.unwrap();
316 
317         let cow_page = Arc::new(Page::new(false, cow_page_phys));
318         pfm.cow_page = Some(cow_page.clone());
319 
320         //复制PageCache内容到新的页内
321         let new_frame = MMArch::phys_2_virt(cow_page_phys).unwrap();
322         (new_frame.data() as *mut u8).copy_from_nonoverlapping(
323             MMArch::phys_2_virt(cache_page.read_irqsave().phys_address())
324                 .unwrap()
325                 .data() as *mut u8,
326             MMArch::PAGE_SIZE,
327         );
328 
329         let mut page_manager_guard = page_manager_lock_irqsave();
330 
331         // 新页加入页管理器中
332         page_manager_guard.insert(cow_page_phys, &cow_page);
333         cow_page.write_irqsave().set_page_cache_index(
334             cache_page.read_irqsave().page_cache(),
335             cache_page.read_irqsave().index(),
336         );
337 
338         ret = ret.union(Self::finish_fault(pfm));
339 
340         ret
341     }
342 
343     /// 处理文件映射页的缺页异常
344     /// ## 参数
345     ///
346     /// - `pfm`: 缺页异常信息
347     /// - `mapper`: 页表映射器
348     ///
349     /// ## 返回值
350     /// - VmFaultReason: 页面错误处理信息标志
do_read_fault(pfm: &mut PageFaultMessage) -> VmFaultReason351     pub unsafe fn do_read_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
352         let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs();
353 
354         let mut ret = Self::do_fault_around(pfm);
355         if !ret.is_empty() {
356             return ret;
357         }
358 
359         ret = fs.fault(pfm);
360 
361         ret = ret.union(Self::finish_fault(pfm));
362 
363         ret
364     }
365 
366     /// 处理对共享文件映射区写入引起的缺页
367     /// ## 参数
368     ///
369     /// - `pfm`: 缺页异常信息
370     /// - `mapper`: 页表映射器
371     ///
372     /// ## 返回值
373     /// - VmFaultReason: 页面错误处理信息标志
do_shared_fault(pfm: &mut PageFaultMessage) -> VmFaultReason374     pub unsafe fn do_shared_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
375         let mut ret = Self::filemap_fault(pfm);
376 
377         let cache_page = pfm.page.clone().expect("no cache_page in PageFaultMessage");
378 
379         // 将pagecache页设为脏页,以便回收时能够回写
380         cache_page.write_irqsave().add_flags(PageFlags::PG_DIRTY);
381         ret = ret.union(Self::finish_fault(pfm));
382 
383         ret
384     }
385 
386     /// 处理被置换页面的缺页异常
387     /// ## 参数
388     ///
389     /// - `pfm`: 缺页异常信息
390     /// - `mapper`: 页表映射器
391     ///
392     /// ## 返回值
393     /// - VmFaultReason: 页面错误处理信息标志
394     #[allow(unused_variables)]
do_swap_page(pfm: &mut PageFaultMessage) -> VmFaultReason395     pub unsafe fn do_swap_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
396         panic!(
397             "do_swap_page has not yet been implemented,
398         fault message: {:?},
399         pid: {}\n",
400             pfm,
401             crate::process::ProcessManager::current_pid().data()
402         );
403         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_swap_page
404     }
405 
406     /// 处理NUMA的缺页异常
407     /// ## 参数
408     ///
409     /// - `pfm`: 缺页异常信息
410     /// - `mapper`: 页表映射器
411     ///
412     /// ## 返回值
413     /// - VmFaultReason: 页面错误处理信息标志
414     #[allow(unused_variables)]
do_numa_page(pfm: &mut PageFaultMessage) -> VmFaultReason415     pub unsafe fn do_numa_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
416         panic!(
417             "do_numa_page has not yet been implemented,
418         fault message: {:?},
419         pid: {}\n",
420             pfm,
421             crate::process::ProcessManager::current_pid().data()
422         );
423         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_numa_page
424     }
425 
426     /// 处理写保护页面的写保护异常
427     /// ## 参数
428     ///
429     /// - `pfm`: 缺页异常信息
430     /// - `mapper`: 页表映射器
431     ///
432     /// ## 返回值
433     /// - VmFaultReason: 页面错误处理信息标志
do_wp_page(pfm: &mut PageFaultMessage) -> VmFaultReason434     pub unsafe fn do_wp_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
435         let address = pfm.address_aligned_down();
436         let vma = pfm.vma.clone();
437         let mapper = &mut pfm.mapper;
438 
439         let old_paddr = mapper.translate(address).unwrap().0;
440         let mut page_manager = page_manager_lock_irqsave();
441         let old_page = page_manager.get_unwrap(&old_paddr);
442         let map_count = old_page.read_irqsave().map_count();
443         drop(page_manager);
444 
445         let mut entry = mapper.get_entry(address, 0).unwrap();
446         let new_flags = entry.flags().set_write(true).set_dirty(true);
447 
448         if vma.lock().vm_flags().contains(VmFlags::VM_SHARED) {
449             // 共享映射,直接修改页表项保护位,标记为脏页
450             let table = mapper.get_table(address, 0).unwrap();
451             let i = table.index_of(address).unwrap();
452             entry.set_flags(new_flags);
453             table.set_entry(i, entry);
454 
455             old_page.write_irqsave().add_flags(PageFlags::PG_DIRTY);
456 
457             VmFaultReason::VM_FAULT_COMPLETED
458         } else if vma.is_anonymous() {
459             // 私有匿名映射,根据引用计数判断是否拷贝页面
460             if map_count == 1 {
461                 let table = mapper.get_table(address, 0).unwrap();
462                 let i = table.index_of(address).unwrap();
463                 entry.set_flags(new_flags);
464                 table.set_entry(i, entry);
465                 VmFaultReason::VM_FAULT_COMPLETED
466             } else if let Some(flush) = mapper.map(address, new_flags) {
467                 let mut page_manager_guard = page_manager_lock_irqsave();
468                 let old_page = page_manager_guard.get_unwrap(&old_paddr);
469                 old_page.write_irqsave().remove_vma(&vma);
470                 // drop(page_manager_guard);
471 
472                 flush.flush();
473                 let paddr = mapper.translate(address).unwrap().0;
474                 // let mut page_manager_guard = page_manager_lock_irqsave();
475                 let page = page_manager_guard.get_unwrap(&paddr);
476                 page.write_irqsave().insert_vma(vma.clone());
477 
478                 (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
479                     MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8,
480                     MMArch::PAGE_SIZE,
481                 );
482 
483                 VmFaultReason::VM_FAULT_COMPLETED
484             } else {
485                 VmFaultReason::VM_FAULT_OOM
486             }
487         } else {
488             // 私有文件映射,必须拷贝页面
489             if let Some(flush) = mapper.map(address, new_flags) {
490                 let mut page_manager_guard = page_manager_lock_irqsave();
491                 let old_page = page_manager_guard.get_unwrap(&old_paddr);
492                 old_page.write_irqsave().remove_vma(&vma);
493                 // drop(page_manager_guard);
494 
495                 flush.flush();
496                 let paddr = mapper.translate(address).unwrap().0;
497                 // let mut page_manager_guard = page_manager_lock_irqsave();
498                 let page = page_manager_guard.get_unwrap(&paddr);
499                 page.write_irqsave().insert_vma(vma.clone());
500 
501                 (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
502                     MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8,
503                     MMArch::PAGE_SIZE,
504                 );
505 
506                 VmFaultReason::VM_FAULT_COMPLETED
507             } else {
508                 VmFaultReason::VM_FAULT_OOM
509             }
510         }
511     }
512 
513     /// 缺页附近页预读
514     /// ## 参数
515     ///
516     /// - `pfm`: 缺页异常信息
517     /// - `mapper`: 页表映射器
518     ///
519     /// ## 返回值
520     /// - VmFaultReason: 页面错误处理信息标志
do_fault_around(pfm: &mut PageFaultMessage) -> VmFaultReason521     pub unsafe fn do_fault_around(pfm: &mut PageFaultMessage) -> VmFaultReason {
522         let vma = pfm.vma();
523         let address = pfm.address();
524         let mapper = &mut pfm.mapper;
525 
526         if mapper.get_table(address, 0).is_none() {
527             mapper
528                 .allocate_table(address, 0)
529                 .expect("failed to allocate pte table");
530         }
531         let vma_guard = vma.lock_irqsave();
532         let vma_region = *vma_guard.region();
533         drop(vma_guard);
534 
535         // 缺页在VMA中的偏移量
536         let vm_pgoff = (address - vma_region.start()) >> MMArch::PAGE_SHIFT;
537 
538         // 缺页在PTE中的偏移量
539         let pte_pgoff = (address.data() >> MMArch::PAGE_SHIFT) & (1 << MMArch::PAGE_ENTRY_SHIFT);
540 
541         // 缺页在文件中的偏移量
542         let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
543 
544         let vma_pages_count = (vma_region.end() - vma_region.start()) >> MMArch::PAGE_SHIFT;
545 
546         let fault_around_page_number = 16;
547 
548         // 开始位置不能超出当前pte和vma头部
549         let from_pte = max(
550             align_down(pte_pgoff, fault_around_page_number),
551             pte_pgoff - min(vm_pgoff, pte_pgoff),
552         );
553 
554         // pte结束位置不能超过:
555         // 1.最大预读上限(默认16)
556         // 2.最大pte(512)
557         // 3.vma结束位置(pte_pgoff + (vma_pages_count - vm_pgoff)计算出vma结束页号对当前pte开头的偏移)
558         let to_pte = min(
559             from_pte + fault_around_page_number,
560             min(
561                 1 << MMArch::PAGE_SHIFT,
562                 pte_pgoff + (vma_pages_count - vm_pgoff),
563             ),
564         );
565 
566         // 预先分配pte页表(如果不存在)
567         if mapper.get_table(address, 0).is_none() && mapper.allocate_table(address, 0).is_none() {
568             return VmFaultReason::VM_FAULT_OOM;
569         }
570 
571         let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs();
572         // from_pte - pte_pgoff得出预读起始pte相对缺失页的偏移,加上pfm.file_pgoff(缺失页在文件中的偏移)得出起始页在文件中的偏移,结束pte同理
573         fs.map_pages(
574             pfm,
575             file_pgoff + (from_pte - pte_pgoff),
576             file_pgoff + (to_pte - pte_pgoff),
577         );
578 
579         VmFaultReason::empty()
580     }
581 
582     /// 通用的VMA文件映射页面映射函数,将PageCache中的页面映射到进程空间
583     /// ## 参数
584     ///
585     /// - `pfm`: 缺页异常信息
586     /// - `mapper`: 页表映射器
587     ///
588     /// ## 返回值
589     /// - VmFaultReason: 页面错误处理信息标志
filemap_map_pages( pfm: &mut PageFaultMessage, start_pgoff: usize, end_pgoff: usize, ) -> VmFaultReason590     pub unsafe fn filemap_map_pages(
591         pfm: &mut PageFaultMessage,
592 
593         start_pgoff: usize,
594         end_pgoff: usize,
595     ) -> VmFaultReason {
596         let vma = pfm.vma();
597         let vma_guard = vma.lock_irqsave();
598         let file = vma_guard.vm_file().expect("no vm_file in vma");
599         let page_cache = file.inode().page_cache().unwrap();
600         let mapper = &mut pfm.mapper;
601 
602         // 起始页地址
603         let addr = vma_guard.region().start
604             + ((start_pgoff
605                 - vma_guard
606                     .file_page_offset()
607                     .expect("file_page_offset is none"))
608                 << MMArch::PAGE_SHIFT);
609 
610         for pgoff in start_pgoff..=end_pgoff {
611             if let Some(page) = page_cache.get_page(pgoff) {
612                 let page_guard = page.read_irqsave();
613                 if page_guard.flags().contains(PageFlags::PG_UPTODATE) {
614                     let phys = page_guard.phys_address();
615 
616                     let address =
617                         VirtAddr::new(addr.data() + ((pgoff - start_pgoff) << MMArch::PAGE_SHIFT));
618                     mapper
619                         .map_phys(address, phys, vma_guard.flags())
620                         .unwrap()
621                         .flush();
622                 }
623             }
624         }
625         VmFaultReason::empty()
626     }
627 
628     /// 通用的VMA文件映射错误处理函数
629     /// ## 参数
630     ///
631     /// - `pfm`: 缺页异常信息
632     /// - `mapper`: 页表映射器
633     ///
634     /// ## 返回值
635     /// - VmFaultReason: 页面错误处理信息标志
filemap_fault(pfm: &mut PageFaultMessage) -> VmFaultReason636     pub unsafe fn filemap_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
637         let vma = pfm.vma();
638         let vma_guard = vma.lock_irqsave();
639         let file = vma_guard.vm_file().expect("no vm_file in vma");
640         let page_cache = file.inode().page_cache().unwrap();
641         let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
642         let mapper = &mut pfm.mapper;
643         let mut ret = VmFaultReason::empty();
644 
645         if let Some(page) = page_cache.get_page(file_pgoff) {
646             // TODO 异步从磁盘中预读页面进PageCache
647 
648             // 直接将PageCache中的页面作为要映射的页面
649             pfm.page = Some(page.clone());
650         } else {
651             // TODO 同步预读
652             //涉及磁盘IO,返回标志为VM_FAULT_MAJOR
653             ret = VmFaultReason::VM_FAULT_MAJOR;
654             // let mut buf: Vec<u8> = vec![0; MMArch::PAGE_SIZE];
655 
656             let allocator = mapper.allocator_mut();
657 
658             // 分配一个物理页面作为加入PageCache的新页
659             let new_cache_page = allocator.allocate_one().unwrap();
660             // (MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8)
661             //     .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
662             file.pread(
663                 file_pgoff * MMArch::PAGE_SIZE,
664                 MMArch::PAGE_SIZE,
665                 core::slice::from_raw_parts_mut(
666                     MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8,
667                     MMArch::PAGE_SIZE,
668                 ),
669             )
670             .expect("failed to read file to create pagecache page");
671 
672             let page = Arc::new(Page::new(true, new_cache_page));
673             pfm.page = Some(page.clone());
674 
675             page.write_irqsave().add_flags(PageFlags::PG_LRU);
676             page_manager_lock_irqsave().insert(new_cache_page, &page);
677             page_reclaimer_lock_irqsave().insert_page(new_cache_page, &page);
678             page_cache.add_page(file_pgoff, &page);
679 
680             page.write_irqsave()
681                 .set_page_cache_index(Some(page_cache), Some(file_pgoff));
682         }
683         ret
684     }
685 
686     /// 将文件页映射到缺页地址
687     /// ## 参数
688     ///
689     /// - `pfm`: 缺页异常信息
690     /// - `mapper`: 页表映射器
691     ///
692     /// ## 返回值
693     /// - VmFaultReason: 页面错误处理信息标志
finish_fault(pfm: &mut PageFaultMessage) -> VmFaultReason694     pub unsafe fn finish_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
695         let vma = pfm.vma();
696         let vma_guard = vma.lock_irqsave();
697         let flags = pfm.flags();
698         let cache_page = pfm.page.clone();
699         let cow_page = pfm.cow_page.clone();
700         let address = pfm.address();
701         let mapper = &mut pfm.mapper;
702 
703         let page_to_map = if flags.contains(FaultFlags::FAULT_FLAG_WRITE)
704             && !vma_guard.vm_flags().contains(VmFlags::VM_SHARED)
705         {
706             // 私有文件映射的写时复制
707             cow_page.expect("no cow_page in PageFaultMessage")
708         } else {
709             // 直接映射到PageCache
710             cache_page.expect("no cache_page in PageFaultMessage")
711         };
712 
713         let page_phys = page_to_map.read_irqsave().phys_address();
714 
715         mapper.map_phys(address, page_phys, vma_guard.flags());
716         page_to_map.write_irqsave().insert_vma(pfm.vma());
717         VmFaultReason::VM_FAULT_COMPLETED
718     }
719 }
720