xref: /DragonOS/kernel/src/arch/x86_64/mm/fault.rs (revision 2eab6dd743e94a86a685f1f3c01e599adf86610a)
1a17651b1SMemoryShore use core::{
2a17651b1SMemoryShore     intrinsics::{likely, unlikely},
3a17651b1SMemoryShore     panic,
4a17651b1SMemoryShore };
5a17651b1SMemoryShore 
6a17651b1SMemoryShore use alloc::sync::Arc;
7*2eab6dd7S曾俊 use log::error;
8a17651b1SMemoryShore use x86::{bits64::rflags::RFlags, controlregs::Cr4};
9a17651b1SMemoryShore 
10a17651b1SMemoryShore use crate::{
11a17651b1SMemoryShore     arch::{
12a17651b1SMemoryShore         interrupt::{trap::X86PfErrorCode, TrapFrame},
13a17651b1SMemoryShore         mm::{MemoryManagementArch, X86_64MMArch},
14a17651b1SMemoryShore         CurrentIrqArch, MMArch,
15a17651b1SMemoryShore     },
16a17651b1SMemoryShore     exception::InterruptArch,
17a17651b1SMemoryShore     mm::{
18a17651b1SMemoryShore         fault::{FaultFlags, PageFaultHandler, PageFaultMessage},
19a17651b1SMemoryShore         ucontext::{AddressSpace, LockedVMA},
20a17651b1SMemoryShore         VirtAddr, VmFaultReason, VmFlags,
21a17651b1SMemoryShore     },
22a17651b1SMemoryShore };
23a17651b1SMemoryShore 
24a17651b1SMemoryShore use super::LockedFrameAllocator;
25a17651b1SMemoryShore 
26a17651b1SMemoryShore pub type PageMapper =
27a17651b1SMemoryShore     crate::mm::page::PageMapper<crate::arch::x86_64::mm::X86_64MMArch, LockedFrameAllocator>;
28a17651b1SMemoryShore 
29a17651b1SMemoryShore impl X86_64MMArch {
30a17651b1SMemoryShore     pub fn vma_access_error(vma: Arc<LockedVMA>, error_code: X86PfErrorCode) -> bool {
31a17651b1SMemoryShore         let vm_flags = *vma.lock().vm_flags();
32a17651b1SMemoryShore         let foreign = false;
33a17651b1SMemoryShore         if error_code.contains(X86PfErrorCode::X86_PF_PK) {
34a17651b1SMemoryShore             return true;
35a17651b1SMemoryShore         }
36a17651b1SMemoryShore 
37a17651b1SMemoryShore         if unlikely(error_code.contains(X86PfErrorCode::X86_PF_SGX)) {
38a17651b1SMemoryShore             return true;
39a17651b1SMemoryShore         }
40a17651b1SMemoryShore 
41a17651b1SMemoryShore         if !Self::vma_access_permitted(
42a17651b1SMemoryShore             vma.clone(),
43a17651b1SMemoryShore             error_code.contains(X86PfErrorCode::X86_PF_WRITE),
44a17651b1SMemoryShore             error_code.contains(X86PfErrorCode::X86_PF_INSTR),
45a17651b1SMemoryShore             foreign,
46a17651b1SMemoryShore         ) {
47a17651b1SMemoryShore             return true;
48a17651b1SMemoryShore         }
49a17651b1SMemoryShore 
50a17651b1SMemoryShore         if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
51a17651b1SMemoryShore             if unlikely(!vm_flags.contains(VmFlags::VM_WRITE)) {
52a17651b1SMemoryShore                 return true;
53a17651b1SMemoryShore             }
54a17651b1SMemoryShore             return false;
55a17651b1SMemoryShore         }
56a17651b1SMemoryShore 
57a17651b1SMemoryShore         if unlikely(error_code.contains(X86PfErrorCode::X86_PF_PROT)) {
58a17651b1SMemoryShore             return true;
59a17651b1SMemoryShore         }
60a17651b1SMemoryShore 
61a17651b1SMemoryShore         if unlikely(!vma.is_accessible()) {
62a17651b1SMemoryShore             return true;
63a17651b1SMemoryShore         }
64a17651b1SMemoryShore         false
65a17651b1SMemoryShore     }
66a17651b1SMemoryShore 
67a17651b1SMemoryShore     pub fn show_fault_oops(
68a17651b1SMemoryShore         regs: &'static TrapFrame,
69a17651b1SMemoryShore         error_code: X86PfErrorCode,
70a17651b1SMemoryShore         address: VirtAddr,
71a17651b1SMemoryShore     ) {
72a17651b1SMemoryShore         let mapper =
73a17651b1SMemoryShore             unsafe { PageMapper::current(crate::mm::PageTableKind::User, LockedFrameAllocator) };
74a17651b1SMemoryShore         if let Some(entry) = mapper.get_entry(address, 0) {
75a17651b1SMemoryShore             if entry.present() {
76a17651b1SMemoryShore                 if !entry.flags().has_execute() {
77*2eab6dd7S曾俊                     error!("kernel tried to execute NX-protected page - exploit attempt?");
78a17651b1SMemoryShore                 } else if mapper.table().phys().data() & MMArch::ENTRY_FLAG_USER != 0
79a17651b1SMemoryShore                     && unsafe { x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_SMEP) }
80a17651b1SMemoryShore                 {
81*2eab6dd7S曾俊                     error!("unable to execute userspace code (SMEP?)");
82a17651b1SMemoryShore                 }
83a17651b1SMemoryShore             }
84a17651b1SMemoryShore         }
85a17651b1SMemoryShore         if address.data() < X86_64MMArch::PAGE_SIZE && !regs.is_from_user() {
86*2eab6dd7S曾俊             error!(
87a17651b1SMemoryShore                 "BUG: kernel NULL pointer dereference, address: {:#x}",
88a17651b1SMemoryShore                 address.data()
89a17651b1SMemoryShore             );
90a17651b1SMemoryShore         } else {
91*2eab6dd7S曾俊             error!(
92a17651b1SMemoryShore                 "BUG: unable to handle page fault for address: {:#x}",
93a17651b1SMemoryShore                 address.data()
94a17651b1SMemoryShore             );
95a17651b1SMemoryShore         }
96a17651b1SMemoryShore 
97*2eab6dd7S曾俊         error!(
98a17651b1SMemoryShore             "#PF: {} {} in {} mode\n",
99a17651b1SMemoryShore             if error_code.contains(X86PfErrorCode::X86_PF_USER) {
100a17651b1SMemoryShore                 "user"
101a17651b1SMemoryShore             } else {
102a17651b1SMemoryShore                 "supervisor"
103a17651b1SMemoryShore             },
104a17651b1SMemoryShore             if error_code.contains(X86PfErrorCode::X86_PF_INSTR) {
105a17651b1SMemoryShore                 "instruction fetch"
106a17651b1SMemoryShore             } else if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
107a17651b1SMemoryShore                 "write access"
108a17651b1SMemoryShore             } else {
109a17651b1SMemoryShore                 "read access"
110a17651b1SMemoryShore             },
111a17651b1SMemoryShore             if regs.is_from_user() {
112a17651b1SMemoryShore                 "user"
113a17651b1SMemoryShore             } else {
114a17651b1SMemoryShore                 "kernel"
115a17651b1SMemoryShore             }
116a17651b1SMemoryShore         );
117*2eab6dd7S曾俊         error!(
118a17651b1SMemoryShore             "#PF: error_code({:#04x}) - {}\n",
119a17651b1SMemoryShore             error_code,
120a17651b1SMemoryShore             if !error_code.contains(X86PfErrorCode::X86_PF_PROT) {
121a17651b1SMemoryShore                 "not-present page"
122a17651b1SMemoryShore             } else if error_code.contains(X86PfErrorCode::X86_PF_RSVD) {
123a17651b1SMemoryShore                 "reserved bit violation"
124a17651b1SMemoryShore             } else if error_code.contains(X86PfErrorCode::X86_PF_PK) {
125a17651b1SMemoryShore                 "protection keys violation"
126a17651b1SMemoryShore             } else {
127a17651b1SMemoryShore                 "permissions violation"
128a17651b1SMemoryShore             }
129a17651b1SMemoryShore         );
130a17651b1SMemoryShore     }
131a17651b1SMemoryShore 
132a17651b1SMemoryShore     pub fn page_fault_oops(
133a17651b1SMemoryShore         regs: &'static TrapFrame,
134a17651b1SMemoryShore         error_code: X86PfErrorCode,
135a17651b1SMemoryShore         address: VirtAddr,
136a17651b1SMemoryShore     ) {
137a17651b1SMemoryShore         if regs.is_from_user() {
138a17651b1SMemoryShore             Self::show_fault_oops(regs, error_code, address);
139a17651b1SMemoryShore         }
140a17651b1SMemoryShore         panic!()
141a17651b1SMemoryShore     }
142a17651b1SMemoryShore 
143a17651b1SMemoryShore     /// 内核态缺页异常处理
144a17651b1SMemoryShore     /// ## 参数
145a17651b1SMemoryShore     ///
146a17651b1SMemoryShore     /// - `regs`: 中断栈帧
147a17651b1SMemoryShore     /// - `error_code`: 错误标志
148a17651b1SMemoryShore     /// - `address`: 发生缺页异常的虚拟地址
149a17651b1SMemoryShore     pub fn do_kern_addr_fault(
150a17651b1SMemoryShore         _regs: &'static TrapFrame,
151a17651b1SMemoryShore         error_code: X86PfErrorCode,
152a17651b1SMemoryShore         address: VirtAddr,
153a17651b1SMemoryShore     ) {
154a17651b1SMemoryShore         panic!(
155a17651b1SMemoryShore             "do_kern_addr_fault has not yet been implemented,
156a17651b1SMemoryShore         fault address: {:#x},
157a17651b1SMemoryShore         error_code: {:#b},
158a17651b1SMemoryShore         pid: {}\n",
159a17651b1SMemoryShore             address.data(),
160a17651b1SMemoryShore             error_code,
161a17651b1SMemoryShore             crate::process::ProcessManager::current_pid().data()
162a17651b1SMemoryShore         );
163a17651b1SMemoryShore         //TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault
164a17651b1SMemoryShore     }
165a17651b1SMemoryShore 
166a17651b1SMemoryShore     /// 用户态缺页异常处理
167a17651b1SMemoryShore     /// ## 参数
168a17651b1SMemoryShore     ///
169a17651b1SMemoryShore     /// - `regs`: 中断栈帧
170a17651b1SMemoryShore     /// - `error_code`: 错误标志
171a17651b1SMemoryShore     /// - `address`: 发生缺页异常的虚拟地址
172a17651b1SMemoryShore     pub unsafe fn do_user_addr_fault(
173a17651b1SMemoryShore         regs: &'static TrapFrame,
174a17651b1SMemoryShore         error_code: X86PfErrorCode,
175a17651b1SMemoryShore         address: VirtAddr,
176a17651b1SMemoryShore     ) {
177a17651b1SMemoryShore         let rflags = RFlags::from_bits_truncate(regs.rflags);
178a17651b1SMemoryShore         let mut flags: FaultFlags = FaultFlags::FAULT_FLAG_ALLOW_RETRY
179a17651b1SMemoryShore             | FaultFlags::FAULT_FLAG_KILLABLE
180a17651b1SMemoryShore             | FaultFlags::FAULT_FLAG_INTERRUPTIBLE;
181a17651b1SMemoryShore 
182a17651b1SMemoryShore         if error_code & (X86PfErrorCode::X86_PF_USER | X86PfErrorCode::X86_PF_INSTR)
183a17651b1SMemoryShore             == X86PfErrorCode::X86_PF_INSTR
184a17651b1SMemoryShore         {
185a17651b1SMemoryShore             Self::page_fault_oops(regs, error_code, address);
186a17651b1SMemoryShore         }
187a17651b1SMemoryShore 
188a17651b1SMemoryShore         let feature = x86::cpuid::CpuId::new()
189a17651b1SMemoryShore             .get_extended_feature_info()
190a17651b1SMemoryShore             .unwrap();
191a17651b1SMemoryShore         if unlikely(
192a17651b1SMemoryShore             feature.has_smap()
193a17651b1SMemoryShore                 && !error_code.contains(X86PfErrorCode::X86_PF_USER)
194a17651b1SMemoryShore                 && rflags.contains(RFlags::FLAGS_AC),
195a17651b1SMemoryShore         ) {
196a17651b1SMemoryShore             Self::page_fault_oops(regs, error_code, address);
197a17651b1SMemoryShore         }
198a17651b1SMemoryShore 
199a17651b1SMemoryShore         if unlikely(error_code.contains(X86PfErrorCode::X86_PF_RSVD)) {
200a17651b1SMemoryShore             // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#pgtable_bad
201a17651b1SMemoryShore             panic!(
202a17651b1SMemoryShore                 "Reserved bits are never expected to be set, error_code: {:#b}, address: {:#x}",
203a17651b1SMemoryShore                 error_code,
204a17651b1SMemoryShore                 address.data()
205a17651b1SMemoryShore             );
206a17651b1SMemoryShore         }
207a17651b1SMemoryShore 
208a17651b1SMemoryShore         if regs.is_from_user() {
209a17651b1SMemoryShore             unsafe { CurrentIrqArch::interrupt_enable() };
210a17651b1SMemoryShore             flags |= FaultFlags::FAULT_FLAG_USER;
211a17651b1SMemoryShore         } else if rflags.contains(RFlags::FLAGS_IF) {
212a17651b1SMemoryShore             unsafe { CurrentIrqArch::interrupt_enable() };
213a17651b1SMemoryShore         }
214a17651b1SMemoryShore 
215a17651b1SMemoryShore         if error_code.contains(X86PfErrorCode::X86_PF_SHSTK) {
216a17651b1SMemoryShore             flags |= FaultFlags::FAULT_FLAG_WRITE;
217a17651b1SMemoryShore         }
218a17651b1SMemoryShore         if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
219a17651b1SMemoryShore             flags |= FaultFlags::FAULT_FLAG_WRITE;
220a17651b1SMemoryShore         }
221a17651b1SMemoryShore         if error_code.contains(X86PfErrorCode::X86_PF_INSTR) {
222a17651b1SMemoryShore             flags |= FaultFlags::FAULT_FLAG_INSTRUCTION;
223a17651b1SMemoryShore         }
224a17651b1SMemoryShore 
225a17651b1SMemoryShore         let current_address_space: Arc<AddressSpace> = AddressSpace::current().unwrap();
226a17651b1SMemoryShore         let mut space_guard = current_address_space.write();
227a17651b1SMemoryShore         let mut fault;
228a17651b1SMemoryShore         loop {
229a17651b1SMemoryShore             let vma = space_guard.mappings.find_nearest(address);
230a17651b1SMemoryShore             // let vma = space_guard.mappings.contains(address);
231a17651b1SMemoryShore 
232a17651b1SMemoryShore             let vma = vma.unwrap_or_else(|| {
233a17651b1SMemoryShore                 panic!(
234a17651b1SMemoryShore                     "can not find nearest vma, error_code: {:#b}, address: {:#x}",
235a17651b1SMemoryShore                     error_code,
236a17651b1SMemoryShore                     address.data(),
237a17651b1SMemoryShore                 )
238a17651b1SMemoryShore             });
239a17651b1SMemoryShore             let guard = vma.lock();
240a17651b1SMemoryShore             let region = *guard.region();
241a17651b1SMemoryShore             let vm_flags = *guard.vm_flags();
242a17651b1SMemoryShore             drop(guard);
243a17651b1SMemoryShore 
244a17651b1SMemoryShore             if !region.contains(address) {
245a17651b1SMemoryShore                 if vm_flags.contains(VmFlags::VM_GROWSDOWN) {
246a17651b1SMemoryShore                     space_guard
247a17651b1SMemoryShore                         .extend_stack(region.start() - address)
248a17651b1SMemoryShore                         .unwrap_or_else(|_| {
249a17651b1SMemoryShore                             panic!(
250a17651b1SMemoryShore                                 "user stack extend failed, error_code: {:#b}, address: {:#x}",
251a17651b1SMemoryShore                                 error_code,
252a17651b1SMemoryShore                                 address.data(),
253a17651b1SMemoryShore                             )
254a17651b1SMemoryShore                         });
255a17651b1SMemoryShore                 } else {
256a17651b1SMemoryShore                     panic!(
257a17651b1SMemoryShore                         "No mapped vma, error_code: {:#b}, address: {:#x}",
258a17651b1SMemoryShore                         error_code,
259a17651b1SMemoryShore                         address.data(),
260a17651b1SMemoryShore                     )
261a17651b1SMemoryShore                 }
262a17651b1SMemoryShore             }
263a17651b1SMemoryShore 
264a17651b1SMemoryShore             if unlikely(Self::vma_access_error(vma.clone(), error_code)) {
265a17651b1SMemoryShore                 panic!(
266a17651b1SMemoryShore                     "vma access error, error_code: {:#b}, address: {:#x}",
267a17651b1SMemoryShore                     error_code,
268a17651b1SMemoryShore                     address.data(),
269a17651b1SMemoryShore                 );
270a17651b1SMemoryShore             }
271a17651b1SMemoryShore             let mapper = &mut space_guard.user_mapper.utable;
272a17651b1SMemoryShore 
273a17651b1SMemoryShore             fault = PageFaultHandler::handle_mm_fault(
274a17651b1SMemoryShore                 PageFaultMessage::new(vma.clone(), address, flags),
275a17651b1SMemoryShore                 mapper,
276a17651b1SMemoryShore             );
277a17651b1SMemoryShore 
278a17651b1SMemoryShore             if fault.contains(VmFaultReason::VM_FAULT_COMPLETED) {
279a17651b1SMemoryShore                 return;
280a17651b1SMemoryShore             }
281a17651b1SMemoryShore 
282a17651b1SMemoryShore             if unlikely(fault.contains(VmFaultReason::VM_FAULT_RETRY)) {
283a17651b1SMemoryShore                 flags |= FaultFlags::FAULT_FLAG_TRIED;
284a17651b1SMemoryShore             } else {
285a17651b1SMemoryShore                 break;
286a17651b1SMemoryShore             }
287a17651b1SMemoryShore         }
288a17651b1SMemoryShore 
289a17651b1SMemoryShore         let vm_fault_error = VmFaultReason::VM_FAULT_OOM
290a17651b1SMemoryShore             | VmFaultReason::VM_FAULT_SIGBUS
291a17651b1SMemoryShore             | VmFaultReason::VM_FAULT_SIGSEGV
292a17651b1SMemoryShore             | VmFaultReason::VM_FAULT_HWPOISON
293a17651b1SMemoryShore             | VmFaultReason::VM_FAULT_HWPOISON_LARGE
294a17651b1SMemoryShore             | VmFaultReason::VM_FAULT_FALLBACK;
295a17651b1SMemoryShore 
296a17651b1SMemoryShore         if likely(!fault.contains(vm_fault_error)) {
297a17651b1SMemoryShore             panic!("fault error: {:?}", fault)
298a17651b1SMemoryShore         }
299a17651b1SMemoryShore     }
300a17651b1SMemoryShore }
301