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