diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index 90e8cf4ce..bfc3f4f85 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -10,14 +10,14 @@ use crate::{ arch::{ interrupt::{trap::X86PfErrorCode, TrapFrame}, mm::{MemoryManagementArch, X86_64MMArch}, - CurrentIrqArch, MMArch, + CurrentIrqArch, MMArch, ProtectionKey, }, exception::InterruptArch, kerror, mm::{ - fault::{FaultFlags, PageFault, PageFaultHandler}, + fault::{FaultFlags, PageFault, PageFaultHandler, PageFaultMessage}, ucontext::{AddressSpace, LockedVMA}, - VirtAddr, VmFaultReason, VmFlags, + ProtectionKeyTrait, VirtAddr, VmFaultReason, VmFlags, }, }; @@ -41,8 +41,7 @@ impl PageFault for X86_64PageFault { if foreign | vma.is_foreign() { return true; } - let guard = vma.lock(); - super::pkru::pkru_allows_pkey(guard.pkey(), write) + super::pkey::pkru_allows_pkey(ProtectionKey::vma_pkey(vma), write) } } @@ -160,13 +159,35 @@ impl X86_64PageFault { panic!() } + /// 内核态缺页异常处理 + /// ## 参数 + /// + /// - `regs`: 中断栈帧 + /// - `error_code`: 错误标志 + /// - `address`: 发生缺页异常的虚拟地址 pub fn do_kern_addr_fault( _regs: &'static TrapFrame, - _error_code: X86PfErrorCode, - _address: VirtAddr, + error_code: X86PfErrorCode, + address: VirtAddr, ) { + panic!( + "do_kern_addr_fault has not yet been implemented, + fault address: {:#x}, + error_code: {:#b}, + pid: {}\n", + address.data(), + error_code, + crate::process::ProcessManager::current_pid().data() + ); + //TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault } + /// 用户态缺页异常处理 + /// ## 参数 + /// + /// - `regs`: 中断栈帧 + /// - `error_code`: 错误标志 + /// - `address`: 发生缺页异常的虚拟地址 pub unsafe fn do_user_addr_fault( regs: &'static TrapFrame, error_code: X86PfErrorCode, @@ -242,7 +263,14 @@ impl X86_64PageFault { } let mapper = &mut space_guard.user_mapper.utable; - fault = PageFaultHandler::handle_mm_fault(vma.clone(), mapper, address, flags, regs); + fault = PageFaultHandler::handle_mm_fault( + PageFaultMessage { + vma: vma.clone(), + address, + flags, + }, + mapper, + ); if fault.contains(VmFaultReason::VM_FAULT_COMPLETED) { return; diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 58d3bc91a..97a9697e6 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -1,7 +1,7 @@ pub mod barrier; pub mod bump; pub mod fault; -pub mod pkru; +pub mod pkey; use alloc::vec::Vec; use hashbrown::HashSet; diff --git a/kernel/src/arch/x86_64/mm/pkey.rs b/kernel/src/arch/x86_64/mm/pkey.rs new file mode 100644 index 000000000..f9b70fd86 --- /dev/null +++ b/kernel/src/arch/x86_64/mm/pkey.rs @@ -0,0 +1,52 @@ +use alloc::sync::Arc; + +use crate::mm::{ucontext::LockedVMA, ProtectionKeyTrait}; + +pub struct X86_64ProtectionKey; + +impl ProtectionKeyTrait for X86_64ProtectionKey { + const VM_PKEY_SHIFT: usize = 32; + + /// X86_64架构的ProtectionKey使用32、33、34、35四个比特位 + const PKEY_MASK: usize = 1 << 32 | 1 << 33 | 1 << 34 | 1 << 35; + + fn vma_pkey(vma: Arc) -> u16 { + let guard = vma.lock(); + ((guard.vm_flags().bits() & Self::PKEY_MASK as u64) >> Self::VM_PKEY_SHIFT) as u16 + } +} + +// TODO pkru实现参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/pkru.h + +const PKRU_AD_BIT: u16 = 0x1; +const PKRU_WD_BIT: u16 = 0x2; +const PKRU_BITS_PER_PKEY: u32 = 2; + +pub fn pkru_allows_pkey(pkey: u16, write: bool) -> bool { + let pkru = read_pkru(); + + if !pkru_allows_read(pkru, pkey) { + return false; + } + if write & !pkru_allows_write(pkru, pkey) { + return false; + } + + true +} + +pub fn pkru_allows_read(pkru: u32, pkey: u16) -> bool { + let pkru_pkey_bits: u32 = pkey as u32 * PKRU_BITS_PER_PKEY; + pkru & ((PKRU_AD_BIT as u32) << pkru_pkey_bits) > 0 +} + +pub fn pkru_allows_write(pkru: u32, pkey: u16) -> bool { + let pkru_pkey_bits: u32 = pkey as u32 * PKRU_BITS_PER_PKEY; + pkru & (((PKRU_AD_BIT | PKRU_WD_BIT) as u32) << pkru_pkey_bits) > 0 +} + +pub fn read_pkru() -> u32 { + // TODO 实现读取pkru逻辑 + // https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/pkru.h?fi=read_pkru#read_pkru + 0 +} diff --git a/kernel/src/arch/x86_64/mm/pkru.rs b/kernel/src/arch/x86_64/mm/pkru.rs deleted file mode 100644 index 079bb4f00..000000000 --- a/kernel/src/arch/x86_64/mm/pkru.rs +++ /dev/null @@ -1,30 +0,0 @@ -const PKRU_AD_BIT: u16 = 0x1; -const PKRU_WD_BIT: u16 = 0x2; -const PKRU_BITS_PER_PKEY: u32 = 2; - -pub fn pkru_allows_pkey(pkey: u16, write: bool) -> bool { - let pkru = read_pkru(); - - if !pkru_allows_read(pkru, pkey) { - return false; - } - if write & !pkru_allows_write(pkru, pkey) { - return false; - } - - true -} - -pub fn pkru_allows_read(pkru: u32, pkey: u16) -> bool { - let pkru_pkey_bits: u32 = pkey as u32 * PKRU_BITS_PER_PKEY; - pkru & ((PKRU_AD_BIT as u32) << pkru_pkey_bits) > 0 -} - -pub fn pkru_allows_write(pkru: u32, pkey: u16) -> bool { - let pkru_pkey_bits: u32 = pkey as u32 * PKRU_BITS_PER_PKEY; - pkru & (((PKRU_AD_BIT | PKRU_WD_BIT) as u32) << pkru_pkey_bits) > 0 -} - -pub fn read_pkru() -> u32 { - 0 -} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 219850c93..5c38d2f96 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -40,3 +40,5 @@ pub use crate::arch::smp::X86_64SMPArch as CurrentSMPArch; pub use crate::arch::sched::X86_64SchedArch as CurrentSchedArch; pub use crate::arch::mm::fault::X86_64PageFault as PageFaultArch; + +pub use crate::arch::mm::pkey::X86_64ProtectionKey as ProtectionKey; diff --git a/kernel/src/mm/fault.rs b/kernel/src/mm/fault.rs index fb8ae7a65..39fbd2443 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -3,7 +3,7 @@ use core::{alloc::Layout, intrinsics::unlikely, panic}; use alloc::sync::Arc; use crate::{ - arch::{interrupt::TrapFrame, mm::PageMapper, MMArch, PageFaultArch}, + arch::{mm::PageMapper, MMArch, PageFaultArch}, mm::{ page::{page_manager_lock_irqsave, PageFlags}, ucontext::LockedVMA, @@ -32,7 +32,23 @@ bitflags! { } } +/// # 缺页中断trait +/// +/// 封装了处理缺页中断需要的方法和属性,需要根据架构进行不同的实现 pub trait PageFault { + /// 判断一个VMA是否允许访问 + /// + /// ## 参数 + /// + /// - `vma`: 进行判断的VMA + /// - `write`: 是否需要写入权限(true 表示需要写权限) + /// - `execute`: 是否需要执行权限(true 表示需要执行权限) + /// - `foreign`: 是否是外部的(即非当前进程的)VMA + /// + /// ## 返回值 + /// - `true`: VMA允许访问 + /// - `false`: 错误的说明 + fn vma_access_permitted( _vma: Arc, _write: bool, @@ -43,16 +59,33 @@ pub trait PageFault { } } +/// # 缺页异常信息结构体 +/// 包含了页面错误处理的相关信息,例如出错的地址、VMA等 +#[derive(Debug)] +pub struct PageFaultMessage { + pub vma: Arc, + pub address: VirtAddr, + pub flags: FaultFlags, +} + +/// 缺页中断处理结构体 pub struct PageFaultHandler; impl PageFaultHandler { - pub unsafe fn handle_mm_fault( - vma: Arc, - mapper: &mut PageMapper, - address: VirtAddr, - flags: FaultFlags, - _regs: &'static TrapFrame, - ) -> VmFaultReason { + /// 处理缺页异常 + /// ## 参数 + /// + /// - `vma`: VMA + /// - `mapper`: VMA + /// - `address`: VMA + /// - `flags`: VMA + /// + /// ## 返回值 + /// - Some(Arc): 虚拟地址所在的或最近的下一个VMA + /// - None: 未找到VMA + pub unsafe fn handle_mm_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + let flags = pfm.flags; + let vma = pfm.vma.clone(); let current_pcb = ProcessManager::current_pcb(); let mut guard = current_pcb.sched_info().inner_lock_write_irqsave(); guard.set_state(ProcessState::Runnable); @@ -70,20 +103,28 @@ impl PageFaultHandler { let vm_flags = *guard.vm_flags(); drop(guard); if unlikely(vm_flags.contains(VmFlags::VM_HUGETLB)) { - //TODO: 添加handle_hugetlb_fault + //TODO: 添加handle_hugetlb_fault处理大页缺页异常 } else { - Self::handle_normal_fault(vma.clone(), mapper, address, flags); + Self::handle_normal_fault(pfm, mapper); } VmFaultReason::VM_FAULT_COMPLETED } + /// 处理普通页缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 pub unsafe fn handle_normal_fault( - vma: Arc, + pfm: PageFaultMessage, mapper: &mut PageMapper, - address: VirtAddr, - flags: FaultFlags, ) -> VmFaultReason { + let address = pfm.address; + let vma = pfm.vma.clone(); if mapper.get_entry(address, 3).is_none() { mapper .allocate_table(address, 2) @@ -104,25 +145,34 @@ impl PageFaultHandler { } } - Self::handle_pte_fault(vma, mapper, address, flags) + Self::handle_pte_fault(pfm, mapper) } + /// 处理页表项异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 pub unsafe fn handle_pte_fault( - vma: Arc, + pfm: PageFaultMessage, mapper: &mut PageMapper, - address: VirtAddr, - flags: FaultFlags, ) -> VmFaultReason { + let address = pfm.address; + let flags = pfm.flags; + let vma = pfm.vma.clone(); if let Some(mut entry) = mapper.get_entry(address, 0) { if !entry.present() { - return Self::do_swap_page(vma, mapper, address, flags); + return Self::do_swap_page(pfm, mapper); } if entry.protnone() && vma.is_accessible() { - return Self::do_numa_page(vma, mapper, address, flags); + return Self::do_numa_page(pfm, mapper); } if flags.intersects(FaultFlags::FAULT_FLAG_WRITE | FaultFlags::FAULT_FLAG_UNSHARE) { if !entry.write() { - return Self::do_wp_page(vma, mapper, address); + return Self::do_wp_page(pfm, mapper); } else { entry.set_flags(PageFlags::from_data(MMArch::ENTRY_FLAG_DIRTY)); } @@ -132,20 +182,30 @@ impl PageFaultHandler { entry.set_flags(entry.flags().set_access(true)); pte_table.set_entry(i, entry); } else if vma.is_anonymous() { - return Self::do_anonymous_page(vma, mapper, address); + return Self::do_anonymous_page(pfm, mapper); } else { - return Self::do_fault(vma, mapper, address, flags); + return Self::do_fault(pfm, mapper); } VmFaultReason::VM_FAULT_COMPLETED } + /// 处理匿名映射页缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 pub unsafe fn do_anonymous_page( - vma: Arc, + pfm: PageFaultMessage, mapper: &mut PageMapper, - address: VirtAddr, ) -> VmFaultReason { - if let Some(flush) = mapper.map(address, vma.lock().flags()) { + let address = pfm.address; + let vma = pfm.vma.clone(); + let guard = vma.lock(); + if let Some(flush) = mapper.map(address, guard.flags()) { flush.flush(); crate::debug::klog::mm::mm_debug_log( klog_types::AllocatorLogType::LazyAlloc(klog_types::AllocLogItem::new( @@ -165,41 +225,140 @@ impl PageFaultHandler { } } - pub unsafe fn do_fault( - _vma: Arc, - _mapper: &mut PageMapper, - _address: VirtAddr, - _flags: FaultFlags, - ) -> VmFaultReason { - panic!("do_fault has not yet been implemented"); + /// 处理文件映射页的缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(unused_variables)] + pub unsafe fn do_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_fault has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_fault } - pub unsafe fn do_swap_page( - _vma: Arc, - _mapper: &mut PageMapper, - _address: VirtAddr, - _flags: FaultFlags, - ) -> VmFaultReason { - panic!("do_swap_page has not yet been implemented"); + /// 处理私有文件映射的写时复制 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(dead_code, unused_variables)] + pub unsafe fn do_cow_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_cow_fault has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_cow_fault } - pub unsafe fn do_numa_page( - _vma: Arc, - _mapper: &mut PageMapper, - _address: VirtAddr, - _flags: FaultFlags, - ) -> VmFaultReason { - panic!("do_numa_page has not yet been implemented"); + /// 处理文件映射页的缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(dead_code, unused_variables)] + pub unsafe fn do_read_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_read_fault has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault } - pub unsafe fn do_wp_page( - vma: Arc, - mapper: &mut PageMapper, - address: VirtAddr, - ) -> VmFaultReason { + /// 处理对共享文件映射区写入引起的缺页 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(dead_code, unused_variables)] + pub unsafe fn do_shared_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_shared_fault has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_shared_fault + } + + /// 处理被置换页面的缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(unused_variables)] + pub unsafe fn do_swap_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_swap_page has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_swap_page + } + + /// 处理NUMA的缺页异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + #[allow(unused_variables)] + pub unsafe fn do_numa_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + panic!( + "do_numa_page has not yet been implemented, + fault message: {:?}, + pid: {}\n", + pfm, + crate::process::ProcessManager::current_pid().data() + ); + // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_numa_page + } + + /// 处理写保护页面的写保护异常 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub unsafe fn do_wp_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + let address = pfm.address; + let vma = pfm.vma.clone(); let old_paddr = mapper.translate(address).unwrap().0; let mut page_manager = page_manager_lock_irqsave(); - let map_count = page_manager.get_mut(&old_paddr).map_count; + let map_count = page_manager.get_mut(&old_paddr).map_count(); drop(page_manager); let mut entry = mapper.get_entry(address, 0).unwrap(); diff --git a/kernel/src/mm/madvise.rs b/kernel/src/mm/madvise.rs index 83dcb2884..5e9587a40 100644 --- a/kernel/src/mm/madvise.rs +++ b/kernel/src/mm/madvise.rs @@ -5,12 +5,13 @@ use crate::arch::{mm::PageMapper, MMArch}; use super::{page::Flusher, syscall::MadvFlags, ucontext::LockedVMA, VmFlags}; impl LockedVMA { - pub fn do_advise( + pub fn do_madvise( &self, behavior: MadvFlags, _mapper: &mut PageMapper, _flusher: impl Flusher, ) -> Result<(), SystemError> { + //TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/madvise.c?fi=madvise#do_madvise let mut vma = self.lock(); let mut new_flags = *vma.vm_flags(); match behavior { diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 37028d921..e63551d1a 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -76,6 +76,7 @@ bitflags! { const VM_DONTDUMP = 0x04000000; } + /// 描述页面错误处理过程中发生的不同情况或结果 pub struct VmFaultReason:u32 { const VM_FAULT_OOM = 0x000001; const VM_FAULT_SIGBUS = 0x000002; @@ -780,3 +781,16 @@ pub fn verify_area(addr: VirtAddr, size: usize) -> Result<(), SystemError> { return Ok(()); } + +pub trait ProtectionKeyTrait { + /// ProtectionKey的掩码 + const PKEY_MASK: usize; + + /// ProtectionKey的偏移量 + const VM_PKEY_SHIFT: usize; + + /// 获取vma的protection_key + fn vma_pkey(_vma: Arc) -> u16 { + 0 + } +} diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index 03697cbc5..f348950ed 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -86,7 +86,7 @@ impl PageManager { /// 物理页面信息 pub struct Page { /// 映射计数 - pub map_count: usize, + map_count: usize, /// 是否为共享页 shared: bool, /// 映射计数为0时,是否可回收 @@ -142,9 +142,15 @@ impl Page { self.free_when_zero = dealloc_when_zero; } + #[inline(always)] pub fn anon_vma(&self) -> &HashSet> { &self.anon_vma } + + #[inline(always)] + pub fn map_count(&self) -> usize { + self.map_count + } } #[derive(Debug)] @@ -990,7 +996,15 @@ impl PageMapper { table.next_level_table(i) } - // 获取虚拟地址的指定层级页表 + /// 获取虚拟地址的指定层级页表 + /// ## 参数 + /// + /// - `virt`: 虚拟地址 + /// - `level`: 指定页表层级 + /// + /// ## 返回值 + /// - Some(PageTable): 虚拟地址对应层级的页表 + /// - None: 对应页表不存在 pub fn get_table(&self, virt: VirtAddr, level: usize) -> Option> { let mut table = self.table(); if level > Arch::PAGE_LEVELS - 1 { @@ -1010,7 +1024,15 @@ impl PageMapper { } } - //获取虚拟地址在指定层级页表的有效entry + /// 获取虚拟地址在指定层级页表的PageEntry + /// ## 参数 + /// + /// - `virt`: 虚拟地址 + /// - `level`: 指定页表层级 + /// + /// ## 返回值 + /// - Some(PageEntry): 虚拟地址在指定层级的页表的有效PageEntry + /// - None: 无对应的有效PageEntry pub fn get_entry(&self, virt: VirtAddr, level: usize) -> Option> { let table = self.get_table(virt, level)?; let i = table.index_of(virt)?; @@ -1045,7 +1067,10 @@ impl PageMapper { // } } - // 拷贝用户空间映射 + /// 拷贝用户空间映射 + /// ## 参数 + /// + /// - `umapper`: 要拷贝的用户空间 pub unsafe fn clone_user_mapping(&mut self, umapper: &mut Self) { let old_table = umapper.table(); let new_table = self.table(); diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs index 29e0ed0b9..ec789ee7a 100644 --- a/kernel/src/mm/syscall.rs +++ b/kernel/src/mm/syscall.rs @@ -75,42 +75,65 @@ bitflags! { pub struct MadvFlags: u64 { - const MADV_NORMAL = 0; /* no further special treatment */ - const MADV_RANDOM = 1; /* expect random page references */ - const MADV_SEQUENTIAL = 2; /* expect sequential page references */ - const MADV_WILLNEED = 3; /* will need these pages */ - const MADV_DONTNEED = 4; /* don't need these pages */ - - /* common parameters: try to keep these consistent across architectures */ - const MADV_FREE = 8; /* free pages only if memory pressure */ - const MADV_REMOVE = 9; /* remove these pages & resources */ - const MADV_DONTFORK = 10; /* don't inherit across fork */ - const MADV_DOFORK = 11; /* do inherit across fork */ - const MADV_HWPOISON = 100; /* poison a page for testing */ - const MADV_SOFT_OFFLINE = 101; /* soft offline page for testing */ - - const MADV_MERGEABLE = 12; /* KSM may merge identical pages */ - const MADV_UNMERGEABLE = 13; /* KSM may not merge identical pages */ - - const MADV_HUGEPAGE = 14; /* Worth backing with hugepages */ - const MADV_NOHUGEPAGE = 15; /* Not worth backing with hugepages */ - - const MADV_DONTDUMP = 16; /* Explicity exclude from the core dump, - overrides the coredump filter bits */ - const MADV_DODUMP = 17; /* Clear the MADV_DONTDUMP flag */ - - const MADV_WIPEONFORK = 18; /* Zero memory on fork, child only */ - const MADV_KEEPONFORK = 19; /* Undo MADV_WIPEONFORK */ - - const MADV_COLD = 20; /* deactivate these pages */ - const MADV_PAGEOUT = 21; /* reclaim these pages */ - - const MADV_POPULATE_READ = 22; /* populate (prefault) page tables readable */ - const MADV_POPULATE_WRITE = 23; /* populate (prefault) page tables writable */ - - const MADV_DONTNEED_LOCKED = 24; /* like DONTNEED, but drop locked pages too */ - - const MADV_COLLAPSE = 25; /* Synchronous hugepage collapse */ + /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 + const MADV_NORMAL = 0; + /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 + const MADV_RANDOM = 1; + /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 + const MADV_SEQUENTIAL = 2; + /// 通知系统预读某些页面,用于应用程序提前准备数据 + const MADV_WILLNEED = 3; + /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 + const MADV_DONTNEED = 4; + + /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 + const MADV_FREE = 8; + /// 应用程序请求释放指定范围的页面和相关的后备存储 + const MADV_REMOVE = 9; + /// 在 fork 时排除指定区域 + const MADV_DONTFORK = 10; + /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 + const MADV_DOFORK = 11; + /// 模拟内存硬件错误,触发内存错误处理器处理 + const MADV_HWPOISON = 100; + /// 尝试软下线指定的内存范围 + const MADV_SOFT_OFFLINE = 101; + + /// 应用程序建议内核尝试合并指定范围内内容相同的页面 + const MADV_MERGEABLE = 12; + /// 取消 MADV_MERGEABLE 的效果,不再合并页面 + const MADV_UNMERGEABLE = 13; + + /// 应用程序希望将指定范围以透明大页方式支持 + const MADV_HUGEPAGE = 14; + /// 将指定范围标记为不值得用透明大页支持 + const MADV_NOHUGEPAGE = 15; + + /// 应用程序请求在核心转储时排除指定范围内的页面 + const MADV_DONTDUMP = 16; + /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 + const MADV_DODUMP = 17; + + /// 在 fork 时将子进程的该区域内存填充为零 + const MADV_WIPEONFORK = 18; + /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 + const MADV_KEEPONFORK = 19; + + /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 + const MADV_COLD = 20; + /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 + const MADV_PAGEOUT = 21; + + /// 预先填充页面表,可读,通过触发读取故障 + const MADV_POPULATE_READ = 22; + /// 预先填充页面表,可写,通过触发写入故障 + const MADV_POPULATE_WRITE = 23; + + /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 + const MADV_DONTNEED_LOCKED = 24; + + /// 同步将页面合并为新的透明大页 + const MADV_COLLAPSE = 25; } } diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index c39a30680..172a50ff8 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -229,6 +229,7 @@ impl InnerAddressSpace { /// - `prot_flags`:保护标志 /// - `map_flags`:映射标志 /// - `round_to_min`:是否将`start_vaddr`对齐到`mmap_min`,如果为`true`,则当`start_vaddr`不为0时,会对齐到`mmap_min`,否则仅向下对齐到页边界 + /// - `allocate_at_once`:是否立即分配物理空间 /// /// ## 返回 /// @@ -598,7 +599,7 @@ impl InnerAddressSpace { if let Some(after) = split_result.after { self.mappings.insert_vma(after); } - r.do_advise(behavior, mapper, &mut flusher)?; + r.do_madvise(behavior, mapper, &mut flusher)?; self.mappings.insert_vma(r); } Ok(()) @@ -763,9 +764,14 @@ impl UserMappings { return None; } - /// 判断当前进程的VMA内,是否有包含指定的虚拟地址的VMA。 + /// 向下寻找距离虚拟地址最近的VMA + /// ## 参数 /// - /// 如果有,返回包含指定虚拟地址的VMA的Arc指针,否则返回None。 + /// - `vaddr`: 虚拟地址 + /// + /// ## 返回值 + /// - Some(Arc): 虚拟地址所在的或最近的下一个VMA + /// - None: 未找到VMA #[allow(dead_code)] pub fn find_nearest(&self, vaddr: VirtAddr) -> Option> { let mut nearest: Option> = None; @@ -1036,27 +1042,28 @@ impl LockedVMA { let mut page_manager_guard: SpinLockGuard<'_, crate::mm::page::PageManager> = page_manager_lock_irqsave(); for page in guard.region.pages() { - if mapper.translate(page.virt_address()).is_some() { - let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) } - .expect("Failed to unmap, beacuse of some page is not mapped"); - - // 从anon_vma中删除当前VMA - let page = page_manager_guard.get_mut(&paddr); - page.remove_vma(self); - - // 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页. - if page.can_deallocate() { - unsafe { - deallocate_page_frames( - PhysPageFrame::new(paddr), - PageFrameCount::new(1), - &mut page_manager_guard, - ) - }; - } + if mapper.translate(page.virt_address()).is_none() { + continue; + } + let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) } + .expect("Failed to unmap, beacuse of some page is not mapped"); - flusher.consume(flush); + // 从anon_vma中删除当前VMA + let page = page_manager_guard.get_mut(&paddr); + page.remove_vma(self); + + // 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页. + if page.can_deallocate() { + unsafe { + deallocate_page_frames( + PhysPageFrame::new(paddr), + PageFrameCount::new(1), + &mut page_manager_guard, + ) + }; } + + flusher.consume(flush); } guard.mapped = false; } @@ -1145,34 +1152,34 @@ impl LockedVMA { )); } + /// 判断VMA是否为外部(非当前进程空间)的VMA pub fn is_foreign(&self) -> bool { let guard = self.lock(); if let Some(space) = guard.user_address_space.clone() { if let Some(space) = space.upgrade() { - if AddressSpace::is_current(&space) { - return true; - } + return AddressSpace::is_current(&space); } else { return true; } } else { return true; } - - false } + /// 判断VMA是否可访问 pub fn is_accessible(&self) -> bool { let guard = self.lock(); let vm_access_flags: VmFlags = VmFlags::VM_READ | VmFlags::VM_WRITE | VmFlags::VM_EXEC; guard.vm_flags().intersects(vm_access_flags) } + /// 判断VMA是否为匿名映射 pub fn is_anonymous(&self) -> bool { //TODO: 实现匿名映射判断逻辑,目前仅支持匿名映射 true } + /// 判断VMA是否为大页映射 pub fn is_hugepage(&self) -> bool { //TODO: 实现巨页映射判断逻辑,目前不支持巨页映射 false @@ -1489,12 +1496,6 @@ impl VMA { // kdebug!("VMA::zeroed: done"); return Ok(r); } - - pub fn pkey(&self) -> u16 { - let pkey_mask: u64 = 1 << 32 | 1 << 33 | 1 << 34 | 1 << 35; - let pkey_shift = 32; - ((self.vm_flags.bits() & pkey_mask) >> pkey_shift) as u16 - } } impl Drop for VMA {