xref: /DragonOS/kernel/src/mm/fault.rs (revision 1ea2daad8121b77ed704e6d7c3a09f478147441d)
1 use core::{alloc::Layout, intrinsics::unlikely, panic};
2 
3 use alloc::sync::Arc;
4 
5 use crate::{
6     arch::{mm::PageMapper, MMArch},
7     mm::{
8         page::{page_manager_lock_irqsave, PageFlags},
9         ucontext::LockedVMA,
10         VirtAddr, VmFaultReason, VmFlags,
11     },
12     process::{ProcessManager, ProcessState},
13 };
14 
15 use crate::mm::MemoryManagementArch;
16 
17 bitflags! {
18     pub struct FaultFlags: u64{
19     const FAULT_FLAG_WRITE = 1 << 0;
20     const FAULT_FLAG_MKWRITE = 1 << 1;
21     const FAULT_FLAG_ALLOW_RETRY = 1 << 2;
22     const FAULT_FLAG_RETRY_NOWAIT = 1 << 3;
23     const FAULT_FLAG_KILLABLE = 1 << 4;
24     const FAULT_FLAG_TRIED = 1 << 5;
25     const FAULT_FLAG_USER = 1 << 6;
26     const FAULT_FLAG_REMOTE = 1 << 7;
27     const FAULT_FLAG_INSTRUCTION = 1 << 8;
28     const FAULT_FLAG_INTERRUPTIBLE =1 << 9;
29     const FAULT_FLAG_UNSHARE = 1 << 10;
30     const FAULT_FLAG_ORIG_PTE_VALID = 1 << 11;
31     const FAULT_FLAG_VMA_LOCK = 1 << 12;
32     }
33 }
34 
35 /// # 缺页异常信息结构体
36 /// 包含了页面错误处理的相关信息,例如出错的地址、VMA等
37 #[derive(Debug)]
38 pub struct PageFaultMessage {
39     vma: Arc<LockedVMA>,
40     address: VirtAddr,
41     flags: FaultFlags,
42 }
43 
44 impl PageFaultMessage {
45     pub fn new(vma: Arc<LockedVMA>, address: VirtAddr, flags: FaultFlags) -> Self {
46         Self {
47             vma: vma.clone(),
48             address,
49             flags,
50         }
51     }
52 
53     #[inline(always)]
54     #[allow(dead_code)]
55     pub fn vma(&self) -> Arc<LockedVMA> {
56         self.vma.clone()
57     }
58 
59     #[inline(always)]
60     #[allow(dead_code)]
61     pub fn address(&self) -> VirtAddr {
62         self.address
63     }
64 
65     #[inline(always)]
66     #[allow(dead_code)]
67     pub fn address_aligned_down(&self) -> VirtAddr {
68         VirtAddr::new(crate::libs::align::page_align_down(self.address.data()))
69     }
70 
71     #[inline(always)]
72     #[allow(dead_code)]
73     pub fn flags(&self) -> FaultFlags {
74         self.flags
75     }
76 }
77 
78 impl Clone for PageFaultMessage {
79     fn clone(&self) -> Self {
80         Self {
81             vma: self.vma.clone(),
82             address: self.address,
83             flags: self.flags,
84         }
85     }
86 }
87 
88 /// 缺页中断处理结构体
89 pub struct PageFaultHandler;
90 
91 impl PageFaultHandler {
92     /// 处理缺页异常
93     /// ## 参数
94     ///
95     /// - `pfm`: 缺页异常信息
96     /// - `mapper`: 页表映射器
97     ///
98     /// ## 返回值
99     /// - VmFaultReason: 页面错误处理信息标志
100     pub unsafe fn handle_mm_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
101         let flags = pfm.flags();
102         let vma = pfm.vma();
103         let current_pcb = ProcessManager::current_pcb();
104         let mut guard = current_pcb.sched_info().inner_lock_write_irqsave();
105         guard.set_state(ProcessState::Runnable);
106 
107         if !MMArch::vma_access_permitted(
108             vma.clone(),
109             flags.contains(FaultFlags::FAULT_FLAG_WRITE),
110             flags.contains(FaultFlags::FAULT_FLAG_INSTRUCTION),
111             flags.contains(FaultFlags::FAULT_FLAG_REMOTE),
112         ) {
113             return VmFaultReason::VM_FAULT_SIGSEGV;
114         }
115 
116         let guard = vma.lock();
117         let vm_flags = *guard.vm_flags();
118         drop(guard);
119         if unlikely(vm_flags.contains(VmFlags::VM_HUGETLB)) {
120             //TODO: 添加handle_hugetlb_fault处理大页缺页异常
121         } else {
122             Self::handle_normal_fault(pfm, mapper);
123         }
124 
125         VmFaultReason::VM_FAULT_COMPLETED
126     }
127 
128     /// 处理普通页缺页异常
129     /// ## 参数
130     ///
131     /// - `pfm`: 缺页异常信息
132     /// - `mapper`: 页表映射器
133     ///
134     /// ## 返回值
135     /// - VmFaultReason: 页面错误处理信息标志
136     pub unsafe fn handle_normal_fault(
137         pfm: PageFaultMessage,
138         mapper: &mut PageMapper,
139     ) -> VmFaultReason {
140         let address = pfm.address_aligned_down();
141         let vma = pfm.vma.clone();
142         if mapper.get_entry(address, 3).is_none() {
143             mapper
144                 .allocate_table(address, 2)
145                 .expect("failed to allocate PUD table");
146         }
147         let page_flags = vma.lock().flags();
148 
149         for level in 2..=3 {
150             let level = MMArch::PAGE_LEVELS - level;
151             if mapper.get_entry(address, level).is_none() {
152                 if vma.is_hugepage() {
153                     if vma.is_anonymous() {
154                         mapper.map_huge_page(address, page_flags);
155                     }
156                 } else if mapper.allocate_table(address, level - 1).is_none() {
157                     return VmFaultReason::VM_FAULT_OOM;
158                 }
159             }
160         }
161 
162         Self::handle_pte_fault(pfm, mapper)
163     }
164 
165     /// 处理页表项异常
166     /// ## 参数
167     ///
168     /// - `pfm`: 缺页异常信息
169     /// - `mapper`: 页表映射器
170     ///
171     /// ## 返回值
172     /// - VmFaultReason: 页面错误处理信息标志
173     pub unsafe fn handle_pte_fault(
174         pfm: PageFaultMessage,
175         mapper: &mut PageMapper,
176     ) -> VmFaultReason {
177         let address = pfm.address_aligned_down();
178         let flags = pfm.flags;
179         let vma = pfm.vma.clone();
180         let mut ret = VmFaultReason::VM_FAULT_COMPLETED;
181         if let Some(mut entry) = mapper.get_entry(address, 0) {
182             if !entry.present() {
183                 ret = Self::do_swap_page(pfm.clone(), mapper);
184             }
185             if entry.protnone() && vma.is_accessible() {
186                 ret = Self::do_numa_page(pfm.clone(), mapper);
187             }
188             if flags.intersects(FaultFlags::FAULT_FLAG_WRITE | FaultFlags::FAULT_FLAG_UNSHARE) {
189                 if !entry.write() {
190                     ret = Self::do_wp_page(pfm.clone(), mapper);
191                 } else {
192                     entry.set_flags(PageFlags::from_data(MMArch::ENTRY_FLAG_DIRTY));
193                 }
194             }
195         } else if vma.is_anonymous() {
196             ret = Self::do_anonymous_page(pfm.clone(), mapper);
197         } else {
198             ret = Self::do_fault(pfm.clone(), mapper);
199         }
200 
201         vma.lock().set_mapped(true);
202 
203         return ret;
204     }
205 
206     /// 处理匿名映射页缺页异常
207     /// ## 参数
208     ///
209     /// - `pfm`: 缺页异常信息
210     /// - `mapper`: 页表映射器
211     ///
212     /// ## 返回值
213     /// - VmFaultReason: 页面错误处理信息标志
214     pub unsafe fn do_anonymous_page(
215         pfm: PageFaultMessage,
216         mapper: &mut PageMapper,
217     ) -> VmFaultReason {
218         let address = pfm.address_aligned_down();
219         let vma = pfm.vma.clone();
220         let guard = vma.lock();
221         if let Some(flush) = mapper.map(address, guard.flags()) {
222             flush.flush();
223             crate::debug::klog::mm::mm_debug_log(
224                 klog_types::AllocatorLogType::LazyAlloc(klog_types::AllocLogItem::new(
225                     Layout::from_size_align(MMArch::PAGE_SIZE, MMArch::PAGE_SIZE).unwrap(),
226                     Some(address.data()),
227                     Some(mapper.translate(address).unwrap().0.data()),
228                 )),
229                 klog_types::LogSource::Buddy,
230             );
231             let paddr = mapper.translate(address).unwrap().0;
232             let mut anon_vma_guard = page_manager_lock_irqsave();
233             let page = anon_vma_guard.get_mut(&paddr);
234             page.insert_vma(vma.clone());
235             VmFaultReason::VM_FAULT_COMPLETED
236         } else {
237             VmFaultReason::VM_FAULT_OOM
238         }
239     }
240 
241     /// 处理文件映射页的缺页异常
242     /// ## 参数
243     ///
244     /// - `pfm`: 缺页异常信息
245     /// - `mapper`: 页表映射器
246     ///
247     /// ## 返回值
248     /// - VmFaultReason: 页面错误处理信息标志
249     #[allow(unused_variables)]
250     pub unsafe fn do_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
251         panic!(
252             "do_fault has not yet been implemented,
253         fault message: {:?},
254         pid: {}\n",
255             pfm,
256             crate::process::ProcessManager::current_pid().data()
257         );
258         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_fault
259     }
260 
261     /// 处理私有文件映射的写时复制
262     /// ## 参数
263     ///
264     /// - `pfm`: 缺页异常信息
265     /// - `mapper`: 页表映射器
266     ///
267     /// ## 返回值
268     /// - VmFaultReason: 页面错误处理信息标志
269     #[allow(dead_code, unused_variables)]
270     pub unsafe fn do_cow_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
271         panic!(
272             "do_cow_fault has not yet been implemented,
273         fault message: {:?},
274         pid: {}\n",
275             pfm,
276             crate::process::ProcessManager::current_pid().data()
277         );
278         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_cow_fault
279     }
280 
281     /// 处理文件映射页的缺页异常
282     /// ## 参数
283     ///
284     /// - `pfm`: 缺页异常信息
285     /// - `mapper`: 页表映射器
286     ///
287     /// ## 返回值
288     /// - VmFaultReason: 页面错误处理信息标志
289     #[allow(dead_code, unused_variables)]
290     pub unsafe fn do_read_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
291         panic!(
292             "do_read_fault has not yet been implemented,
293         fault message: {:?},
294         pid: {}\n",
295             pfm,
296             crate::process::ProcessManager::current_pid().data()
297         );
298         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault
299     }
300 
301     /// 处理对共享文件映射区写入引起的缺页
302     /// ## 参数
303     ///
304     /// - `pfm`: 缺页异常信息
305     /// - `mapper`: 页表映射器
306     ///
307     /// ## 返回值
308     /// - VmFaultReason: 页面错误处理信息标志
309     #[allow(dead_code, unused_variables)]
310     pub unsafe fn do_shared_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
311         panic!(
312             "do_shared_fault has not yet been implemented,
313         fault message: {:?},
314         pid: {}\n",
315             pfm,
316             crate::process::ProcessManager::current_pid().data()
317         );
318         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_shared_fault
319     }
320 
321     /// 处理被置换页面的缺页异常
322     /// ## 参数
323     ///
324     /// - `pfm`: 缺页异常信息
325     /// - `mapper`: 页表映射器
326     ///
327     /// ## 返回值
328     /// - VmFaultReason: 页面错误处理信息标志
329     #[allow(unused_variables)]
330     pub unsafe fn do_swap_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
331         panic!(
332             "do_swap_page has not yet been implemented,
333         fault message: {:?},
334         pid: {}\n",
335             pfm,
336             crate::process::ProcessManager::current_pid().data()
337         );
338         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_swap_page
339     }
340 
341     /// 处理NUMA的缺页异常
342     /// ## 参数
343     ///
344     /// - `pfm`: 缺页异常信息
345     /// - `mapper`: 页表映射器
346     ///
347     /// ## 返回值
348     /// - VmFaultReason: 页面错误处理信息标志
349     #[allow(unused_variables)]
350     pub unsafe fn do_numa_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
351         panic!(
352             "do_numa_page has not yet been implemented,
353         fault message: {:?},
354         pid: {}\n",
355             pfm,
356             crate::process::ProcessManager::current_pid().data()
357         );
358         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_numa_page
359     }
360 
361     /// 处理写保护页面的写保护异常
362     /// ## 参数
363     ///
364     /// - `pfm`: 缺页异常信息
365     /// - `mapper`: 页表映射器
366     ///
367     /// ## 返回值
368     /// - VmFaultReason: 页面错误处理信息标志
369     pub unsafe fn do_wp_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
370         let address = pfm.address_aligned_down();
371         let vma = pfm.vma.clone();
372         let old_paddr = mapper.translate(address).unwrap().0;
373         let mut page_manager = page_manager_lock_irqsave();
374         let map_count = page_manager.get_mut(&old_paddr).map_count();
375         drop(page_manager);
376 
377         let mut entry = mapper.get_entry(address, 0).unwrap();
378         let new_flags = entry.flags().set_write(true);
379 
380         if map_count == 1 {
381             let table = mapper.get_table(address, 0).unwrap();
382             let i = table.index_of(address).unwrap();
383             entry.set_flags(new_flags);
384             table.set_entry(i, entry);
385             VmFaultReason::VM_FAULT_COMPLETED
386         } else if let Some(flush) = mapper.map(address, new_flags) {
387             let mut page_manager = page_manager_lock_irqsave();
388             let old_page = page_manager.get_mut(&old_paddr);
389             old_page.remove_vma(&vma);
390             drop(page_manager);
391 
392             flush.flush();
393             let paddr = mapper.translate(address).unwrap().0;
394             let mut anon_vma_guard = page_manager_lock_irqsave();
395             let page = anon_vma_guard.get_mut(&paddr);
396             page.insert_vma(vma.clone());
397 
398             (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
399                 MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8,
400                 MMArch::PAGE_SIZE,
401             );
402 
403             VmFaultReason::VM_FAULT_COMPLETED
404         } else {
405             VmFaultReason::VM_FAULT_OOM
406         }
407     }
408 }
409