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