diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index 76bfbed0..a335dee5 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -12,7 +12,7 @@ use crate::{ page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage, PhysPageFrame}, }, kernel_mapper::KernelMapper, - page::{PageEntry, PageFlags, PAGE_1G_SHIFT}, + page::{EntryFlags, PageEntry, PAGE_1G_SHIFT}, ucontext::UserMapper, MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, }, @@ -270,8 +270,8 @@ impl VirtAddr { } /// 获取内核地址默认的页面标志 -pub unsafe fn kernel_page_flags(_virt: VirtAddr) -> PageFlags { - PageFlags::from_data(RiscV64MMArch::ENTRY_FLAG_DEFAULT_PAGE) +pub unsafe fn kernel_page_flags(_virt: VirtAddr) -> EntryFlags { + EntryFlags::from_data(RiscV64MMArch::ENTRY_FLAG_DEFAULT_PAGE) .set_user(false) .set_execute(true) } diff --git a/kernel/src/arch/x86_64/kvm/vmx/ept.rs b/kernel/src/arch/x86_64/kvm/vmx/ept.rs index 03223190..838c1a15 100644 --- a/kernel/src/arch/x86_64/kvm/vmx/ept.rs +++ b/kernel/src/arch/x86_64/kvm/vmx/ept.rs @@ -1,7 +1,7 @@ use crate::arch::mm::LockedFrameAllocator; use crate::arch::mm::PageMapper; use crate::arch::MMArch; -use crate::mm::page::PageFlags; +use crate::mm::page::EntryFlags; use crate::mm::{PageTableKind, PhysAddr, VirtAddr}; use crate::smp::core::smp_get_processor_id; use crate::smp::cpu::AtomicProcessorId; @@ -92,7 +92,7 @@ impl EptMapper { &mut self, gpa: u64, hpa: u64, - flags: PageFlags, + flags: EntryFlags, ) -> Result<(), SystemError> { if self.readonly { return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); diff --git a/kernel/src/arch/x86_64/kvm/vmx/mmu.rs b/kernel/src/arch/x86_64/kvm/vmx/mmu.rs index e28b3f03..c05ef9bb 100644 --- a/kernel/src/arch/x86_64/kvm/vmx/mmu.rs +++ b/kernel/src/arch/x86_64/kvm/vmx/mmu.rs @@ -1,7 +1,7 @@ use crate::{ arch::kvm::vmx::ept::EptMapper, libs::mutex::Mutex, - mm::{page::PageFlags, syscall::ProtFlags}, + mm::{page::EntryFlags, syscall::ProtFlags}, virt::kvm::host_mem::{__gfn_to_pfn, kvm_vcpu_gfn_to_memslot, PAGE_MASK, PAGE_SHIFT}, }; use bitfield_struct::bitfield; @@ -218,7 +218,7 @@ pub fn __direct_map( } // 把gpa映射到hpa let mut ept_mapper = EptMapper::lock(); - let page_flags = PageFlags::from_prot_flags(ProtFlags::from_bits_truncate(0x7_u64), false); + let page_flags = EntryFlags::from_prot_flags(ProtFlags::from_bits_truncate(0x7_u64), false); unsafe { assert!(ept_mapper.walk(gpa, pfn << PAGE_SHIFT, page_flags).is_ok()); } diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 6eaf2dd5..841ae433 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -28,7 +28,7 @@ use crate::{ }; use crate::mm::kernel_mapper::KernelMapper; -use crate::mm::page::{PageEntry, PageFlags, PAGE_1G_SHIFT}; +use crate::mm::page::{EntryFlags, PageEntry, PAGE_1G_SHIFT}; use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr}; use system_error::SystemError; @@ -650,17 +650,17 @@ impl FrameAllocator for LockedFrameAllocator { } /// 获取内核地址默认的页面标志 -pub unsafe fn kernel_page_flags(virt: VirtAddr) -> PageFlags { +pub unsafe fn kernel_page_flags(virt: VirtAddr) -> EntryFlags { let info: X86_64MMBootstrapInfo = BOOTSTRAP_MM_INFO.unwrap(); if virt.data() >= info.kernel_code_start && virt.data() < info.kernel_code_end { // Remap kernel code execute - return PageFlags::new().set_execute(true).set_write(true); + return EntryFlags::new().set_execute(true).set_write(true); } else if virt.data() >= info.kernel_data_end && virt.data() < info.kernel_rodata_end { // Remap kernel rodata read only - return PageFlags::new().set_execute(true); + return EntryFlags::new().set_execute(true); } else { - return PageFlags::new().set_write(true).set_execute(true); + return EntryFlags::new().set_write(true).set_execute(true); } } diff --git a/kernel/src/driver/net/dma.rs b/kernel/src/driver/net/dma.rs index 11fcf622..f8c06b74 100644 --- a/kernel/src/driver/net/dma.rs +++ b/kernel/src/driver/net/dma.rs @@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags; use crate::arch::MMArch; use crate::mm::kernel_mapper::KernelMapper; -use crate::mm::page::{page_manager_lock_irqsave, PageFlags}; +use crate::mm::page::{page_manager_lock_irqsave, EntryFlags}; use crate::mm::{ allocator::page_frame::{ allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame, @@ -25,7 +25,7 @@ pub fn dma_alloc(pages: usize) -> (usize, NonNull) { // 清空这块区域,防止出现脏数据 core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE); - let dma_flags: PageFlags = PageFlags::mmio_flags(); + let dma_flags: EntryFlags = EntryFlags::mmio_flags(); let mut kernel_mapper = KernelMapper::lock(); let kernel_mapper = kernel_mapper.as_mut().unwrap(); diff --git a/kernel/src/driver/video/mod.rs b/kernel/src/driver/video/mod.rs index 282e672d..e9a70514 100644 --- a/kernel/src/driver/video/mod.rs +++ b/kernel/src/driver/video/mod.rs @@ -10,7 +10,7 @@ use crate::{ spinlock::SpinLock, }, mm::{ - allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::PageFlags, + allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::EntryFlags, MemoryManagementArch, }, time::timer::{Timer, TimerFunction}, @@ -95,7 +95,7 @@ impl VideoRefreshManager { let count = PageFrameCount::new( page_align_up(frame_buffer_info_guard.buf_size()) / MMArch::PAGE_SIZE, ); - let page_flags: PageFlags = PageFlags::new().set_execute(true).set_write(true); + let page_flags: EntryFlags = EntryFlags::new().set_execute(true).set_write(true); let mut kernel_mapper = KernelMapper::lock(); let mut kernel_mapper = kernel_mapper.as_mut(); diff --git a/kernel/src/driver/virtio/virtio_impl.rs b/kernel/src/driver/virtio/virtio_impl.rs index 256b40eb..0166b138 100644 --- a/kernel/src/driver/virtio/virtio_impl.rs +++ b/kernel/src/driver/virtio/virtio_impl.rs @@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags; use crate::arch::MMArch; use crate::mm::kernel_mapper::KernelMapper; -use crate::mm::page::{page_manager_lock_irqsave, PageFlags}; +use crate::mm::page::{page_manager_lock_irqsave, EntryFlags}; use crate::mm::{ allocator::page_frame::{ allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame, @@ -32,7 +32,7 @@ unsafe impl Hal for HalImpl { // 清空这块区域,防止出现脏数据 core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE); - let dma_flags: PageFlags = PageFlags::mmio_flags(); + let dma_flags: EntryFlags = EntryFlags::mmio_flags(); let mut kernel_mapper = KernelMapper::lock(); let kernel_mapper = kernel_mapper.as_mut().unwrap(); diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 2271065d..c7646076 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -5,6 +5,7 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; +use hashbrown::HashMap; use log::error; use system_error::SystemError; @@ -16,6 +17,7 @@ use crate::{ filesystem::procfs::ProcfsFilePrivateData, ipc::pipe::{LockedPipeInode, PipeFsPrivateData}, libs::{rwlock::RwLock, spinlock::SpinLock}, + mm::page::Page, net::{ event_poll::{EPollItem, EPollPrivateData, EventPoll}, socket::SocketInode, @@ -118,6 +120,45 @@ impl FileMode { return self.bits() & FileMode::O_ACCMODE.bits(); } } + +#[allow(dead_code)] +pub struct PageCache { + inode_ref: Weak, + map: HashMap>, +} + +impl PageCache { + pub fn new(inode_ref: Weak) -> PageCache { + Self { + inode_ref, + map: HashMap::new(), + } + } + + pub fn add_page(&mut self, offset: usize, page: Arc) { + self.map.insert(offset, page); + } + + pub fn get_page(&self, offset: usize) -> Option> { + self.map.get(&offset).cloned() + } + + // pub fn get_pages(&self, start_pgoff: usize, end_pgoff: usize) -> Vec> { + // let mut vec = Vec::new(); + // for pgoff in start_pgoff..=end_pgoff { + // if let Some(page) = self.map.get(&pgoff) { + // vec.push(page.clone()); + // } + // } + // vec + // } +} + +pub trait PageCacheOperations: IndexNode { + fn write_page(&self, page: Page); + fn read_ahead(&self); +} + /// @brief 抽象文件结构体 #[derive(Debug)] pub struct File { diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 7bdbe47b..09c04f07 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -23,7 +23,12 @@ use crate::{ time::PosixTimeSpec, }; -use self::{core::generate_inode_id, file::FileMode, syscall::ModeType, utils::DName}; +use self::{ + core::generate_inode_id, + file::{FileMode, PageCache}, + syscall::ModeType, + utils::DName, +}; pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; /// vfs容许的最大的路径名称长度 @@ -548,6 +553,10 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { fn parent(&self) -> Result, SystemError> { return self.find(".."); } + + fn page_cache(&self) -> Option { + None + } } impl DowncastArc for dyn IndexNode { diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 13c9f1b0..f3f87eb7 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -165,7 +165,7 @@ impl ShmManager { let mut page_manager_guard = page_manager_lock_irqsave(); let mut cur_phys = PhysPageFrame::new(phys_page.0); for _ in 0..page_count.data() { - let mut page = Page::new(true); + let mut page = Page::new(true, cur_phys); page.set_shm_id(shm_id); let paddr = cur_phys.phys_address(); page_manager_guard.insert(paddr, page); diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs index 37a9cc9c..6cc525bb 100644 --- a/kernel/src/ipc/syscall.rs +++ b/kernel/src/ipc/syscall.rs @@ -20,7 +20,7 @@ use crate::{ libs::spinlock::SpinLock, mm::{ allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame}, - page::{page_manager_lock_irqsave, PageFlags, PageFlushAll}, + page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll}, syscall::ProtFlags, ucontext::{AddressSpace, VMA}, VirtAddr, VmFlags, @@ -324,8 +324,8 @@ impl Syscall { .ok_or(SystemError::EINVAL)?; let vm_flags = VmFlags::from(shmflg); let destination = VirtPageFrame::new(region.start()); - let page_flags: PageFlags = - PageFlags::from_prot_flags(ProtFlags::from(vm_flags), true); + let page_flags: EntryFlags = + EntryFlags::from_prot_flags(ProtFlags::from(vm_flags), true); let flusher: PageFlushAll = PageFlushAll::new(); // 将共享内存映射到对应虚拟区域 @@ -358,7 +358,7 @@ impl Syscall { // 验证用户虚拟内存区域是否有效 let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?; - // 必须在取消映射前获取到PageFlags + // 必须在取消映射前获取到EntryFlags let page_flags = address_write_guard .user_mapper .utable diff --git a/kernel/src/mm/c_adapter.rs b/kernel/src/mm/c_adapter.rs index bd949fa5..1c824595 100644 --- a/kernel/src/mm/c_adapter.rs +++ b/kernel/src/mm/c_adapter.rs @@ -15,7 +15,7 @@ use crate::{ use super::{ allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, mmio_buddy::mmio_pool, - no_init::pseudo_map_phys, page::PageFlags, MemoryManagementArch, PhysAddr, VirtAddr, + no_init::pseudo_map_phys, page::EntryFlags, MemoryManagementArch, PhysAddr, VirtAddr, }; lazy_static! { @@ -40,7 +40,7 @@ pub unsafe extern "C" fn rs_map_phys(vaddr: usize, paddr: usize, size: usize, fl let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE); // debug!("rs_map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}"); - let mut page_flags: PageFlags = PageFlags::new().set_execute(true).set_write(true); + let mut page_flags: EntryFlags = EntryFlags::new().set_execute(true).set_write(true); if flags & PAGE_U_S as usize != 0 { page_flags = page_flags.set_user(true); } diff --git a/kernel/src/mm/fault.rs b/kernel/src/mm/fault.rs index 71e0623a..63116c04 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -1,11 +1,11 @@ -use core::{alloc::Layout, intrinsics::unlikely, panic}; +use core::{alloc::Layout, cmp::min, intrinsics::unlikely, panic}; -use alloc::sync::Arc; +use alloc::{sync::Arc, vec::Vec}; use crate::{ arch::{mm::PageMapper, MMArch}, mm::{ - page::{page_manager_lock_irqsave, PageFlags}, + page::{page_manager_lock_irqsave, EntryFlags}, ucontext::LockedVMA, VirtAddr, VmFaultReason, VmFlags, }, @@ -14,21 +14,27 @@ use crate::{ use crate::mm::MemoryManagementArch; +use super::{ + allocator::page_frame::{FrameAllocator, PhysPageFrame}, + page::{Page, PageFlags}, + phys_2_virt, +}; + bitflags! { pub struct FaultFlags: u64{ - const FAULT_FLAG_WRITE = 1 << 0; - const FAULT_FLAG_MKWRITE = 1 << 1; - const FAULT_FLAG_ALLOW_RETRY = 1 << 2; - const FAULT_FLAG_RETRY_NOWAIT = 1 << 3; - const FAULT_FLAG_KILLABLE = 1 << 4; - const FAULT_FLAG_TRIED = 1 << 5; - const FAULT_FLAG_USER = 1 << 6; - const FAULT_FLAG_REMOTE = 1 << 7; - const FAULT_FLAG_INSTRUCTION = 1 << 8; - const FAULT_FLAG_INTERRUPTIBLE =1 << 9; - const FAULT_FLAG_UNSHARE = 1 << 10; - const FAULT_FLAG_ORIG_PTE_VALID = 1 << 11; - const FAULT_FLAG_VMA_LOCK = 1 << 12; + const FAULT_FLAG_WRITE = 1 << 0; + const FAULT_FLAG_MKWRITE = 1 << 1; + const FAULT_FLAG_ALLOW_RETRY = 1 << 2; + const FAULT_FLAG_RETRY_NOWAIT = 1 << 3; + const FAULT_FLAG_KILLABLE = 1 << 4; + const FAULT_FLAG_TRIED = 1 << 5; + const FAULT_FLAG_USER = 1 << 6; + const FAULT_FLAG_REMOTE = 1 << 7; + const FAULT_FLAG_INSTRUCTION = 1 << 8; + const FAULT_FLAG_INTERRUPTIBLE =1 << 9; + const FAULT_FLAG_UNSHARE = 1 << 10; + const FAULT_FLAG_ORIG_PTE_VALID = 1 << 11; + const FAULT_FLAG_VMA_LOCK = 1 << 12; } } @@ -36,9 +42,14 @@ bitflags! { /// 包含了页面错误处理的相关信息,例如出错的地址、VMA等 #[derive(Debug)] pub struct PageFaultMessage { + /// 产生缺页的VMA结构体 vma: Arc, + /// 缺页地址 address: VirtAddr, + /// 异常处理标志 flags: FaultFlags, + /// 缺页的文件页在文件中的偏移量 + file_pgoff: usize, } impl PageFaultMessage { @@ -47,6 +58,8 @@ impl PageFaultMessage { vma: vma.clone(), address, flags, + file_pgoff: ((address - vma.lock().region().start()) >> MMArch::PAGE_SHIFT) + + vma.lock().file_page_offset().unwrap(), } } @@ -58,8 +71,8 @@ impl PageFaultMessage { #[inline(always)] #[allow(dead_code)] - pub fn address(&self) -> VirtAddr { - self.address + pub fn address(&self) -> &VirtAddr { + &self.address } #[inline(always)] @@ -70,8 +83,8 @@ impl PageFaultMessage { #[inline(always)] #[allow(dead_code)] - pub fn flags(&self) -> FaultFlags { - self.flags + pub fn flags(&self) -> &FaultFlags { + &self.flags } } @@ -81,6 +94,7 @@ impl Clone for PageFaultMessage { vma: self.vma.clone(), address: self.address, flags: self.flags, + file_pgoff: self.file_pgoff, } } } @@ -189,7 +203,7 @@ impl PageFaultHandler { if !entry.write() { ret = Self::do_wp_page(pfm.clone(), mapper); } else { - entry.set_flags(PageFlags::from_data(MMArch::ENTRY_FLAG_DIRTY)); + entry.set_flags(EntryFlags::from_data(MMArch::ENTRY_FLAG_DIRTY)); } } } else if vma.is_anonymous() { @@ -248,14 +262,22 @@ impl PageFaultHandler { /// - 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() - ); + // 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 + + if !pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE) { + return Self::do_read_fault(pfm, mapper); + } else if !pfm.vma().lock().vm_flags().contains(VmFlags::VM_SHARED) { + return Self::do_cow_fault(pfm, mapper); + } else { + return Self::do_shared_fault(pfm, mapper); + } } /// 处理私有文件映射的写时复制 @@ -288,14 +310,20 @@ impl PageFaultHandler { /// - 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() - ); + // 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 + let ret = Self::do_fault_around(pfm.clone(), mapper); + if !ret.is_empty() { + return ret; + } + return Self::filemap_fault(pfm.clone(), mapper); } /// 处理对共享文件映射区写入引起的缺页 @@ -405,4 +433,144 @@ impl PageFaultHandler { VmFaultReason::VM_FAULT_OOM } } + + pub unsafe fn do_fault_around(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + if mapper.get_table(*pfm.address(), 0).is_none() { + mapper + .allocate_table(*pfm.address(), 0) + .expect("failed to allocate pte table"); + } + let vma = pfm.vma(); + let vma_guard = vma.lock(); + let vma_region = vma_guard.region(); + // 缺页在VMA中的偏移量 + let vm_pgoff = (*pfm.address() - vma_region.start()) >> MMArch::PAGE_SHIFT; + + // 缺页在PTE中的偏移量 + let pte_pgoff = + (pfm.address().data() >> MMArch::PAGE_SHIFT) & (1 << MMArch::PAGE_ENTRY_SHIFT); + + let vma_pages_count = (vma_region.end() - vma_region.start()) >> MMArch::PAGE_SHIFT; + + // 开始位置不能超出当前pte和vma头部 + let from_pte = pte_pgoff - min(vm_pgoff, pte_pgoff); + + let fault_around_page_number = 16; + + // pte结束位置不能超过: + // 1.最大预读上限(默认16) + // 2.最大pte(512) + // 3.vma结束位置(pte_pgoff + (vma_pages_count - vm_pgoff)计算出vma结束页号对当前pte开头的偏移) + let to_pte = min( + from_pte + fault_around_page_number, + min( + 1 << MMArch::PAGE_SHIFT, + pte_pgoff + (vma_pages_count - vm_pgoff), + ), + ); + + // 预先分配pte页表(如果不存在) + if mapper.get_table(*pfm.address(), 0).is_none() + && mapper.allocate_table(*pfm.address(), 0).is_none() + { + return VmFaultReason::VM_FAULT_OOM; + } + + // from_pte - pte_pgoff得出预读起始pte相对缺失页的偏移,加上pfm.file_pgoff(缺失页在文件中的偏移)得出起始页在文件中的偏移,结束pte同理 + Self::filemap_map_pages( + pfm.clone(), + mapper, + pfm.file_pgoff + (from_pte - pte_pgoff), + pfm.file_pgoff + (to_pte - pte_pgoff), + ); + + VmFaultReason::empty() + } + + pub unsafe fn filemap_map_pages( + pfm: PageFaultMessage, + mapper: &mut PageMapper, + start_pgoff: usize, + end_pgoff: usize, + ) -> VmFaultReason { + let vma = pfm.vma(); + let vma_guard = vma.lock(); + let file = vma_guard.vm_file().expect("no vm_file in vma"); + let page_cache = file.inode().page_cache().unwrap(); + + // 起始页地址 + let addr = vma_guard.region().start + + ((start_pgoff + - vma_guard + .file_page_offset() + .expect("file_page_offset is none")) + << MMArch::PAGE_SHIFT); + // let pages = page_cache.get_pages(start_pgoff, end_pgoff); + // let uptodate_pages = pages + // .iter() + // .filter(|page| page.flags().contains(PageFlags::PG_UPTODATE)); + for pgoff in start_pgoff..=end_pgoff { + if let Some(page) = page_cache.get_page(pgoff) { + if page.flags().contains(PageFlags::PG_UPTODATE) { + let phys = page.phys_frame().phys_address(); + let virt = phys_2_virt(phys.data()); + + let address = + VirtAddr::new(addr.data() + ((pgoff - start_pgoff) << MMArch::PAGE_SHIFT)); + mapper.map(address, vma_guard.flags()).unwrap().flush(); + let frame = virt as *mut u8; + let new_frame = + phys_2_virt(mapper.translate(address).unwrap().0.data()) as *mut u8; + new_frame.copy_from_nonoverlapping(frame, MMArch::PAGE_SIZE); + } + } + } + VmFaultReason::empty() + } + + pub unsafe fn filemap_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + let vma = pfm.vma(); + let vma_guard = vma.lock(); + let file = vma_guard.vm_file().expect("no vm_file in vma"); + let mut page_cache = file.inode().page_cache().unwrap(); + + if let Some(page) = page_cache.get_page(pfm.file_pgoff) { + // TODO 异步从磁盘中预读页面进PageCache + let address = vma_guard.region().start + + ((pfm.file_pgoff + - vma_guard + .file_page_offset() + .expect("file_page_offset is none")) + << MMArch::PAGE_SHIFT); + mapper.map(address, vma_guard.flags()).unwrap().flush(); + let frame = phys_2_virt(page.phys_frame().phys_address().data()) as *mut u8; + let new_frame = phys_2_virt(mapper.translate(address).unwrap().0.data()) as *mut u8; + new_frame.copy_from_nonoverlapping(frame, MMArch::PAGE_SIZE); + } else { + // TODO 同步预读 + let mut buf: Vec = vec![0; MMArch::PAGE_SIZE]; + file.pread( + pfm.file_pgoff * MMArch::PAGE_SIZE, + MMArch::PAGE_SIZE, + &mut buf[..], + ) + .unwrap(); + let allocator = mapper.allocator_mut(); + + // 分配一个物理页面作为加入PageCache的新页 + let new_cache_page = allocator.allocate_one().unwrap(); + (phys_2_virt(new_cache_page.data()) as *mut u8) + .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE); + page_cache.add_page( + pfm.file_pgoff, + Arc::new(Page::new(false, PhysPageFrame::new(new_cache_page))), + ); + + // 分配空白页并映射到缺页地址 + mapper.map(pfm.address, vma_guard.flags()).unwrap().flush(); + let new_frame = phys_2_virt(mapper.translate(pfm.address).unwrap().0.data()); + (new_frame as *mut u8).copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE); + } + VmFaultReason::VM_FAULT_COMPLETED + } } diff --git a/kernel/src/mm/kernel_mapper.rs b/kernel/src/mm/kernel_mapper.rs index 682fad60..487d1537 100644 --- a/kernel/src/mm/kernel_mapper.rs +++ b/kernel/src/mm/kernel_mapper.rs @@ -1,6 +1,6 @@ use system_error::SystemError; -use super::{page::PageFlags, PageTableKind, PhysAddr, VirtAddr}; +use super::{page::EntryFlags, PageTableKind, PhysAddr, VirtAddr}; use crate::{ arch::{ mm::{LockedFrameAllocator, PageMapper}, @@ -104,7 +104,7 @@ impl KernelMapper { mut vaddr: VirtAddr, mut paddr: PhysAddr, size: usize, - flags: PageFlags, + flags: EntryFlags, flush: bool, ) -> Result<(), SystemError> { if self.readonly { diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index 99e845d3..b15eda9a 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -12,7 +12,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use log::{debug, error, info, warn}; use system_error::SystemError; -use super::page::{PageFlags, PAGE_4K_SIZE}; +use super::page::{EntryFlags, PAGE_4K_SIZE}; use super::{PhysAddr, VirtAddr}; // 最大的伙伴块的幂 @@ -549,7 +549,7 @@ impl MmioBuddyMemPool { unsafe { let x: Option<( PhysAddr, - PageFlags, + EntryFlags, crate::mm::page::PageFlush, )> = kernel_mapper .as_mut() @@ -674,7 +674,7 @@ impl MMIOSpaceGuard { return Err(SystemError::EINVAL); } - let flags = PageFlags::mmio_flags(); + let flags = EntryFlags::mmio_flags(); let mut kernel_mapper = KernelMapper::lock(); let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true); diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 49e61fcd..bfd05193 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -610,7 +610,7 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { /// 创建页表项 /// - /// 这是一个低阶api,用于根据物理地址以及指定好的pageflags,创建页表项 + /// 这是一个低阶api,用于根据物理地址以及指定好的EntryFlags,创建页表项 /// /// ## 参数 /// diff --git a/kernel/src/mm/no_init.rs b/kernel/src/mm/no_init.rs index 855a8676..fdb8d4d6 100644 --- a/kernel/src/mm/no_init.rs +++ b/kernel/src/mm/no_init.rs @@ -19,7 +19,7 @@ use core::marker::PhantomData; use super::{ allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}, - page::PageFlags, + page::EntryFlags, PageTableKind, VirtAddr, }; @@ -141,7 +141,7 @@ impl FrameAllocator for PseudoAllocator { /// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准) #[inline(never)] pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) { - let flags: PageFlags = PageFlags::new().set_write(true); + let flags: EntryFlags = EntryFlags::new().set_write(true); pseudo_map_phys_with_flags(vaddr, paddr, count, flags); } @@ -150,7 +150,7 @@ pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrame /// with READ_ONLY and EXECUTE flags. #[inline(never)] pub unsafe fn pseudo_map_phys_ro(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) { - let flags: PageFlags = PageFlags::new().set_write(false).set_execute(true); + let flags: EntryFlags = EntryFlags::new().set_write(false).set_execute(true); pseudo_map_phys_with_flags(vaddr, paddr, count, flags); } @@ -160,7 +160,7 @@ pub unsafe fn pseudo_map_phys_with_flags( vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount, - flags: PageFlags, + flags: EntryFlags, ) { assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); assert!(paddr.check_aligned(MMArch::PAGE_SIZE)); diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index 11770811..b359c129 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -18,7 +18,7 @@ use crate::{ }; use super::{ - allocator::page_frame::{FrameAllocator, PageFrameCount}, + allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame}, syscall::ProtFlags, ucontext::LockedVMA, MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, @@ -86,6 +86,27 @@ impl PageManager { } } +bitflags! { + pub struct PageFlags: u64 { + const PG_LOCKED = 1 << 0; + const PG_WRITEBACK = 1 << 1; + const PG_REFERENCED = 1 << 2; + const PG_UPTODATE = 1 << 3; + const PG_DIRTY = 1 << 4; + const PG_LRU = 1 << 5; + const PG_HEAD = 1 << 6; + const PG_WAITERS = 1 << 7; + const PG_ACTIVE = 1 << 8; + const PG_WORKINGSET = 1 << 9; + const PG_ERROR = 1 << 10; + const PG_SLAB = 1 << 11; + const PG_RESERVED = 1 << 14; + const PG_PRIVATE = 1 << 15; + const PG_RECLAIM = 1 << 18; + const PG_SWAPBACKED = 1 << 19; + } +} + /// 物理页面信息 pub struct Page { /// 映射计数 @@ -98,10 +119,14 @@ pub struct Page { shm_id: Option, /// 映射到当前page的VMA anon_vma: HashSet>, + /// 标志 + flags: PageFlags, + /// 页所在的物理页帧号 + phys_frame: PhysPageFrame, } impl Page { - pub fn new(shared: bool) -> Self { + pub fn new(shared: bool, phys_frame: PhysPageFrame) -> Self { let dealloc_when_zero = !shared; Self { map_count: 0, @@ -109,6 +134,8 @@ impl Page { free_when_zero: dealloc_when_zero, shm_id: None, anon_vma: HashSet::new(), + flags: PageFlags::empty(), + phys_frame, } } @@ -154,6 +181,16 @@ impl Page { pub fn map_count(&self) -> usize { self.map_count } + + #[inline(always)] + pub fn flags(&self) -> &PageFlags { + &self.flags + } + + #[inline(always)] + pub fn phys_frame(&self) -> &PhysPageFrame { + &self.phys_frame + } } #[derive(Debug)] @@ -330,7 +367,7 @@ impl PageTable { } else { let phys = allocator.allocate_one()?; let mut anon_vma_guard = page_manager_lock_irqsave(); - anon_vma_guard.insert(phys, Page::new(false)); + anon_vma_guard.insert(phys, Page::new(false, PhysPageFrame::new(phys))); let old_phys = entry.address().unwrap(); let frame = MMArch::phys_2_virt(phys).unwrap().data() as *mut u8; frame.copy_from_nonoverlapping( @@ -372,7 +409,7 @@ impl Debug for PageEntry { impl PageEntry { #[inline(always)] - pub fn new(paddr: PhysAddr, flags: PageFlags) -> Self { + pub fn new(paddr: PhysAddr, flags: EntryFlags) -> Self { Self { data: MMArch::make_entry(paddr, flags.data()), phantom: PhantomData, @@ -420,12 +457,12 @@ impl PageEntry { } #[inline(always)] - pub fn flags(&self) -> PageFlags { - unsafe { PageFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) } + pub fn flags(&self) -> EntryFlags { + unsafe { EntryFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) } } #[inline(always)] - pub fn set_flags(&mut self, flags: PageFlags) { + pub fn set_flags(&mut self, flags: EntryFlags) { self.data = (self.data & !Arch::ENTRY_FLAGS_MASK) | flags.data(); } @@ -453,13 +490,19 @@ impl PageEntry { /// 页表项的标志位 #[derive(Copy, Clone, Hash)] -pub struct PageFlags { +pub struct EntryFlags { data: usize, phantom: PhantomData, } +impl Default for EntryFlags { + fn default() -> Self { + Self::new() + } +} + #[allow(dead_code)] -impl PageFlags { +impl EntryFlags { #[inline(always)] pub fn new() -> Self { let mut r = unsafe { @@ -480,14 +523,14 @@ impl PageFlags { return r; } - /// 根据ProtFlags生成PageFlags + /// 根据ProtFlags生成EntryFlags /// /// ## 参数 /// /// - prot_flags: 页的保护标志 /// - user: 用户空间是否可访问 - pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> PageFlags { - let flags: PageFlags = PageFlags::new() + pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> EntryFlags { + let flags: EntryFlags = EntryFlags::new() .set_user(user) .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC)) .set_write(prot_flags.contains(ProtFlags::PROT_WRITE)); @@ -757,9 +800,9 @@ impl PageFlags { } } -impl fmt::Debug for PageFlags { +impl fmt::Debug for EntryFlags { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PageFlags") + f.debug_struct("EntryFlags") .field("bits", &format_args!("{:#0x}", self.data)) .field("present", &self.present()) .field("has_write", &self.has_write()) @@ -855,7 +898,7 @@ impl PageMapper { pub unsafe fn map( &mut self, virt: VirtAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option> { compiler_fence(Ordering::SeqCst); let phys: PhysAddr = self.frame_allocator.allocate_one()?; @@ -869,7 +912,7 @@ impl PageMapper { let mut page_manager_guard: SpinLockGuard<'static, PageManager> = page_manager_lock_irqsave(); if !page_manager_guard.contains(&phys) { - page_manager_guard.insert(phys, Page::new(false)) + page_manager_guard.insert(phys, Page::new(false, PhysPageFrame::new(phys))) } return self.map_phys(virt, phys, flags); @@ -880,7 +923,7 @@ impl PageMapper { &mut self, virt: VirtAddr, phys: PhysAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option> { // 验证虚拟地址和物理地址是否对齐 if !(virt.check_aligned(Arch::PAGE_SIZE) && phys.check_aligned(Arch::PAGE_SIZE)) { @@ -920,8 +963,8 @@ impl PageMapper { // 清空这个页帧 MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE); // 设置页表项的flags - let flags: PageFlags = - PageFlags::new_page_table(virt.kind() == PageTableKind::User); + let flags: EntryFlags = + EntryFlags::new_page_table(virt.kind() == PageTableKind::User); // 把新分配的页表映射到当前页表 table.set_entry(i, PageEntry::new(frame, flags)); @@ -937,7 +980,7 @@ impl PageMapper { pub unsafe fn map_huge_page( &mut self, virt: VirtAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option> { // 验证虚拟地址是否对齐 if !(virt.check_aligned(Arch::PAGE_SIZE)) { @@ -1003,7 +1046,8 @@ impl PageMapper { MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE); // 设置页表项的flags - let flags: PageFlags = PageFlags::new_page_table(virt.kind() == PageTableKind::User); + let flags: EntryFlags = + EntryFlags::new_page_table(virt.kind() == PageTableKind::User); table.set_entry(i, PageEntry::new(frame, flags)); table.next_level_table(i) @@ -1105,7 +1149,7 @@ impl PageMapper { pub unsafe fn map_linearly( &mut self, phys: PhysAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option<(VirtAddr, PageFlush)> { let virt: VirtAddr = Arch::phys_2_virt(phys)?; return self.map_phys(virt, phys, flags).map(|flush| (virt, flush)); @@ -1125,7 +1169,7 @@ impl PageMapper { pub unsafe fn remap( &mut self, virt: VirtAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option> { return self .visit(virt, |p1, i| { @@ -1147,7 +1191,7 @@ impl PageMapper { /// ## 返回值 /// /// 如果查找成功,返回物理地址和页表项的flags,否则返回None - pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, PageFlags)> { + pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, EntryFlags)> { let entry: PageEntry = self.visit(virt, |p1, i| unsafe { p1.entry(i) })??; let paddr = entry.address().ok()?; let flags = entry.flags(); @@ -1186,7 +1230,7 @@ impl PageMapper { &mut self, virt: VirtAddr, unmap_parents: bool, - ) -> Option<(PhysAddr, PageFlags, PageFlush)> { + ) -> Option<(PhysAddr, EntryFlags, PageFlush)> { if !virt.check_aligned(Arch::PAGE_SIZE) { error!("Try to unmap unaligned page: virt={:?}", virt); return None; @@ -1234,7 +1278,7 @@ unsafe fn unmap_phys_inner( table: &PageTable, unmap_parents: bool, allocator: &mut impl FrameAllocator, -) -> Option<(PhysAddr, PageFlags)> { +) -> Option<(PhysAddr, EntryFlags)> { // 获取页表项的索引 let i = table.index_of(vaddr)?; diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index f5d484bc..791cd7f1 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -20,6 +20,7 @@ use system_error::SystemError; use crate::{ arch::{mm::PageMapper, CurrentIrqArch, MMArch}, exception::InterruptArch, + filesystem::vfs::file::File, libs::{ align::page_align_up, rwlock::RwLock, @@ -34,7 +35,7 @@ use super::{ allocator::page_frame::{ deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter, }, - page::{Flusher, InactiveFlusher, PageFlags, PageFlushAll}, + page::{EntryFlags, Flusher, InactiveFlusher, PageFlushAll}, syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags}, MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags, }; @@ -333,7 +334,7 @@ impl InnerAddressSpace { F: FnOnce( VirtPageFrame, PageFrameCount, - PageFlags, + EntryFlags, &mut PageMapper, &mut dyn Flusher, ) -> Result, SystemError>, @@ -380,7 +381,7 @@ impl InnerAddressSpace { self.mappings.insert_vma(map_func( page, page_count, - PageFlags::from_prot_flags(prot_flags, true), + EntryFlags::from_prot_flags(prot_flags, true), &mut self.user_mapper.utable, flusher, )?); @@ -556,7 +557,7 @@ impl InnerAddressSpace { return Err(SystemError::EACCES); } - let new_flags: PageFlags = r_guard + let new_flags: EntryFlags = r_guard .flags() .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC)) .set_write(prot_flags.contains(ProtFlags::PROT_WRITE)); @@ -1022,7 +1023,7 @@ impl LockedVMA { /// pub fn remap( &self, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result<(), SystemError> { @@ -1233,13 +1234,17 @@ pub struct VMA { /// 虚拟内存区域标志 vm_flags: VmFlags, /// VMA内的页帧的标志 - flags: PageFlags, + flags: EntryFlags, /// VMA内的页帧是否已经映射到页表 mapped: bool, /// VMA所属的用户地址空间 user_address_space: Option>, self_ref: Weak, + vm_file: Option>, + /// VMA映射的文件部分相对于整个文件的偏移页数 + file_pgoff: Option, + provider: Provider, } @@ -1262,7 +1267,7 @@ impl VMA { pub fn new( region: VirtRegion, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, mapped: bool, ) -> Self { VMA { @@ -1273,6 +1278,8 @@ impl VMA { user_address_space: None, self_ref: Weak::default(), provider: Provider::Allocated, + file_pgoff: None, + vm_file: None, } } @@ -1284,6 +1291,10 @@ impl VMA { return &self.vm_flags; } + pub fn vm_file(&self) -> Option> { + return self.vm_file.clone(); + } + pub fn set_vm_flags(&mut self, vm_flags: VmFlags) { self.vm_flags = vm_flags; } @@ -1310,6 +1321,8 @@ impl VMA { user_address_space: self.user_address_space.clone(), self_ref: self.self_ref.clone(), provider: Provider::Allocated, + file_pgoff: self.file_pgoff, + vm_file: self.vm_file.clone(), }; } @@ -1322,14 +1335,21 @@ impl VMA { user_address_space: None, self_ref: Weak::default(), provider: Provider::Allocated, + file_pgoff: self.file_pgoff, + vm_file: self.vm_file.clone(), }; } #[inline(always)] - pub fn flags(&self) -> PageFlags { + pub fn flags(&self) -> EntryFlags { return self.flags; } + #[inline(always)] + pub fn file_page_offset(&self) -> Option { + return self.file_pgoff; + } + pub fn pages(&self) -> VirtPageFrameIter { return VirtPageFrameIter::new( VirtPageFrame::new(self.region.start()), @@ -1339,7 +1359,7 @@ impl VMA { pub fn remap( &mut self, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result<(), SystemError> { @@ -1392,7 +1412,7 @@ impl VMA { destination: VirtPageFrame, count: PageFrameCount, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result, SystemError> { @@ -1414,15 +1434,12 @@ impl VMA { cur_dest = cur_dest.next(); } - let r: Arc = LockedVMA::new(VMA { - region: VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE), + let r: Arc = LockedVMA::new(VMA::new( + VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE), vm_flags, flags, - mapped: true, - user_address_space: None, - self_ref: Weak::default(), - provider: Provider::Allocated, - }); + true, + )); // 将VMA加入到anon_vma中 let mut page_manager_guard = page_manager_lock_irqsave(); @@ -1450,7 +1467,7 @@ impl VMA { destination: VirtPageFrame, page_count: PageFrameCount, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result, SystemError> { diff --git a/kernel/src/virt/kvm/host_mem.rs b/kernel/src/virt/kvm/host_mem.rs index f34a1e83..95291b14 100644 --- a/kernel/src/virt/kvm/host_mem.rs +++ b/kernel/src/virt/kvm/host_mem.rs @@ -2,7 +2,7 @@ use log::debug; use system_error::SystemError; use super::{vcpu::Vcpu, vm}; -use crate::mm::{kernel_mapper::KernelMapper, page::PageFlags, VirtAddr}; +use crate::mm::{kernel_mapper::KernelMapper, page::EntryFlags, VirtAddr}; /* * Address types: @@ -152,7 +152,7 @@ fn hva_to_pfn(addr: u64, _atomic: bool, _writable: &mut bool) -> Result> PAGE_SHIFT); } unsafe { - mapper.map(hva, PageFlags::mmio_flags()); + mapper.map(hva, EntryFlags::mmio_flags()); } let (hpa, _) = mapper.translate(hva).unwrap(); return Ok(hpa.data() as u64 >> PAGE_SHIFT);