From cf7f801e1d50ee5b04cb728e4251a57f4183bfbc Mon Sep 17 00:00:00 2001 From: MemoryShore <1353318529@qq.com> Date: Thu, 5 Sep 2024 00:35:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(mm):=20=E7=AE=80=E5=8D=95=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0fat=E6=96=87=E4=BB=B6=E7=B3=BB=E7=BB=9F=E7=9A=84?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=98=A0=E5=B0=84=20(#840)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加文件映射相关接口,目前已简单实现fat文件系统的私有映射和共享映射 - 添加msync系统调用(由于当前未实现脏页自动回写,需要手动调用msync进行同步) - 简单实现PageCache(暂时使用HashMap进行文件页号与页的映射) - 添加新的PageFlags标志结构,原PageFlags改名为EntryFlags - 参考linux使用protection_map映射表进行页面标志的获取 - 添加页面回收机制 - 添加页面回收内核线程 - 缺页中断使用的锁修改为irq_save; 添加脏页回写机制 - 修复do_cow_page死锁问题 - 访问非法地址时发送信号终止进程 - 修复重复插入反向vma表的错误 - 添加test_filemap文件映射测试程序 --- kernel/Cargo.toml | 3 +- kernel/src/arch/riscv64/mm/mod.rs | 74 ++- kernel/src/arch/x86_64/kvm/vmx/ept.rs | 4 +- kernel/src/arch/x86_64/kvm/vmx/mmu.rs | 4 +- kernel/src/arch/x86_64/mm/fault.rs | 50 ++- kernel/src/arch/x86_64/mm/mod.rs | 99 +++- kernel/src/arch/x86_64/mm/pkru.rs | 4 +- kernel/src/driver/net/dma.rs | 4 +- kernel/src/driver/video/mod.rs | 4 +- kernel/src/driver/virtio/virtio_impl.rs | 4 +- kernel/src/filesystem/fat/fs.rs | 30 ++ kernel/src/filesystem/vfs/file.rs | 64 ++- kernel/src/filesystem/vfs/mod.rs | 35 +- kernel/src/filesystem/vfs/mount.rs | 24 +- kernel/src/ipc/shm.rs | 17 +- kernel/src/ipc/syscall.rs | 21 +- kernel/src/libs/mod.rs | 1 + kernel/src/libs/name.rs | 13 + kernel/src/mm/allocator/page_frame.rs | 5 +- kernel/src/mm/c_adapter.rs | 4 +- kernel/src/mm/fault.rs | 549 ++++++++++++++++++----- kernel/src/mm/init.rs | 8 +- kernel/src/mm/kernel_mapper.rs | 4 +- kernel/src/mm/madvise.rs | 2 +- kernel/src/mm/mmio_buddy.rs | 6 +- kernel/src/mm/mod.rs | 68 ++- kernel/src/mm/no_init.rs | 8 +- kernel/src/mm/page.rs | 404 +++++++++++++++-- kernel/src/mm/syscall.rs | 163 ++++++- kernel/src/mm/ucontext.rs | 351 +++++++++++---- kernel/src/sched/mod.rs | 1 + kernel/src/syscall/mod.rs | 6 + kernel/src/virt/kvm/host_mem.rs | 4 +- user/apps/test_filemap/.gitignore | 1 + user/apps/test_filemap/Makefile | 20 + user/apps/test_filemap/main.c | 61 +++ user/dadk/config/test_filemap-0.1.0.dadk | 23 + 37 files changed, 1791 insertions(+), 352 deletions(-) create mode 100644 kernel/src/libs/name.rs create mode 100644 user/apps/test_filemap/.gitignore create mode 100644 user/apps/test_filemap/Makefile create mode 100644 user/apps/test_filemap/main.c create mode 100644 user/dadk/config/test_filemap-0.1.0.dadk diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index f7bf6223..36a01f65 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -57,7 +57,8 @@ wait_queue_macros = { path = "crates/wait_queue_macros" } paste = "=1.0.14" slabmalloc = { path = "crates/rust-slabmalloc" } log = "0.4.21" - +xarray = "0.1.0" +lru = "0.12.3" # target为x86_64时,使用下面的依赖 [target.'cfg(target_arch = "x86_64")'.dependencies] diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index 76bfbed0..1970d3d6 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -12,9 +12,9 @@ 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, + MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags, }, smp::cpu::ProcessorId, }; @@ -256,8 +256,74 @@ impl MemoryManagementArch for RiscV64MMArch { ) -> bool { true } + + const PAGE_NONE: usize = Self::ENTRY_FLAG_GLOBAL | Self::ENTRY_FLAG_READONLY; + + const PAGE_READ: usize = PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY; + + const PAGE_WRITE: usize = + PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY | Self::ENTRY_FLAG_WRITEABLE; + + const PAGE_EXEC: usize = PAGE_ENTRY_BASE | Self::ENTRY_FLAG_EXEC; + + const PAGE_READ_EXEC: usize = + PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY | Self::ENTRY_FLAG_EXEC; + + const PAGE_WRITE_EXEC: usize = PAGE_ENTRY_BASE + | Self::ENTRY_FLAG_READONLY + | Self::ENTRY_FLAG_EXEC + | Self::ENTRY_FLAG_WRITEABLE; + + const PAGE_COPY: usize = Self::PAGE_READ; + const PAGE_COPY_EXEC: usize = Self::PAGE_READ_EXEC; + const PAGE_SHARED: usize = Self::PAGE_WRITE; + const PAGE_SHARED_EXEC: usize = Self::PAGE_WRITE_EXEC; + + const PAGE_COPY_NOEXEC: usize = 0; + const PAGE_READONLY: usize = 0; + const PAGE_READONLY_EXEC: usize = 0; + + const PROTECTION_MAP: [EntryFlags; 16] = protection_map(); } +const fn protection_map() -> [EntryFlags; 16] { + let mut map = [0; 16]; + map[VmFlags::VM_NONE.bits()] = MMArch::PAGE_NONE; + map[VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY; + map[VmFlags::VM_WRITE.bits()] = MMArch::PAGE_COPY; + map[VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_COPY; + map[VmFlags::VM_EXEC.bits()] = MMArch::PAGE_READONLY_EXEC; + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY_EXEC; + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = MMArch::PAGE_COPY_EXEC; + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + MMArch::PAGE_COPY_EXEC; + map[VmFlags::VM_SHARED.bits()] = MMArch::PAGE_NONE; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits()] = MMArch::PAGE_SHARED; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + MMArch::PAGE_SHARED; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits()] = MMArch::PAGE_READONLY_EXEC; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = + MMArch::PAGE_READONLY_EXEC; + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = + MMArch::PAGE_SHARED_EXEC; + map[VmFlags::VM_SHARED.bits() + | VmFlags::VM_EXEC.bits() + | VmFlags::VM_WRITE.bits() + | VmFlags::VM_READ.bits()] = MMArch::PAGE_SHARED_EXEC; + let mut ret = [unsafe { EntryFlags::from_data(0) }; 16]; + let mut index = 0; + while index < 16 { + ret[index] = unsafe { EntryFlags::from_data(map[index]) }; + index += 1; + } + ret +} + +const PAGE_ENTRY_BASE: usize = RiscV64MMArch::ENTRY_FLAG_PRESENT + | RiscV64MMArch::ENTRY_FLAG_ACCESSED + | RiscV64MMArch::ENTRY_FLAG_USER; + impl VirtAddr { /// 判断虚拟地址是否合法 #[inline(always)] @@ -270,8 +336,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/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index 00eb4cef..e38df1f2 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -10,15 +10,18 @@ use x86::{bits64::rflags::RFlags, controlregs::Cr4}; use crate::{ arch::{ interrupt::{trap::X86PfErrorCode, TrapFrame}, + ipc::signal::{SigCode, Signal}, mm::{MemoryManagementArch, X86_64MMArch}, CurrentIrqArch, MMArch, }, exception::InterruptArch, + ipc::signal_types::{SigInfo, SigType}, mm::{ fault::{FaultFlags, PageFaultHandler, PageFaultMessage}, ucontext::{AddressSpace, LockedVMA}, VirtAddr, VmFaultReason, VmFlags, }, + process::ProcessManager, }; use super::LockedFrameAllocator; @@ -28,7 +31,7 @@ pub type PageMapper = impl X86_64MMArch { pub fn vma_access_error(vma: Arc, error_code: X86PfErrorCode) -> bool { - let vm_flags = *vma.lock().vm_flags(); + let vm_flags = *vma.lock_irqsave().vm_flags(); let foreign = false; if error_code.contains(X86PfErrorCode::X86_PF_PK) { return true; @@ -223,20 +226,30 @@ impl X86_64MMArch { } let current_address_space: Arc = AddressSpace::current().unwrap(); - let mut space_guard = current_address_space.write(); + let mut space_guard = current_address_space.write_irqsave(); let mut fault; loop { let vma = space_guard.mappings.find_nearest(address); // let vma = space_guard.mappings.contains(address); - let vma = vma.unwrap_or_else(|| { - panic!( - "can not find nearest vma, error_code: {:#b}, address: {:#x}", - error_code, - address.data(), - ) - }); - let guard = vma.lock(); + let vma = match vma { + Some(vma) => vma, + None => { + log::error!( + "can not find nearest vma, error_code: {:#b}, address: {:#x}", + error_code, + address.data(), + ); + let pid = ProcessManager::current_pid(); + let mut info = + SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); + Signal::SIGSEGV + .send_signal_info(Some(&mut info), pid) + .expect("failed to send SIGSEGV to process"); + return; + } + }; + let guard = vma.lock_irqsave(); let region = *guard.region(); let vm_flags = *guard.vm_flags(); drop(guard); @@ -253,11 +266,18 @@ impl X86_64MMArch { ) }); } else { - panic!( + log::error!( "No mapped vma, error_code: {:#b}, address: {:#x}", error_code, address.data(), - ) + ); + let pid = ProcessManager::current_pid(); + let mut info = + SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); + Signal::SIGSEGV + .send_signal_info(Some(&mut info), pid) + .expect("failed to send SIGSEGV to process"); + return; } } @@ -269,11 +289,9 @@ impl X86_64MMArch { ); } let mapper = &mut space_guard.user_mapper.utable; + let message = PageFaultMessage::new(vma.clone(), address, flags, mapper); - fault = PageFaultHandler::handle_mm_fault( - PageFaultMessage::new(vma.clone(), address, flags), - mapper, - ); + fault = PageFaultHandler::handle_mm_fault(message); 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 6eaf2dd5..f5c5badc 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -28,8 +28,8 @@ use crate::{ }; use crate::mm::kernel_mapper::KernelMapper; -use crate::mm::page::{PageEntry, PageFlags, PAGE_1G_SHIFT}; -use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr}; +use crate::mm::page::{EntryFlags, PageEntry, PAGE_1G_SHIFT}; +use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags}; use system_error::SystemError; @@ -326,6 +326,93 @@ impl MemoryManagementArch for X86_64MMArch { } pkru::pkru_allows_pkey(pkru::vma_pkey(vma), write) } + + const PROTECTION_MAP: [EntryFlags; 16] = protection_map(); + + const PAGE_NONE: usize = + Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_ACCESSED | Self::ENTRY_FLAG_GLOBAL; + + const PAGE_SHARED: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_READWRITE + | Self::ENTRY_FLAG_USER + | Self::ENTRY_FLAG_ACCESSED + | Self::ENTRY_FLAG_NO_EXEC; + + const PAGE_SHARED_EXEC: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_READWRITE + | Self::ENTRY_FLAG_USER + | Self::ENTRY_FLAG_ACCESSED; + + const PAGE_COPY_NOEXEC: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_USER + | Self::ENTRY_FLAG_ACCESSED + | Self::ENTRY_FLAG_NO_EXEC; + + const PAGE_COPY_EXEC: usize = + Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_USER | Self::ENTRY_FLAG_ACCESSED; + + const PAGE_COPY: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_USER + | Self::ENTRY_FLAG_ACCESSED + | Self::ENTRY_FLAG_NO_EXEC; + + const PAGE_READONLY: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_USER + | Self::ENTRY_FLAG_ACCESSED + | Self::ENTRY_FLAG_NO_EXEC; + + const PAGE_READONLY_EXEC: usize = + Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_USER | Self::ENTRY_FLAG_ACCESSED; + + const PAGE_READ: usize = 0; + const PAGE_READ_EXEC: usize = 0; + const PAGE_WRITE: usize = 0; + const PAGE_WRITE_EXEC: usize = 0; + const PAGE_EXEC: usize = 0; +} + +/// 获取保护标志的映射表 +/// +/// +/// ## 返回值 +/// - `[usize; 16]`: 长度为16的映射表 +const fn protection_map() -> [EntryFlags; 16] { + let mut map = [unsafe { EntryFlags::from_data(0) }; 16]; + unsafe { + map[VmFlags::VM_NONE.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE); + map[VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY); + map[VmFlags::VM_WRITE.bits()] = EntryFlags::from_data(MMArch::PAGE_COPY); + map[VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY); + map[VmFlags::VM_EXEC.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY_EXEC); + map[VmFlags::VM_SHARED.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC); + map[VmFlags::VM_SHARED.bits() + | VmFlags::VM_EXEC.bits() + | VmFlags::VM_WRITE.bits() + | VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC); + } + // if X86_64MMArch::is_xd_reserved() { + // map.iter_mut().for_each(|x| *x &= !Self::ENTRY_FLAG_NO_EXEC) + // } + map } impl X86_64MMArch { @@ -650,17 +737,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/arch/x86_64/mm/pkru.rs b/kernel/src/arch/x86_64/mm/pkru.rs index f467f8d1..c40f5f0f 100644 --- a/kernel/src/arch/x86_64/mm/pkru.rs +++ b/kernel/src/arch/x86_64/mm/pkru.rs @@ -16,8 +16,8 @@ const PKEY_MASK: usize = 1 << 32 | 1 << 33 | 1 << 34 | 1 << 35; /// ## 返回值 /// - `u16`: vma的protection_key pub fn vma_pkey(vma: Arc) -> u16 { - let guard = vma.lock(); - ((guard.vm_flags().bits() & PKEY_MASK as u64) >> VM_PKEY_SHIFT) as u16 + let guard = vma.lock_irqsave(); + ((guard.vm_flags().bits() & PKEY_MASK) >> VM_PKEY_SHIFT) as u16 } // TODO pkru实现参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/pkru.h 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/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index 64967b20..49b68222 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -14,9 +14,12 @@ use alloc::{ use crate::driver::base::block::gendisk::GenDisk; use crate::driver::base::device::device_number::DeviceNumber; +use crate::filesystem::vfs::file::PageCache; use crate::filesystem::vfs::utils::DName; use crate::filesystem::vfs::{Magic, SpecialNodeData, SuperBlock}; use crate::ipc::pipe::LockedPipeInode; +use crate::mm::fault::{PageFaultHandler, PageFaultMessage}; +use crate::mm::VmFaultReason; use crate::{ driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom}, filesystem::vfs::{ @@ -119,6 +122,9 @@ pub struct FATInode { /// 目录名 dname: DName, + + /// 页缓存 + page_cache: Option>, } impl FATInode { @@ -216,8 +222,14 @@ impl LockedFATInode { }, special_node: None, dname, + page_cache: None, }))); + if !inode.0.lock().inode_type.is_dir() { + let page_cache = PageCache::new(Some(Arc::downgrade(&inode) as Weak)); + inode.0.lock().page_cache = Some(page_cache); + } + inode.0.lock().self_ref = Arc::downgrade(&inode); inode.0.lock().update_metadata(); @@ -272,6 +284,19 @@ impl FileSystem for FATFileSystem { FAT_MAX_NAMELEN, ) } + + unsafe fn fault(&self, pfm: &mut PageFaultMessage) -> VmFaultReason { + PageFaultHandler::filemap_fault(pfm) + } + + unsafe fn map_pages( + &self, + pfm: &mut PageFaultMessage, + start_pgoff: usize, + end_pgoff: usize, + ) -> VmFaultReason { + PageFaultHandler::filemap_map_pages(pfm, start_pgoff, end_pgoff) + } } impl FATFileSystem { @@ -348,6 +373,7 @@ impl FATFileSystem { }, special_node: None, dname: DName::default(), + page_cache: None, }))); let result: Arc = Arc::new(FATFileSystem { @@ -1824,6 +1850,10 @@ impl IndexNode for LockedFATInode { .map(|item| item as Arc) .ok_or(SystemError::EINVAL) } + + fn page_cache(&self) -> Option> { + self.0.lock().page_cache.clone() + } } impl Default for FATFsInfo { diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index e3aff021..69994b73 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -7,10 +7,12 @@ use alloc::{ }; use log::error; use system_error::SystemError; +use xarray::XArray; use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; use crate::filesystem::eventfd::EventFdInode; use crate::{ + arch::MMArch, driver::{ base::{block::SeekFrom, device::DevicePrivateData}, tty::tty_device::TtyFilePrivateData, @@ -18,6 +20,7 @@ use crate::{ filesystem::procfs::ProcfsFilePrivateData, ipc::pipe::{LockedPipeInode, PipeFsPrivateData}, libs::{rwlock::RwLock, spinlock::SpinLock}, + mm::{page::Page, MemoryManagementArch}, net::{ event_poll::{EPollItem, EPollPrivateData, EventPoll}, socket::SocketInode, @@ -118,6 +121,66 @@ impl FileMode { return self.bits() & FileMode::O_ACCMODE.bits(); } } + +/// 页面缓存 +pub struct PageCache { + xarray: SpinLock>>, + inode: Option>, +} + +impl core::fmt::Debug for PageCache { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PageCache") + .field( + "xarray", + &self + .xarray + .lock() + .range(0..((MMArch::PAGE_ADDRESS_SIZE >> MMArch::PAGE_SHIFT) as u64)) + .map(|(_, r)| (*r).clone()) + .collect::>>(), + ) + .finish() + } +} + +impl PageCache { + pub fn new(inode: Option>) -> Arc { + let page_cache = Self { + xarray: SpinLock::new(XArray::new()), + inode, + }; + Arc::new(page_cache) + } + + pub fn inode(&self) -> Option> { + self.inode.clone() + } + + pub fn add_page(&self, offset: usize, page: &Arc) { + let mut guard = self.xarray.lock(); + let mut cursor = guard.cursor_mut(offset as u64); + cursor.store(page.clone()); + } + + pub fn get_page(&self, offset: usize) -> Option> { + let mut guard = self.xarray.lock(); + let mut cursor = guard.cursor_mut(offset as u64); + let page = cursor.load().map(|r| (*r).clone()); + page + } + + pub fn remove_page(&self, offset: usize) { + let mut guard = self.xarray.lock(); + let mut cursor = guard.cursor_mut(offset as u64); + cursor.remove(); + } + + pub fn set_inode(&mut self, inode: Weak) { + self.inode = Some(inode) + } +} + /// @brief 抽象文件结构体 #[derive(Debug)] pub struct File { @@ -683,7 +746,6 @@ impl FileDescriptorVec { // 把文件描述符数组对应位置设置为空 let file = self.fds[fd as usize].take().unwrap(); - assert!(Arc::strong_count(&file) == 1); return Ok(file); } diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index c8b4a3ae..00ce6ba5 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -20,10 +20,16 @@ use crate::{ casting::DowncastArc, spinlock::{SpinLock, SpinLockGuard}, }, + mm::{fault::PageFaultMessage, VmFaultReason}, 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容许的最大的路径名称长度 @@ -556,6 +562,14 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { fn parent(&self) -> Result, SystemError> { return self.find(".."); } + + fn page_cache(&self) -> Option> { + log::error!( + "function page_cache() has not yet been implemented for inode:{}", + crate::libs::name::get_type_name(&self) + ); + None + } } impl DowncastArc for dyn IndexNode { @@ -805,6 +819,25 @@ pub trait FileSystem: Any + Sync + Send + Debug { fn name(&self) -> &str; fn super_block(&self) -> SuperBlock; + + unsafe fn fault(&self, _pfm: &mut PageFaultMessage) -> VmFaultReason { + panic!( + "fault() has not yet been implemented for filesystem: {}", + crate::libs::name::get_type_name(&self) + ) + } + + unsafe fn map_pages( + &self, + _pfm: &mut PageFaultMessage, + _start_pgoff: usize, + _end_pgoff: usize, + ) -> VmFaultReason { + panic!( + "map_pages() has not yet been implemented for filesystem: {}", + crate::libs::name::get_type_name(&self) + ) + } } impl DowncastArc for dyn FileSystem { diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index 27084a0f..cc479883 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -19,11 +19,14 @@ use crate::{ rwlock::RwLock, spinlock::{SpinLock, SpinLockGuard}, }, + mm::{fault::PageFaultMessage, VmFaultReason}, }; use super::{ - file::FileMode, syscall::ModeType, utils::DName, FilePrivateData, FileSystem, FileType, - IndexNode, InodeId, Magic, SuperBlock, + file::{FileMode, PageCache}, + syscall::ModeType, + utils::DName, + FilePrivateData, FileSystem, FileType, IndexNode, InodeId, Magic, SuperBlock, }; const MOUNTFS_BLOCK_SIZE: u64 = 512; @@ -501,6 +504,10 @@ impl IndexNode for MountFSInode { fn parent(&self) -> Result, SystemError> { return self.do_parent().map(|inode| inode as Arc); } + + fn page_cache(&self) -> Option> { + self.inner_inode.page_cache() + } } impl FileSystem for MountFS { @@ -528,6 +535,19 @@ impl FileSystem for MountFS { fn super_block(&self) -> SuperBlock { SuperBlock::new(Magic::MOUNT_MAGIC, MOUNTFS_BLOCK_SIZE, MOUNTFS_MAX_NAMELEN) } + + unsafe fn fault(&self, pfm: &mut PageFaultMessage) -> VmFaultReason { + self.inner_filesystem.fault(pfm) + } + + unsafe fn map_pages( + &self, + pfm: &mut PageFaultMessage, + start_pgoff: usize, + end_pgoff: usize, + ) -> VmFaultReason { + self.inner_filesystem.map_pages(pfm, start_pgoff, end_pgoff) + } } /// MountList diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 13c9f1b0..99cce2e4 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -14,7 +14,7 @@ use crate::{ syscall::user_access::{UserBufferReader, UserBufferWriter}, time::PosixTimeSpec, }; -use alloc::vec::Vec; +use alloc::{sync::Arc, vec::Vec}; use core::sync::atomic::{compiler_fence, Ordering}; use hashbrown::{HashMap, HashSet}; use ida::IdAllocator; @@ -165,10 +165,10 @@ 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); - page.set_shm_id(shm_id); + let page = Arc::new(Page::new(true, cur_phys.phys_address())); + page.write_irqsave().set_shm_id(shm_id); let paddr = cur_phys.phys_address(); - page_manager_guard.insert(paddr, page); + page_manager_guard.insert(paddr, &page); cur_phys = cur_phys.next(); } @@ -324,8 +324,8 @@ impl ShmManager { if map_count > 0 { // 设置共享内存物理页当映射计数等于0时可被回收 for _ in 0..count.data() { - let page = page_manager_guard.get_mut(&cur_phys.phys_address()); - page.set_dealloc_when_zero(true); + let page = page_manager_guard.get_unwrap(&cur_phys.phys_address()); + page.write_irqsave().set_dealloc_when_zero(true); cur_phys = cur_phys.next(); } @@ -436,7 +436,7 @@ impl KernelShm { /// 共享内存段的映射计数(有多少个不同的VMA映射) pub fn map_count(&self) -> usize { - let page_manager_guard = page_manager_lock_irqsave(); + let mut page_manager_guard = page_manager_lock_irqsave(); let mut id_set: HashSet = HashSet::new(); let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr); let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap(); @@ -444,7 +444,8 @@ impl KernelShm { for _ in 0..page_count.data() { let page = page_manager_guard.get(&cur_phys.phys_address()).unwrap(); id_set.extend( - page.anon_vma() + page.read_irqsave() + .anon_vma() .iter() .map(|vma| vma.id()) .collect::>(), diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs index 37a9cc9c..2d0b9b6b 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(); // 将共享内存映射到对应虚拟区域 @@ -351,14 +351,14 @@ impl Syscall { .mappings .contains(vaddr) .ok_or(SystemError::EINVAL)?; - if vma.lock().region().start() != vaddr { + if vma.lock_irqsave().region().start() != vaddr { return Err(SystemError::EINVAL); } // 验证用户虚拟内存区域是否有效 let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?; - // 必须在取消映射前获取到PageFlags + // 必须在取消映射前获取到EntryFlags let page_flags = address_write_guard .user_mapper .utable @@ -386,7 +386,8 @@ impl Syscall { // 将vma加入到对应Page的anon_vma page_manager_guard - .get_mut(&phys.phys_address()) + .get_unwrap(&phys.phys_address()) + .write_irqsave() .insert_vma(vma.clone()); phys = phys.next(); @@ -394,7 +395,7 @@ impl Syscall { } // 更新vma的映射状态 - vma.lock().set_mapped(true); + vma.lock_irqsave().set_mapped(true); vaddr.data() } @@ -427,7 +428,7 @@ impl Syscall { .ok_or(SystemError::EINVAL)?; // 判断vaddr是否为起始地址 - if vma.lock().region().start() != vaddr { + if vma.lock_irqsave().region().start() != vaddr { return Err(SystemError::EINVAL); } @@ -440,9 +441,9 @@ impl Syscall { .0; // 如果物理页的shm_id为None,代表不是共享页 - let page_manager_guard = page_manager_lock_irqsave(); + let mut page_manager_guard = page_manager_lock_irqsave(); let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?; - let shm_id = page.shm_id().ok_or(SystemError::EINVAL)?; + let shm_id = page.read_irqsave().shm_id().ok_or(SystemError::EINVAL)?; drop(page_manager_guard); // 获取对应共享页管理信息 diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index c864d605..42788bdd 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -26,3 +26,4 @@ pub mod rand; pub mod wait_queue; pub mod font; +pub mod name; diff --git a/kernel/src/libs/name.rs b/kernel/src/libs/name.rs new file mode 100644 index 00000000..bca4467c --- /dev/null +++ b/kernel/src/libs/name.rs @@ -0,0 +1,13 @@ +use core::any::type_name; + +use alloc::string::{String, ToString}; + +#[allow(dead_code)] +pub fn get_full_type_name(_: &T) -> String { + type_name::().to_string() +} + +pub fn get_type_name(_: &T) -> String { + let full_name = type_name::(); + full_name[(full_name.rfind("::").unwrap_or(0) + 2)..].to_string() +} diff --git a/kernel/src/mm/allocator/page_frame.rs b/kernel/src/mm/allocator/page_frame.rs index 75a79529..180a2ac2 100644 --- a/kernel/src/mm/allocator/page_frame.rs +++ b/kernel/src/mm/allocator/page_frame.rs @@ -371,8 +371,9 @@ pub unsafe fn deallocate_page_frames( if let Some(page) = page { // 如果page是共享页,将其共享页信息从SHM_MANAGER中删去 - if page.shared() { - shm_manager_lock().free_id(&page.shm_id().unwrap()); + let page_guard = page.read_irqsave(); + if page_guard.shared() { + shm_manager_lock().free_id(&page_guard.shm_id().unwrap()); } } 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..457b911f 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -1,11 +1,17 @@ -use core::{alloc::Layout, intrinsics::unlikely, panic}; +use core::{ + alloc::Layout, + cmp::{max, min}, + intrinsics::unlikely, + panic, +}; use alloc::sync::Arc; use crate::{ arch::{mm::PageMapper, MMArch}, + libs::align::align_down, mm::{ - page::{page_manager_lock_irqsave, PageFlags}, + page::{page_manager_lock_irqsave, EntryFlags}, ucontext::LockedVMA, VirtAddr, VmFaultReason, VmFlags, }, @@ -14,39 +20,68 @@ use crate::{ use crate::mm::MemoryManagementArch; +use super::{ + allocator::page_frame::FrameAllocator, + page::{page_reclaimer_lock_irqsave, Page, PageFlags}, +}; + 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; } } /// # 缺页异常信息结构体 /// 包含了页面错误处理的相关信息,例如出错的地址、VMA等 #[derive(Debug)] -pub struct PageFaultMessage { +pub struct PageFaultMessage<'a> { + /// 产生缺页的VMA结构体 vma: Arc, + /// 缺页地址 address: VirtAddr, + /// 异常处理标志 flags: FaultFlags, + /// 页表映射器 + mapper: &'a mut PageMapper, + /// 缺页的文件页在文件中的偏移量 + file_pgoff: Option, + /// 缺页对应PageCache中的文件页 + page: Option>, + /// 写时拷贝需要的页面 + cow_page: Option>, } -impl PageFaultMessage { - pub fn new(vma: Arc, address: VirtAddr, flags: FaultFlags) -> Self { +impl<'a> PageFaultMessage<'a> { + pub fn new( + vma: Arc, + address: VirtAddr, + flags: FaultFlags, + mapper: &'a mut PageMapper, + ) -> Self { + let guard = vma.lock_irqsave(); + let file_pgoff = guard.file_page_offset().map(|file_page_offset| { + ((address - guard.region().start()) >> MMArch::PAGE_SHIFT) + file_page_offset + }); Self { vma: vma.clone(), - address, + address: VirtAddr::new(crate::libs::align::page_align_down(address.data())), flags, + file_pgoff, + page: None, + mapper, + cow_page: None, } } @@ -75,16 +110,6 @@ impl PageFaultMessage { } } -impl Clone for PageFaultMessage { - fn clone(&self) -> Self { - Self { - vma: self.vma.clone(), - address: self.address, - flags: self.flags, - } - } -} - /// 缺页中断处理结构体 pub struct PageFaultHandler; @@ -97,7 +122,7 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 - pub unsafe fn handle_mm_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + pub unsafe fn handle_mm_fault(mut pfm: PageFaultMessage) -> VmFaultReason { let flags = pfm.flags(); let vma = pfm.vma(); let current_pcb = ProcessManager::current_pcb(); @@ -113,13 +138,13 @@ impl PageFaultHandler { return VmFaultReason::VM_FAULT_SIGSEGV; } - let guard = vma.lock(); + let guard = vma.lock_irqsave(); let vm_flags = *guard.vm_flags(); drop(guard); if unlikely(vm_flags.contains(VmFlags::VM_HUGETLB)) { //TODO: 添加handle_hugetlb_fault处理大页缺页异常 } else { - Self::handle_normal_fault(pfm, mapper); + Self::handle_normal_fault(&mut pfm); } VmFaultReason::VM_FAULT_COMPLETED @@ -133,18 +158,16 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 - pub unsafe fn handle_normal_fault( - pfm: PageFaultMessage, - mapper: &mut PageMapper, - ) -> VmFaultReason { + pub unsafe fn handle_normal_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { let address = pfm.address_aligned_down(); let vma = pfm.vma.clone(); + let mapper = &mut pfm.mapper; if mapper.get_entry(address, 3).is_none() { mapper .allocate_table(address, 2) .expect("failed to allocate PUD table"); } - let page_flags = vma.lock().flags(); + let page_flags = vma.lock_irqsave().flags(); for level in 2..=3 { let level = MMArch::PAGE_LEVELS - level; @@ -159,7 +182,7 @@ impl PageFaultHandler { } } - Self::handle_pte_fault(pfm, mapper) + Self::handle_pte_fault(pfm) } /// 处理页表项异常 @@ -170,35 +193,37 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 - pub unsafe fn handle_pte_fault( - pfm: PageFaultMessage, - mapper: &mut PageMapper, - ) -> VmFaultReason { + pub unsafe fn handle_pte_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { let address = pfm.address_aligned_down(); let flags = pfm.flags; let vma = pfm.vma.clone(); let mut ret = VmFaultReason::VM_FAULT_COMPLETED; + let mapper = &pfm.mapper; + + // pte存在 if let Some(mut entry) = mapper.get_entry(address, 0) { if !entry.present() { - ret = Self::do_swap_page(pfm.clone(), mapper); + ret = Self::do_swap_page(pfm); } + if entry.protnone() && vma.is_accessible() { - ret = Self::do_numa_page(pfm.clone(), mapper); + ret = Self::do_numa_page(pfm); } + if flags.intersects(FaultFlags::FAULT_FLAG_WRITE | FaultFlags::FAULT_FLAG_UNSHARE) { if !entry.write() { - ret = Self::do_wp_page(pfm.clone(), mapper); + ret = Self::do_wp_page(pfm); } 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() { - ret = Self::do_anonymous_page(pfm.clone(), mapper); + ret = Self::do_anonymous_page(pfm); } else { - ret = Self::do_fault(pfm.clone(), mapper); + ret = Self::do_fault(pfm); } - vma.lock().set_mapped(true); + vma.lock_irqsave().set_mapped(true); return ret; } @@ -211,13 +236,12 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 - pub unsafe fn do_anonymous_page( - pfm: PageFaultMessage, - mapper: &mut PageMapper, - ) -> VmFaultReason { + pub unsafe fn do_anonymous_page(pfm: &mut PageFaultMessage) -> VmFaultReason { let address = pfm.address_aligned_down(); let vma = pfm.vma.clone(); - let guard = vma.lock(); + let guard = vma.lock_irqsave(); + let mapper = &mut pfm.mapper; + if let Some(flush) = mapper.map(address, guard.flags()) { flush.flush(); crate::debug::klog::mm::mm_debug_log( @@ -229,9 +253,9 @@ impl PageFaultHandler { klog_types::LogSource::Buddy, ); let paddr = mapper.translate(address).unwrap().0; - let mut anon_vma_guard = page_manager_lock_irqsave(); - let page = anon_vma_guard.get_mut(&paddr); - page.insert_vma(vma.clone()); + let mut page_manager_guard = page_manager_lock_irqsave(); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(vma.clone()); VmFaultReason::VM_FAULT_COMPLETED } else { VmFaultReason::VM_FAULT_OOM @@ -246,16 +270,19 @@ 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() - ); - // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_fault + pub unsafe fn do_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + if !pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE) { + return Self::do_read_fault(pfm); + } else if !pfm + .vma() + .lock_irqsave() + .vm_flags() + .contains(VmFlags::VM_SHARED) + { + return Self::do_cow_fault(pfm); + } else { + return Self::do_shared_fault(pfm); + } } /// 处理私有文件映射的写时复制 @@ -266,16 +293,51 @@ impl PageFaultHandler { /// /// ## 返回值 /// - 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() + pub unsafe fn do_cow_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + let mut ret = Self::filemap_fault(pfm); + + if unlikely(ret.intersects( + VmFaultReason::VM_FAULT_ERROR + | VmFaultReason::VM_FAULT_NOPAGE + | VmFaultReason::VM_FAULT_RETRY + | VmFaultReason::VM_FAULT_DONE_COW, + )) { + return ret; + } + + let cache_page = pfm.page.clone().unwrap(); + let mapper = &mut pfm.mapper; + + let cow_page_phys = mapper.allocator_mut().allocate_one(); + if cow_page_phys.is_none() { + return VmFaultReason::VM_FAULT_OOM; + } + let cow_page_phys = cow_page_phys.unwrap(); + + let cow_page = Arc::new(Page::new(false, cow_page_phys)); + pfm.cow_page = Some(cow_page.clone()); + + //复制PageCache内容到新的页内 + let new_frame = MMArch::phys_2_virt(cow_page_phys).unwrap(); + (new_frame.data() as *mut u8).copy_from_nonoverlapping( + MMArch::phys_2_virt(cache_page.read_irqsave().phys_address()) + .unwrap() + .data() as *mut u8, + MMArch::PAGE_SIZE, ); - // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_cow_fault + + let mut page_manager_guard = page_manager_lock_irqsave(); + + // 新页加入页管理器中 + page_manager_guard.insert(cow_page_phys, &cow_page); + cow_page.write_irqsave().set_page_cache_index( + cache_page.read_irqsave().page_cache(), + cache_page.read_irqsave().index(), + ); + + ret = ret.union(Self::finish_fault(pfm)); + + ret } /// 处理文件映射页的缺页异常 @@ -286,16 +348,19 @@ 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() - ); - // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault + pub unsafe fn do_read_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs(); + + let mut ret = Self::do_fault_around(pfm); + if !ret.is_empty() { + return ret; + } + + ret = fs.fault(pfm); + + ret = ret.union(Self::finish_fault(pfm)); + + ret } /// 处理对共享文件映射区写入引起的缺页 @@ -306,16 +371,16 @@ impl PageFaultHandler { /// /// ## 返回值 /// - 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 + pub unsafe fn do_shared_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + let mut ret = Self::filemap_fault(pfm); + + let cache_page = pfm.page.clone().expect("no cache_page in PageFaultMessage"); + + // 将pagecache页设为脏页,以便回收时能够回写 + cache_page.write_irqsave().add_flags(PageFlags::PG_DIRTY); + ret = ret.union(Self::finish_fault(pfm)); + + ret } /// 处理被置换页面的缺页异常 @@ -327,7 +392,7 @@ impl PageFaultHandler { /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 #[allow(unused_variables)] - pub unsafe fn do_swap_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + pub unsafe fn do_swap_page(pfm: &mut PageFaultMessage) -> VmFaultReason { panic!( "do_swap_page has not yet been implemented, fault message: {:?}, @@ -347,7 +412,7 @@ impl PageFaultHandler { /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 #[allow(unused_variables)] - pub unsafe fn do_numa_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + pub unsafe fn do_numa_page(pfm: &mut PageFaultMessage) -> VmFaultReason { panic!( "do_numa_page has not yet been implemented, fault message: {:?}, @@ -366,43 +431,289 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 - pub unsafe fn do_wp_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason { + pub unsafe fn do_wp_page(pfm: &mut PageFaultMessage) -> VmFaultReason { let address = pfm.address_aligned_down(); let vma = pfm.vma.clone(); + let mapper = &mut pfm.mapper; + 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 old_page = page_manager.get_unwrap(&old_paddr); + let map_count = old_page.read_irqsave().map_count(); drop(page_manager); let mut entry = mapper.get_entry(address, 0).unwrap(); - let new_flags = entry.flags().set_write(true); + let new_flags = entry.flags().set_write(true).set_dirty(true); - if map_count == 1 { + if vma.lock().vm_flags().contains(VmFlags::VM_SHARED) { + // 共享映射,直接修改页表项保护位,标记为脏页 let table = mapper.get_table(address, 0).unwrap(); let i = table.index_of(address).unwrap(); entry.set_flags(new_flags); table.set_entry(i, entry); - VmFaultReason::VM_FAULT_COMPLETED - } else if let Some(flush) = mapper.map(address, new_flags) { - let mut page_manager = page_manager_lock_irqsave(); - let old_page = page_manager.get_mut(&old_paddr); - old_page.remove_vma(&vma); - drop(page_manager); - flush.flush(); - let paddr = mapper.translate(address).unwrap().0; - let mut anon_vma_guard = page_manager_lock_irqsave(); - let page = anon_vma_guard.get_mut(&paddr); - page.insert_vma(vma.clone()); - - (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping( - MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8, - MMArch::PAGE_SIZE, - ); + old_page.write_irqsave().add_flags(PageFlags::PG_DIRTY); VmFaultReason::VM_FAULT_COMPLETED + } else if vma.is_anonymous() { + // 私有匿名映射,根据引用计数判断是否拷贝页面 + if map_count == 1 { + let table = mapper.get_table(address, 0).unwrap(); + let i = table.index_of(address).unwrap(); + entry.set_flags(new_flags); + table.set_entry(i, entry); + VmFaultReason::VM_FAULT_COMPLETED + } else if let Some(flush) = mapper.map(address, new_flags) { + let mut page_manager_guard = page_manager_lock_irqsave(); + let old_page = page_manager_guard.get_unwrap(&old_paddr); + old_page.write_irqsave().remove_vma(&vma); + // drop(page_manager_guard); + + flush.flush(); + let paddr = mapper.translate(address).unwrap().0; + // let mut page_manager_guard = page_manager_lock_irqsave(); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(vma.clone()); + + (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping( + MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8, + MMArch::PAGE_SIZE, + ); + + VmFaultReason::VM_FAULT_COMPLETED + } else { + VmFaultReason::VM_FAULT_OOM + } } else { - VmFaultReason::VM_FAULT_OOM + // 私有文件映射,必须拷贝页面 + if let Some(flush) = mapper.map(address, new_flags) { + let mut page_manager_guard = page_manager_lock_irqsave(); + let old_page = page_manager_guard.get_unwrap(&old_paddr); + old_page.write_irqsave().remove_vma(&vma); + // drop(page_manager_guard); + + flush.flush(); + let paddr = mapper.translate(address).unwrap().0; + // let mut page_manager_guard = page_manager_lock_irqsave(); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(vma.clone()); + + (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping( + MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8, + MMArch::PAGE_SIZE, + ); + + VmFaultReason::VM_FAULT_COMPLETED + } else { + VmFaultReason::VM_FAULT_OOM + } } } + + /// 缺页附近页预读 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub unsafe fn do_fault_around(pfm: &mut PageFaultMessage) -> VmFaultReason { + let vma = pfm.vma(); + let address = pfm.address(); + let mapper = &mut pfm.mapper; + + if mapper.get_table(address, 0).is_none() { + mapper + .allocate_table(address, 0) + .expect("failed to allocate pte table"); + } + let vma_guard = vma.lock_irqsave(); + let vma_region = *vma_guard.region(); + drop(vma_guard); + + // 缺页在VMA中的偏移量 + let vm_pgoff = (address - vma_region.start()) >> MMArch::PAGE_SHIFT; + + // 缺页在PTE中的偏移量 + let pte_pgoff = (address.data() >> MMArch::PAGE_SHIFT) & (1 << MMArch::PAGE_ENTRY_SHIFT); + + // 缺页在文件中的偏移量 + let file_pgoff = pfm.file_pgoff.expect("no file_pgoff"); + + let vma_pages_count = (vma_region.end() - vma_region.start()) >> MMArch::PAGE_SHIFT; + + let fault_around_page_number = 16; + + // 开始位置不能超出当前pte和vma头部 + let from_pte = max( + align_down(pte_pgoff, fault_around_page_number), + pte_pgoff - min(vm_pgoff, pte_pgoff), + ); + + // 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(address, 0).is_none() && mapper.allocate_table(address, 0).is_none() { + return VmFaultReason::VM_FAULT_OOM; + } + + let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs(); + // from_pte - pte_pgoff得出预读起始pte相对缺失页的偏移,加上pfm.file_pgoff(缺失页在文件中的偏移)得出起始页在文件中的偏移,结束pte同理 + fs.map_pages( + pfm, + file_pgoff + (from_pte - pte_pgoff), + file_pgoff + (to_pte - pte_pgoff), + ); + + VmFaultReason::empty() + } + + /// 通用的VMA文件映射页面映射函数,将PageCache中的页面映射到进程空间 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub unsafe fn filemap_map_pages( + pfm: &mut PageFaultMessage, + + start_pgoff: usize, + end_pgoff: usize, + ) -> VmFaultReason { + let vma = pfm.vma(); + let vma_guard = vma.lock_irqsave(); + let file = vma_guard.vm_file().expect("no vm_file in vma"); + let page_cache = file.inode().page_cache().unwrap(); + let mapper = &mut pfm.mapper; + + // 起始页地址 + let addr = vma_guard.region().start + + ((start_pgoff + - vma_guard + .file_page_offset() + .expect("file_page_offset is none")) + << MMArch::PAGE_SHIFT); + + for pgoff in start_pgoff..=end_pgoff { + if let Some(page) = page_cache.get_page(pgoff) { + let page_guard = page.read_irqsave(); + if page_guard.flags().contains(PageFlags::PG_UPTODATE) { + let phys = page_guard.phys_address(); + + let address = + VirtAddr::new(addr.data() + ((pgoff - start_pgoff) << MMArch::PAGE_SHIFT)); + mapper + .map_phys(address, phys, vma_guard.flags()) + .unwrap() + .flush(); + } + } + } + VmFaultReason::empty() + } + + /// 通用的VMA文件映射错误处理函数 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub unsafe fn filemap_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + let vma = pfm.vma(); + let vma_guard = vma.lock_irqsave(); + let file = vma_guard.vm_file().expect("no vm_file in vma"); + let page_cache = file.inode().page_cache().unwrap(); + let file_pgoff = pfm.file_pgoff.expect("no file_pgoff"); + let mapper = &mut pfm.mapper; + let mut ret = VmFaultReason::empty(); + + if let Some(page) = page_cache.get_page(file_pgoff) { + // TODO 异步从磁盘中预读页面进PageCache + + // 直接将PageCache中的页面作为要映射的页面 + pfm.page = Some(page.clone()); + } else { + // TODO 同步预读 + //涉及磁盘IO,返回标志为VM_FAULT_MAJOR + ret = VmFaultReason::VM_FAULT_MAJOR; + // let mut buf: Vec = vec![0; MMArch::PAGE_SIZE]; + + let allocator = mapper.allocator_mut(); + + // 分配一个物理页面作为加入PageCache的新页 + let new_cache_page = allocator.allocate_one().unwrap(); + // (MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8) + // .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE); + file.pread( + file_pgoff * MMArch::PAGE_SIZE, + MMArch::PAGE_SIZE, + core::slice::from_raw_parts_mut( + MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8, + MMArch::PAGE_SIZE, + ), + ) + .expect("failed to read file to create pagecache page"); + + let page = Arc::new(Page::new(true, new_cache_page)); + pfm.page = Some(page.clone()); + + page.write_irqsave().add_flags(PageFlags::PG_LRU); + page_manager_lock_irqsave().insert(new_cache_page, &page); + page_reclaimer_lock_irqsave().insert_page(new_cache_page, &page); + page_cache.add_page(file_pgoff, &page); + + page.write_irqsave() + .set_page_cache_index(Some(page_cache), Some(file_pgoff)); + } + ret + } + + /// 将文件页映射到缺页地址 + /// ## 参数 + /// + /// - `pfm`: 缺页异常信息 + /// - `mapper`: 页表映射器 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub unsafe fn finish_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { + let vma = pfm.vma(); + let vma_guard = vma.lock_irqsave(); + let flags = pfm.flags(); + let cache_page = pfm.page.clone(); + let cow_page = pfm.cow_page.clone(); + let address = pfm.address(); + let mapper = &mut pfm.mapper; + + let page_to_map = if flags.contains(FaultFlags::FAULT_FLAG_WRITE) + && !vma_guard.vm_flags().contains(VmFlags::VM_SHARED) + { + // 私有文件映射的写时复制 + cow_page.expect("no cow_page in PageFaultMessage") + } else { + // 直接映射到PageCache + cache_page.expect("no cache_page in PageFaultMessage") + }; + + let page_phys = page_to_map.read_irqsave().phys_address(); + + mapper.map_phys(address, page_phys, vma_guard.flags()); + page_to_map.write_irqsave().insert_vma(pfm.vma()); + VmFaultReason::VM_FAULT_COMPLETED + } } diff --git a/kernel/src/mm/init.rs b/kernel/src/mm/init.rs index 0f44ef7c..3fe0e72f 100644 --- a/kernel/src/mm/init.rs +++ b/kernel/src/mm/init.rs @@ -8,7 +8,11 @@ use crate::{ filesystem::procfs::kmsg::kmsg_init, ipc::shm::shm_manager_init, libs::printk::PrintkWriter, - mm::{allocator::slab::slab_init, mmio_buddy::mmio_init, page::page_manager_init}, + mm::{ + allocator::slab::slab_init, + mmio_buddy::mmio_init, + page::{page_manager_init, page_reclaimer_init}, + }, }; use super::MemoryManagementArch; @@ -57,6 +61,8 @@ pub unsafe fn mm_init() { page_manager_init(); // enable SHM_MANAGER shm_manager_init(); + // enable PAGE_RECLAIMER + page_reclaimer_init(); MM_INIT .compare_exchange( 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/madvise.rs b/kernel/src/mm/madvise.rs index 5e9587a4..9089f88f 100644 --- a/kernel/src/mm/madvise.rs +++ b/kernel/src/mm/madvise.rs @@ -12,7 +12,7 @@ impl LockedVMA { _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 vma = self.lock_irqsave(); let mut new_flags = *vma.vm_flags(); match behavior { MadvFlags::MADV_REMOVE => { diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index 6f7805b9..8d88f8ac 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}; // 最大的伙伴块的幂 @@ -552,7 +552,7 @@ impl MmioBuddyMemPool { unsafe { let x: Option<( PhysAddr, - PageFlags, + EntryFlags, crate::mm::page::PageFlush, )> = kernel_mapper .as_mut() @@ -677,7 +677,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 e323cbe1..e95e9019 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,4 +1,5 @@ use alloc::sync::Arc; +use page::EntryFlags; use system_error::SystemError; use crate::arch::MMArch; @@ -40,7 +41,7 @@ static mut __IDLE_PROCESS_ADDRESS_SPACE: Option> = None; bitflags! { /// Virtual memory flags #[allow(clippy::bad_bit_mask)] - pub struct VmFlags:u64{ + pub struct VmFlags:usize{ const VM_NONE = 0x00000000; const VM_READ = 0x00000001; @@ -93,6 +94,27 @@ bitflags! { const VM_FAULT_NEEDDSYNC = 0x002000; const VM_FAULT_COMPLETED = 0x004000; const VM_FAULT_HINDEX_MASK = 0x0f0000; + const VM_FAULT_ERROR = 0x000001 | 0x000002 | 0x000040 | 0x000010 | 0x000020 | 0x000800; + } + + pub struct MsFlags:usize { + const MS_ASYNC = 1; + const MS_INVALIDATE = 2; + const MS_SYNC = 4; + } +} + +impl core::ops::Index for [usize] { + type Output = usize; + + fn index(&self, index: VmFlags) -> &Self::Output { + &self[index.bits] + } +} + +impl core::ops::IndexMut for [usize] { + fn index_mut(&mut self, index: VmFlags) -> &mut Self::Output { + &mut self[index.bits] } } @@ -599,7 +621,7 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { /// 创建页表项 /// - /// 这是一个低阶api,用于根据物理地址以及指定好的pageflags,创建页表项 + /// 这是一个低阶api,用于根据物理地址以及指定好的EntryFlags,创建页表项 /// /// ## 参数 /// @@ -631,6 +653,48 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { ) -> bool { true } + + const PAGE_NONE: usize; + const PAGE_SHARED: usize; + const PAGE_SHARED_EXEC: usize; + const PAGE_COPY_NOEXEC: usize; + const PAGE_COPY_EXEC: usize; + const PAGE_COPY: usize; + const PAGE_READONLY: usize; + const PAGE_READONLY_EXEC: usize; + + const PAGE_READ: usize; + const PAGE_READ_EXEC: usize; + const PAGE_WRITE: usize; + const PAGE_WRITE_EXEC: usize; + const PAGE_EXEC: usize; + + const PROTECTION_MAP: [EntryFlags; 16]; + + /// 页面保护标志转换函数 + /// ## 参数 + /// + /// - `vm_flags`: VmFlags标志 + /// + /// ## 返回值 + /// - EntryFlags: 页面的保护位 + fn vm_get_page_prot(vm_flags: VmFlags) -> EntryFlags { + let map = Self::PROTECTION_MAP; + let mut ret = map[vm_flags + .intersection( + VmFlags::VM_READ | VmFlags::VM_WRITE | VmFlags::VM_EXEC | VmFlags::VM_SHARED, + ) + .bits()]; + + #[cfg(target_arch = "x86_64")] + { + // 如果xd位被保留,那么将可执行性设置为true + if crate::arch::mm::X86_64MMArch::is_xd_reserved() { + ret = ret.set_execute(true); + } + } + ret + } } /// @brief 虚拟地址范围 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 d91c437c..27b399dd 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -1,3 +1,4 @@ +use alloc::string::ToString; use core::{ fmt::{self, Debug, Error, Formatter}, marker::PhantomData, @@ -5,16 +6,26 @@ use core::{ ops::Add, sync::atomic::{compiler_fence, Ordering}, }; +use system_error::SystemError; +use unified_init::macros::unified_init; use alloc::sync::Arc; use hashbrown::{HashMap, HashSet}; use log::{error, info}; +use lru::LruCache; use crate::{ - arch::{interrupt::ipi::send_ipi, MMArch}, + arch::{interrupt::ipi::send_ipi, mm::LockedFrameAllocator, MMArch}, exception::ipi::{IpiKind, IpiTarget}, + filesystem::vfs::{file::PageCache, FilePrivateData}, + init::initcall::INITCALL_CORE, ipc::shm::ShmId, - libs::spinlock::{SpinLock, SpinLockGuard}, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, + process::{ProcessControlBlock, ProcessManager}, + time::{sleep::usleep, PosixTimeSpec}, }; use super::{ @@ -53,7 +64,7 @@ pub fn page_manager_lock_irqsave() -> SpinLockGuard<'static, PageManager> { // 物理页管理器 pub struct PageManager { - phys2page: HashMap, + phys2page: HashMap>, } impl PageManager { @@ -67,18 +78,21 @@ impl PageManager { self.phys2page.contains_key(paddr) } - pub fn get(&self, paddr: &PhysAddr) -> Option<&Page> { - self.phys2page.get(paddr) + pub fn get(&mut self, paddr: &PhysAddr) -> Option> { + page_reclaimer_lock_irqsave().get(paddr); + self.phys2page.get(paddr).cloned() } - pub fn get_mut(&mut self, paddr: &PhysAddr) -> &mut Page { + pub fn get_unwrap(&mut self, paddr: &PhysAddr) -> Arc { + page_reclaimer_lock_irqsave().get(paddr); self.phys2page - .get_mut(paddr) - .unwrap_or_else(|| panic!("{:?}", paddr)) + .get(paddr) + .unwrap_or_else(|| panic!("Phys Page not found, {:?}", paddr)) + .clone() } - pub fn insert(&mut self, paddr: PhysAddr, page: Page) { - self.phys2page.insert(paddr, page); + pub fn insert(&mut self, paddr: PhysAddr, page: &Arc) { + self.phys2page.insert(paddr, page.clone()); } pub fn remove_page(&mut self, paddr: &PhysAddr) { @@ -86,8 +100,236 @@ impl PageManager { } } -/// 物理页面信息 +pub static mut PAGE_RECLAIMER: Option> = None; + +pub fn page_reclaimer_init() { + info!("page_reclaimer_init"); + let page_reclaimer = SpinLock::new(PageReclaimer::new()); + + compiler_fence(Ordering::SeqCst); + unsafe { PAGE_RECLAIMER = Some(page_reclaimer) }; + compiler_fence(Ordering::SeqCst); + + info!("page_reclaimer_init done"); +} + +/// 页面回收线程 +static mut PAGE_RECLAIMER_THREAD: Option> = None; + +/// 页面回收线程初始化函数 +#[unified_init(INITCALL_CORE)] +fn page_reclaimer_thread_init() -> Result<(), SystemError> { + let closure = crate::process::kthread::KernelThreadClosure::StaticEmptyClosure(( + &(page_reclaim_thread as fn() -> i32), + (), + )); + let pcb = crate::process::kthread::KernelThreadMechanism::create_and_run( + closure, + "page_reclaim".to_string(), + ) + .ok_or("") + .expect("create tty_refresh thread failed"); + unsafe { + PAGE_RECLAIMER_THREAD = Some(pcb); + } + Ok(()) +} + +/// 页面回收线程执行的函数 +fn page_reclaim_thread() -> i32 { + loop { + let usage = unsafe { LockedFrameAllocator.usage() }; + // log::info!("usage{:?}", usage); + + // 保留4096个页面,总计16MB的空闲空间 + if usage.free().data() < 4096 { + let page_to_free = 4096; + page_reclaimer_lock_irqsave().shrink_list(PageFrameCount::new(page_to_free)); + } else { + //TODO 暂时让页面回收线程负责脏页回写任务,后续需要分离 + page_reclaimer_lock_irqsave().flush_dirty_pages(); + // 休眠5秒 + // log::info!("sleep"); + let _ = usleep(PosixTimeSpec::new(5, 0)); + } + } +} + +/// 获取页面回收器 +pub fn page_reclaimer_lock_irqsave() -> SpinLockGuard<'static, PageReclaimer> { + unsafe { PAGE_RECLAIMER.as_ref().unwrap().lock_irqsave() } +} + +/// 页面回收器 +pub struct PageReclaimer { + lru: LruCache>, +} + +impl PageReclaimer { + pub fn new() -> Self { + Self { + lru: LruCache::unbounded(), + } + } + + pub fn get(&mut self, paddr: &PhysAddr) -> Option> { + self.lru.get(paddr).cloned() + } + + pub fn insert_page(&mut self, paddr: PhysAddr, page: &Arc) { + self.lru.put(paddr, page.clone()); + } + + /// lru链表缩减 + /// ## 参数 + /// + /// - `count`: 需要缩减的页面数量 + pub fn shrink_list(&mut self, count: PageFrameCount) { + for _ in 0..count.data() { + let (paddr, page) = self.lru.pop_lru().expect("pagecache is empty"); + let page_cache = page.read_irqsave().page_cache().unwrap(); + for vma in page.read_irqsave().anon_vma() { + let address_space = vma.lock_irqsave().address_space().unwrap(); + let address_space = address_space.upgrade().unwrap(); + let mut guard = address_space.write(); + let mapper = &mut guard.user_mapper.utable; + let virt = vma.lock_irqsave().page_address(&page).unwrap(); + unsafe { + mapper.unmap(virt, false).unwrap().flush(); + } + } + page_cache.remove_page(page.read_irqsave().index().unwrap()); + page_manager_lock_irqsave().remove_page(&paddr); + if page.read_irqsave().flags.contains(PageFlags::PG_DIRTY) { + Self::page_writeback(&page, true); + } + } + } + + /// 唤醒页面回收线程 + pub fn wakeup_claim_thread() { + // log::info!("wakeup_claim_thread"); + let _ = ProcessManager::wakeup(unsafe { PAGE_RECLAIMER_THREAD.as_ref().unwrap() }); + } + + /// 脏页回写函数 + /// ## 参数 + /// + /// - `page`: 需要回写的脏页 + /// - `unmap`: 是否取消映射 + /// + /// ## 返回值 + /// - VmFaultReason: 页面错误处理信息标志 + pub fn page_writeback(page: &Arc, unmap: bool) { + if !unmap { + page.write_irqsave().remove_flags(PageFlags::PG_DIRTY); + } + + for vma in page.read_irqsave().anon_vma() { + let address_space = vma.lock_irqsave().address_space().unwrap(); + let address_space = address_space.upgrade().unwrap(); + let mut guard = address_space.write(); + let mapper = &mut guard.user_mapper.utable; + let virt = vma.lock_irqsave().page_address(page).unwrap(); + if unmap { + unsafe { + mapper.unmap(virt, false).unwrap().flush(); + } + } else { + unsafe { + // 保护位设为只读 + mapper.remap( + virt, + mapper.get_entry(virt, 0).unwrap().flags().set_write(false), + ) + }; + } + } + let inode = page + .read_irqsave() + .page_cache + .clone() + .unwrap() + .inode() + .clone() + .unwrap() + .upgrade() + .unwrap(); + inode + .write_at( + page.read_irqsave().index().unwrap(), + MMArch::PAGE_SIZE, + unsafe { + core::slice::from_raw_parts( + MMArch::phys_2_virt(page.read_irqsave().phys_addr) + .unwrap() + .data() as *mut u8, + MMArch::PAGE_SIZE, + ) + }, + SpinLock::new(FilePrivateData::Unused).lock(), + ) + .unwrap(); + } + + /// lru脏页刷新 + pub fn flush_dirty_pages(&self) { + // log::info!("flush_dirty_pages"); + let iter = self.lru.iter(); + for (_, page) in iter { + if page.read_irqsave().flags().contains(PageFlags::PG_DIRTY) { + Self::page_writeback(page, false); + } + } + } +} + +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; + } +} + +#[derive(Debug)] pub struct Page { + inner: RwLock, +} + +impl Page { + pub fn new(shared: bool, phys_addr: PhysAddr) -> Self { + let inner = InnerPage::new(shared, phys_addr); + Self { + inner: RwLock::new(inner), + } + } + + pub fn read_irqsave(&self) -> RwLockReadGuard { + self.inner.read_irqsave() + } + + pub fn write_irqsave(&self) -> RwLockWriteGuard { + self.inner.write_irqsave() + } +} + +#[derive(Debug)] +/// 物理页面信息 +pub struct InnerPage { /// 映射计数 map_count: usize, /// 是否为共享页 @@ -98,10 +340,17 @@ pub struct Page { shm_id: Option, /// 映射到当前page的VMA anon_vma: HashSet>, + /// 标志 + flags: PageFlags, + /// 页所在的物理页帧号 + phys_addr: PhysAddr, + /// 在pagecache中的偏移 + index: Option, + page_cache: Option>, } -impl Page { - pub fn new(shared: bool) -> Self { +impl InnerPage { + pub fn new(shared: bool, phys_addr: PhysAddr) -> Self { let dealloc_when_zero = !shared; Self { map_count: 0, @@ -109,6 +358,10 @@ impl Page { free_when_zero: dealloc_when_zero, shm_id: None, anon_vma: HashSet::new(), + flags: PageFlags::empty(), + phys_addr, + index: None, + page_cache: None, } } @@ -137,6 +390,31 @@ impl Page { self.shm_id } + pub fn index(&self) -> Option { + self.index + } + + pub fn page_cache(&self) -> Option> { + self.page_cache.clone() + } + + pub fn set_page_cache(&mut self, page_cache: Option>) { + self.page_cache = page_cache; + } + + pub fn set_index(&mut self, index: Option) { + self.index = index; + } + + pub fn set_page_cache_index( + &mut self, + page_cache: Option>, + index: Option, + ) { + self.page_cache = page_cache; + self.index = index; + } + pub fn set_shm_id(&mut self, shm_id: ShmId) { self.shm_id = Some(shm_id); } @@ -154,6 +432,31 @@ impl Page { pub fn map_count(&self) -> usize { self.map_count } + + #[inline(always)] + pub fn flags(&self) -> &PageFlags { + &self.flags + } + + #[inline(always)] + pub fn set_flags(&mut self, flags: PageFlags) { + self.flags = flags + } + + #[inline(always)] + pub fn add_flags(&mut self, flags: PageFlags) { + self.flags = self.flags.union(flags); + } + + #[inline(always)] + pub fn remove_flags(&mut self, flags: PageFlags) { + self.flags = self.flags.difference(flags); + } + + #[inline(always)] + pub fn phys_address(&self) -> PhysAddr { + self.phys_addr + } } #[derive(Debug)] @@ -329,8 +632,19 @@ impl PageTable { new_table.set_entry(i, entry); } else { let phys = allocator.allocate_one()?; - let mut anon_vma_guard = page_manager_lock_irqsave(); - anon_vma_guard.insert(phys, Page::new(false)); + let mut page_manager_guard = page_manager_lock_irqsave(); + let old_phys = entry.address().unwrap(); + let old_page = page_manager_guard.get_unwrap(&old_phys); + let new_page = + Arc::new(Page::new(old_page.read_irqsave().shared(), phys)); + if let Some(ref page_cache) = old_page.read_irqsave().page_cache() { + new_page.write_irqsave().set_page_cache_index( + Some(page_cache.clone()), + old_page.read_irqsave().index(), + ); + } + + page_manager_guard.insert(phys, &new_page); let old_phys = entry.address().unwrap(); let frame = MMArch::phys_2_virt(phys).unwrap().data() as *mut u8; frame.copy_from_nonoverlapping( @@ -372,7 +686,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 +734,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,19 +767,19 @@ impl PageEntry { /// 页表项的标志位 #[derive(Copy, Clone, Hash)] -pub struct PageFlags { +pub struct EntryFlags { data: usize, phantom: PhantomData, } -impl Default for PageFlags { +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 { @@ -486,18 +800,19 @@ 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() - .set_user(user) - .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC)) - .set_write(prot_flags.contains(ProtFlags::PROT_WRITE)); - + pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> Self { + let vm_flags = super::VmFlags::from(prot_flags); + // let flags: EntryFlags = EntryFlags::new() + // .set_user(user) + // .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC)) + // .set_write(prot_flags.contains(ProtFlags::PROT_WRITE)); + let flags = Arch::vm_get_page_prot(vm_flags).set_user(user); return flags; } @@ -763,9 +1078,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()) @@ -861,7 +1176,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()?; @@ -875,9 +1190,9 @@ 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, &Arc::new(Page::new(false, phys))) } - + drop(page_manager_guard); return self.map_phys(virt, phys, flags); } @@ -886,7 +1201,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)) { @@ -926,8 +1241,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)); @@ -943,7 +1258,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)) { @@ -1009,7 +1324,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) @@ -1111,7 +1427,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)); @@ -1131,7 +1447,7 @@ impl PageMapper { pub unsafe fn remap( &mut self, virt: VirtAddr, - flags: PageFlags, + flags: EntryFlags, ) -> Option> { return self .visit(virt, |p1, i| { @@ -1153,7 +1469,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(); @@ -1192,7 +1508,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; @@ -1240,7 +1556,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/syscall.rs b/kernel/src/mm/syscall.rs index beac5cc2..6c9646a3 100644 --- a/kernel/src/mm/syscall.rs +++ b/kernel/src/mm/syscall.rs @@ -1,4 +1,4 @@ -use core::intrinsics::unlikely; +use core::{intrinsics::unlikely, slice::from_raw_parts}; use alloc::sync::Arc; use log::error; @@ -6,6 +6,7 @@ use system_error::SystemError; use crate::{ arch::MMArch, + driver::base::block::SeekFrom, ipc::shm::ShmFlags, libs::align::{check_aligned, page_align_up}, mm::MemoryManagementArch, @@ -15,7 +16,7 @@ use crate::{ use super::{ allocator::page_frame::{PageFrameCount, VirtPageFrame}, ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, - verify_area, VirtAddr, VmFlags, + verify_area, MsFlags, VirtAddr, VmFlags, }; bitflags! { @@ -154,6 +155,10 @@ impl From for VmFlags { vm_flags |= VmFlags::VM_SYNC; } + if map_flags.contains(MapFlags::MAP_SHARED) { + vm_flags |= VmFlags::VM_SHARED; + } + vm_flags } } @@ -296,8 +301,8 @@ impl Syscall { len: usize, prot_flags: usize, map_flags: usize, - _fd: i32, - _offset: usize, + fd: i32, + offset: usize, ) -> Result { let map_flags = MapFlags::from_bits_truncate(map_flags as u64); let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); @@ -311,11 +316,6 @@ impl Syscall { ); return Err(SystemError::EINVAL); } - // 暂时不支持除匿名页以外的映射 - if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { - error!("mmap: not support file mapping"); - return Err(SystemError::ENOSYS); - } // 暂时不支持巨页映射 if map_flags.contains(MapFlags::MAP_HUGETLB) { @@ -323,14 +323,30 @@ impl Syscall { return Err(SystemError::ENOSYS); } let current_address_space = AddressSpace::current()?; - let start_page = current_address_space.write().map_anonymous( - start_vaddr, - len, - prot_flags, - map_flags, - true, - false, - )?; + let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) { + // 匿名映射 + current_address_space.write().map_anonymous( + start_vaddr, + len, + prot_flags, + map_flags, + true, + false, + )? + } else { + // 文件映射 + current_address_space.write().file_mapping( + start_vaddr, + len, + prot_flags, + map_flags, + fd, + offset, + true, + false, + )? + }; + return Ok(start_page.virt_address().data()); } @@ -390,7 +406,7 @@ impl Syscall { return Err(SystemError::EINVAL); } let vma = vma.unwrap(); - let vm_flags = *vma.lock().vm_flags(); + let vm_flags = *vma.lock_irqsave().vm_flags(); // 暂时不支持巨页映射 if vm_flags.contains(VmFlags::VM_HUGETLB) { @@ -524,4 +540,115 @@ impl Syscall { .map_err(|_| SystemError::EINVAL)?; return Ok(0); } + + /// ## msync系统调用 + /// + /// ## 参数 + /// + /// - `start`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `flags`:标志 + pub fn msync(start: VirtAddr, len: usize, flags: usize) -> Result { + if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + if unlikely(verify_area(start, len).is_err()) { + return Err(SystemError::EINVAL); + } + if unlikely(len == 0) { + return Err(SystemError::EINVAL); + } + + let mut start = start.data(); + let end = start + len; + let flags = MsFlags::from_bits_truncate(flags); + let mut unmapped_error = Ok(0); + + if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) { + return Err(SystemError::EINVAL); + } + + if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) { + return Err(SystemError::EINVAL); + } + + if end < start { + return Err(SystemError::ENOMEM); + } + + if start == end { + return Ok(0); + } + + let current_address_space = AddressSpace::current()?; + let mut err = Err(SystemError::ENOMEM); + let mut next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(start)); + loop { + if let Some(vma) = next_vma.clone() { + let guard = vma.lock_irqsave(); + let vm_start = guard.region().start().data(); + let vm_end = guard.region().end().data(); + if start < vm_start { + if flags == MsFlags::MS_ASYNC { + break; + } + start = vm_start; + if start >= vm_end { + break; + } + unmapped_error = Err(SystemError::ENOMEM); + } + let vm_flags = *guard.vm_flags(); + if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) { + err = Err(SystemError::EBUSY); + break; + } + let file = guard.vm_file(); + let fstart = (start - vm_start) + + (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT); + let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1; + let old_start = start; + start = vm_end; + // log::info!("flags: {:?}", flags); + // log::info!("vm_flags: {:?}", vm_flags); + // log::info!("file: {:?}", file); + if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) { + if let Some(file) = file { + let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap(); + file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap(); + err = file.write(len, unsafe { + from_raw_parts(old_start as *mut u8, fend - fstart + 1) + }); + file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap(); + if err.is_err() { + break; + } else if start >= end { + err = unmapped_error; + break; + } + next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(start)); + } + } else { + if start >= end { + err = unmapped_error; + break; + } + next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(vm_end)); + } + } else { + return Err(SystemError::ENOMEM); + } + } + return err; + } } diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 635213ff..40934b65 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, Page, PageFlushAll}, syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags}, MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags, }; @@ -178,23 +179,23 @@ impl InnerAddressSpace { for vma in self.mappings.vmas.iter() { // TODO: 增加对VMA是否为文件映射的判断,如果是的话,就跳过 - let vma_guard: SpinLockGuard<'_, VMA> = vma.lock(); + let vma_guard: SpinLockGuard<'_, VMA> = vma.lock_irqsave(); // 仅拷贝VMA信息并添加反向映射,因为UserMapper克隆时已经分配了新的物理页 let new_vma = LockedVMA::new(vma_guard.clone_info_only()); new_guard.mappings.vmas.insert(new_vma.clone()); // debug!("new vma: {:x?}", new_vma); - let new_vma_guard = new_vma.lock(); + let new_vma_guard = new_vma.lock_irqsave(); let new_mapper = &new_guard.user_mapper.utable; - let mut anon_vma_guard = page_manager_lock_irqsave(); + let mut page_manager_guard = page_manager_lock_irqsave(); for page in new_vma_guard.pages().map(|p| p.virt_address()) { if let Some((paddr, _)) = new_mapper.translate(page) { - let page = anon_vma_guard.get_mut(&paddr); - page.insert_vma(new_vma.clone()); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(new_vma.clone()); } } - drop(anon_vma_guard); + drop(page_manager_guard); drop(vma_guard); drop(new_vma_guard); } @@ -282,36 +283,138 @@ impl InnerAddressSpace { // debug!("map_anonymous: len = {}", len); - let start_page: VirtPageFrame = if allocate_at_once { - self.mmap( - round_hint_to_min(start_vaddr), - PageFrameCount::from_bytes(len).unwrap(), - prot_flags, - map_flags, - move |page, count, flags, mapper, flusher| { - VMA::zeroed(page, count, vm_flags, flags, mapper, flusher) - }, - )? - } else { - self.mmap( - round_hint_to_min(start_vaddr), - PageFrameCount::from_bytes(len).unwrap(), - prot_flags, - map_flags, - move |page, count, flags, _mapper, _flusher| { + let start_page: VirtPageFrame = self.mmap( + round_hint_to_min(start_vaddr), + PageFrameCount::from_bytes(len).unwrap(), + prot_flags, + map_flags, + move |page, count, flags, mapper, flusher| { + if allocate_at_once { + VMA::zeroed(page, count, vm_flags, flags, mapper, flusher, None, None) + } else { Ok(LockedVMA::new(VMA::new( VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE), vm_flags, flags, + None, + None, false, ))) - }, - )? - }; + } + }, + )?; return Ok(start_page); } + /// 进行文件页映射 + /// + /// ## 参数 + /// + /// - `start_vaddr`:映射的起始地址 + /// - `len`:映射的长度 + /// - `prot_flags`:保护标志 + /// - `map_flags`:映射标志 + /// - `fd`:文件描述符 + /// - `offset`:映射偏移量 + /// - `round_to_min`:是否将`start_vaddr`对齐到`mmap_min`,如果为`true`,则当`start_vaddr`不为0时,会对齐到`mmap_min`,否则仅向下对齐到页边界 + /// - `allocate_at_once`:是否立即分配物理空间 + /// + /// ## 返回 + /// + /// 返回映射的起始虚拟页帧 + #[allow(clippy::too_many_arguments)] + pub fn file_mapping( + &mut self, + start_vaddr: VirtAddr, + len: usize, + prot_flags: ProtFlags, + map_flags: MapFlags, + fd: i32, + offset: usize, + round_to_min: bool, + allocate_at_once: bool, + ) -> Result { + let allocate_at_once = if MMArch::PAGE_FAULT_ENABLED { + allocate_at_once + } else { + true + }; + // 用于对齐hint的函数 + let round_hint_to_min = |hint: VirtAddr| { + // 先把hint向下对齐到页边界 + let addr = hint.data() & (!MMArch::PAGE_OFFSET_MASK); + // debug!("map_anonymous: hint = {:?}, addr = {addr:#x}", hint); + // 如果hint不是0,且hint小于DEFAULT_MMAP_MIN_ADDR,则对齐到DEFAULT_MMAP_MIN_ADDR + if (addr != 0) && round_to_min && (addr < DEFAULT_MMAP_MIN_ADDR) { + Some(VirtAddr::new(page_align_up(DEFAULT_MMAP_MIN_ADDR))) + } else if addr == 0 { + None + } else { + Some(VirtAddr::new(addr)) + } + }; + // debug!("map_anonymous: start_vaddr = {:?}", start_vaddr); + // debug!("map_anonymous: len(no align) = {}", len); + + let len = page_align_up(len); + + let vm_flags = VmFlags::from(prot_flags) + | VmFlags::from(map_flags) + | VmFlags::VM_MAYREAD + | VmFlags::VM_MAYWRITE + | VmFlags::VM_MAYEXEC; + + // debug!("map_anonymous: len = {}", len); + + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + + let file = fd_table_guard.get_file_by_fd(fd); + if file.is_none() { + return Err(SystemError::EBADF); + } + // drop guard 以避免无法调度的问题 + drop(fd_table_guard); + + // offset需要4K对齐 + if !offset & (MMArch::PAGE_SIZE - 1) == 0 { + return Err(SystemError::EINVAL); + } + let pgoff = offset >> MMArch::PAGE_SHIFT; + + let start_page: VirtPageFrame = self.mmap( + round_hint_to_min(start_vaddr), + PageFrameCount::from_bytes(len).unwrap(), + prot_flags, + map_flags, + move |page, count, flags, mapper, flusher| { + if allocate_at_once { + VMA::zeroed( + page, + count, + vm_flags, + flags, + mapper, + flusher, + file, + Some(pgoff), + ) + } else { + Ok(LockedVMA::new(VMA::new( + VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE), + vm_flags, + flags, + file, + Some(pgoff), + false, + ))) + } + }, + )?; + return Ok(start_page); + } + /// 向进程的地址空间映射页面 /// /// # 参数 @@ -333,7 +436,7 @@ impl InnerAddressSpace { F: FnOnce( VirtPageFrame, PageFrameCount, - PageFlags, + EntryFlags, &mut PageMapper, &mut dyn Flusher, ) -> Result, SystemError>, @@ -380,7 +483,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, )?); @@ -479,9 +582,9 @@ impl InnerAddressSpace { let regions: Vec> = self.mappings.conflicts(to_unmap).collect::>(); for r in regions { - let r = r.lock().region; + let r = r.lock_irqsave().region; let r = self.mappings.remove_vma(&r).unwrap(); - let intersection = r.lock().region().intersect(&to_unmap).unwrap(); + let intersection = r.lock_irqsave().region().intersect(&to_unmap).unwrap(); let split_result = r.extract(intersection, &self.user_mapper.utable).unwrap(); // TODO: 当引入后备页映射后,这里需要增加通知文件的逻辑 @@ -533,10 +636,10 @@ impl InnerAddressSpace { for r in regions { // debug!("mprotect: r: {:?}", r); - let r = *r.lock().region(); + let r = *r.lock_irqsave().region(); let r = self.mappings.remove_vma(&r).unwrap(); - let intersection = r.lock().region().intersect(®ion).unwrap(); + let intersection = r.lock_irqsave().region().intersect(®ion).unwrap(); let split_result = r .extract(intersection, mapper) .expect("Failed to extract VMA"); @@ -548,17 +651,16 @@ impl InnerAddressSpace { self.mappings.insert_vma(after); } - let mut r_guard = r.lock(); + let mut r_guard = r.lock_irqsave(); // 如果VMA的保护标志不允许指定的修改,则返回错误 if !r_guard.can_have_flags(prot_flags) { drop(r_guard); self.mappings.insert_vma(r.clone()); return Err(SystemError::EACCES); } - r_guard.set_vm_flags(VmFlags::from(prot_flags)); - 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)); @@ -592,10 +694,10 @@ impl InnerAddressSpace { let regions = self.mappings.conflicts(region).collect::>(); for r in regions { - let r = *r.lock().region(); + let r = *r.lock_irqsave().region(); let r = self.mappings.remove_vma(&r).unwrap(); - let intersection = r.lock().region().intersect(®ion).unwrap(); + let intersection = r.lock_irqsave().region().intersect(®ion).unwrap(); let split_result = r .extract(intersection, mapper) .expect("Failed to extract VMA"); @@ -768,7 +870,7 @@ impl UserMappings { #[allow(dead_code)] pub fn contains(&self, vaddr: VirtAddr) -> Option> { for v in self.vmas.iter() { - let guard = v.lock(); + let guard = v.lock_irqsave(); if guard.region.contains(vaddr) { return Some(v.clone()); } @@ -788,13 +890,13 @@ impl UserMappings { pub fn find_nearest(&self, vaddr: VirtAddr) -> Option> { let mut nearest: Option> = None; for v in self.vmas.iter() { - let guard = v.lock(); + let guard = v.lock_irqsave(); if guard.region.contains(vaddr) { return Some(v.clone()); } - if guard.region.start > vaddr + if guard.region.start >= vaddr && if let Some(ref nearest) = nearest { - guard.region.start < nearest.lock().region.start + guard.region.start < nearest.lock_irqsave().region.start } else { true } @@ -810,7 +912,7 @@ impl UserMappings { let r = self .vmas .iter() - .filter(move |v| v.lock().region.intersect(&request).is_some()) + .filter(move |v| v.lock_irqsave().region.intersect(&request).is_some()) .cloned(); return r; } @@ -932,7 +1034,7 @@ impl UserMappings { /// 在当前进程的映射关系中,插入一个新的VMA。 pub fn insert_vma(&mut self, vma: Arc) { - let region = vma.lock().region; + let region = vma.lock_irqsave().region; // 要求插入的地址范围必须是空闲的,也就是说,当前进程的地址空间中,不能有任何与之重叠的VMA。 assert!(self.conflicts(region).next().is_none()); self.reserve_hole(®ion); @@ -952,7 +1054,7 @@ impl UserMappings { // 请注意,由于这里会对每个VMA加锁,因此性能很低 let vma: Arc = self .vmas - .drain_filter(|vma| vma.lock().region == *region) + .drain_filter(|vma| vma.lock_irqsave().region == *region) .next()?; self.unreserve_hole(region); @@ -1002,7 +1104,7 @@ impl LockedVMA { id: LOCKEDVMA_ID_ALLOCATOR.alloc().unwrap(), vma: SpinLock::new(vma), }); - r.vma.lock().self_ref = Arc::downgrade(&r); + r.vma.lock_irqsave().self_ref = Arc::downgrade(&r); return r; } @@ -1014,6 +1116,10 @@ impl LockedVMA { return self.vma.lock(); } + pub fn lock_irqsave(&self) -> SpinLockGuard { + return self.vma.lock_irqsave(); + } + /// 调整当前VMA的页面的标志位 /// /// TODO:增加调整虚拟页映射的物理地址的功能 @@ -1024,11 +1130,11 @@ impl LockedVMA { /// pub fn remap( &self, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result<(), SystemError> { - let mut guard = self.lock(); + let mut guard = self.lock_irqsave(); for page in guard.region.pages() { // 暂时要求所有的页帧都已经映射到页表 // TODO: 引入Lazy Mapping, 通过缺页中断来映射页帧,这里就不必要求所有的页帧都已经映射到页表了 @@ -1046,7 +1152,7 @@ impl LockedVMA { pub fn unmap(&self, mapper: &mut PageMapper, mut flusher: impl Flusher) { // todo: 如果当前vma与文件相关,完善文件相关的逻辑 - let mut guard = self.lock(); + let mut guard = self.lock_irqsave(); // 获取物理页的anon_vma的守卫 let mut page_manager_guard: SpinLockGuard<'_, crate::mm::page::PageManager> = @@ -1059,12 +1165,13 @@ impl LockedVMA { .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); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().remove_vma(self); // 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页. - if page.can_deallocate() { + if page.read_irqsave().can_deallocate() { unsafe { + drop(page); deallocate_page_frames( PhysPageFrame::new(paddr), PageFrameCount::new(1), @@ -1076,10 +1183,19 @@ impl LockedVMA { flusher.consume(flush); } guard.mapped = false; + + // 当vma对应共享文件的写映射时,唤醒脏页回写线程 + if guard.vm_file().is_some() + && guard + .vm_flags() + .contains(VmFlags::VM_SHARED | VmFlags::VM_WRITE) + { + crate::mm::page::PageReclaimer::wakeup_claim_thread(); + } } pub fn mapped(&self) -> bool { - return self.vma.lock().mapped; + return self.vma.lock_irqsave().mapped; } /// 将当前VMA进行切分,切分成3个VMA,分别是: @@ -1091,7 +1207,7 @@ impl LockedVMA { assert!(region.start().check_aligned(MMArch::PAGE_SIZE)); assert!(region.end().check_aligned(MMArch::PAGE_SIZE)); - let mut guard = self.lock(); + let mut guard = self.lock_irqsave(); { // 如果传入的region不在当前VMA的范围内,则直接返回None if unlikely(region.start() < guard.region.start() || region.end() > guard.region.end()) @@ -1134,25 +1250,27 @@ impl LockedVMA { // 重新设置before、after这两个VMA里面的物理页的anon_vma let mut page_manager_guard = page_manager_lock_irqsave(); if let Some(before) = before.clone() { - let virt_iter = before.lock().region.iter_pages(); + let virt_iter = before.lock_irqsave().region.iter_pages(); for frame in virt_iter { if let Some((paddr, _)) = utable.translate(frame.virt_address()) { - let page = page_manager_guard.get_mut(&paddr); - page.insert_vma(before.clone()); - page.remove_vma(self); - before.lock().mapped = true; + let page = page_manager_guard.get_unwrap(&paddr); + let mut page_guard = page.write_irqsave(); + page_guard.insert_vma(before.clone()); + page_guard.remove_vma(self); + before.lock_irqsave().mapped = true; } } } if let Some(after) = after.clone() { - let virt_iter = after.lock().region.iter_pages(); + let virt_iter = after.lock_irqsave().region.iter_pages(); for frame in virt_iter { if let Some((paddr, _)) = utable.translate(frame.virt_address()) { - let page = page_manager_guard.get_mut(&paddr); - page.insert_vma(after.clone()); - page.remove_vma(self); - after.lock().mapped = true; + let page = page_manager_guard.get_unwrap(&paddr); + let mut page_guard = page.write_irqsave(); + page_guard.insert_vma(after.clone()); + page_guard.remove_vma(self); + after.lock_irqsave().mapped = true; } } } @@ -1168,7 +1286,7 @@ impl LockedVMA { /// 判断VMA是否为外部(非当前进程空间)的VMA pub fn is_foreign(&self) -> bool { - let guard = self.lock(); + let guard = self.lock_irqsave(); if let Some(space) = guard.user_address_space.clone() { if let Some(space) = space.upgrade() { return AddressSpace::is_current(&space); @@ -1182,15 +1300,15 @@ impl LockedVMA { /// 判断VMA是否可访问 pub fn is_accessible(&self) -> bool { - let guard = self.lock(); + let guard = self.lock_irqsave(); 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 + let guard = self.lock_irqsave(); + guard.vm_file.is_none() } /// 判断VMA是否为大页映射 @@ -1236,13 +1354,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, } @@ -1265,7 +1387,9 @@ impl VMA { pub fn new( region: VirtRegion, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, + file: Option>, + pgoff: Option, mapped: bool, ) -> Self { VMA { @@ -1276,6 +1400,8 @@ impl VMA { user_address_space: None, self_ref: Weak::default(), provider: Provider::Allocated, + vm_file: file, + file_pgoff: pgoff, } } @@ -1287,6 +1413,14 @@ impl VMA { return &self.vm_flags; } + pub fn vm_file(&self) -> Option> { + return self.vm_file.clone(); + } + + pub fn address_space(&self) -> Option> { + return self.user_address_space.clone(); + } + pub fn set_vm_flags(&mut self, vm_flags: VmFlags) { self.vm_flags = vm_flags; } @@ -1299,6 +1433,10 @@ impl VMA { self.mapped = mapped; } + pub fn set_flags(&mut self) { + self.flags = MMArch::vm_get_page_prot(self.vm_flags); + } + /// # 拷贝当前VMA的内容 /// /// ### 安全性 @@ -1313,6 +1451,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(), }; } @@ -1325,14 +1465,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()), @@ -1342,7 +1489,7 @@ impl VMA { pub fn remap( &mut self, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result<(), SystemError> { @@ -1395,7 +1542,7 @@ impl VMA { destination: VirtPageFrame, count: PageFrameCount, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result, SystemError> { @@ -1417,23 +1564,22 @@ 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, - }); + None, + None, + true, + )); // 将VMA加入到anon_vma中 let mut page_manager_guard = page_manager_lock_irqsave(); cur_phy = phys; for _ in 0..count.data() { let paddr = cur_phy.phys_address(); - let page = page_manager_guard.get_mut(&paddr); - page.insert_vma(r.clone()); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(r.clone()); cur_phy = cur_phy.next(); } @@ -1441,21 +1587,29 @@ impl VMA { } /// 从页分配器中分配一些物理页,并把它们映射到指定的虚拟地址,然后创建VMA + /// ## 参数 /// - /// @param destination 要映射到的虚拟地址 - /// @param count 要映射的页帧数量 - /// @param flags 页面标志位 - /// @param mapper 页表映射器 - /// @param flusher 页表项刷新器 + /// - `destination`: 要映射到的虚拟地址 + /// - `page_count`: 要映射的页帧数量 + /// - `vm_flags`: VMA标志位 + /// - `flags`: 页面标志位 + /// - `mapper`: 页表映射器 + /// - `flusher`: 页表项刷新器 + /// - `file`: 映射文件 + /// - `pgoff`: 返回映射后的虚拟内存区域 /// - /// @return 返回映射后的虚拟内存区域 + /// ## 返回值 + /// - 页面错误处理信息标志 + #[allow(clippy::too_many_arguments)] pub fn zeroed( destination: VirtPageFrame, page_count: PageFrameCount, vm_flags: VmFlags, - flags: PageFlags, + flags: EntryFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, + file: Option>, + pgoff: Option, ) -> Result, SystemError> { let mut cur_dest: VirtPageFrame = destination; // debug!( @@ -1482,6 +1636,8 @@ impl VMA { ), vm_flags, flags, + file, + pgoff, true, )); drop(flusher); @@ -1495,12 +1651,25 @@ impl VMA { let paddr = mapper.translate(frame.virt_address()).unwrap().0; // 将VMA加入到anon_vma - let page = page_manager_guard.get_mut(&paddr); - page.insert_vma(r.clone()); + let page = page_manager_guard.get_unwrap(&paddr); + page.write_irqsave().insert_vma(r.clone()); } // debug!("VMA::zeroed: done"); return Ok(r); } + + pub fn page_address(&self, page: &Arc) -> Result { + let page_guard = page.read_irqsave(); + let index = page_guard.index().unwrap(); + if index >= self.file_pgoff.unwrap() { + let address = + self.region.start + ((index - self.file_pgoff.unwrap()) << MMArch::PAGE_SHIFT); + if address <= self.region.end() { + return Ok(address); + } + } + return Err(SystemError::EFAULT); + } } impl Drop for VMA { diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index 3930f11f..f453673e 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -112,6 +112,7 @@ pub trait Scheduler { ); /// ## 选择接下来最适合运行的任务 + #[allow(dead_code)] fn pick_task(rq: &mut CpuRunQueue) -> Option>; /// ## 选择接下来最适合运行的任务 diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c9600fdf..7addb0c4 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1104,6 +1104,12 @@ impl Syscall { Self::shmctl(id, cmd, user_buf, from_user) } + SYS_MSYNC => { + let start = page_align_up(args[0]); + let len = page_align_up(args[1]); + let flags = args[2]; + Self::msync(VirtAddr::new(start), len, flags) + } SYS_UTIMENSAT => Self::sys_utimensat( args[0] as i32, args[1] as *const u8, 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); diff --git a/user/apps/test_filemap/.gitignore b/user/apps/test_filemap/.gitignore new file mode 100644 index 00000000..6c6e1f91 --- /dev/null +++ b/user/apps/test_filemap/.gitignore @@ -0,0 +1 @@ +test_filemap \ No newline at end of file diff --git a/user/apps/test_filemap/Makefile b/user/apps/test_filemap/Makefile new file mode 100644 index 00000000..c635a86f --- /dev/null +++ b/user/apps/test_filemap/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_filemap main.c + +.PHONY: install clean +install: all + mv test_filemap $(DADK_CURRENT_BUILD_DIR)/test_filemap + +clean: + rm test_filemap *.o + +fmt: diff --git a/user/apps/test_filemap/main.c b/user/apps/test_filemap/main.c new file mode 100644 index 00000000..e96fa19c --- /dev/null +++ b/user/apps/test_filemap/main.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + // 打开文件 + int fd = open("example.txt", O_RDWR | O_CREAT | O_TRUNC, 0777); + + if (fd == -1) + { + perror("open"); + exit(EXIT_FAILURE); + } + + write(fd, "HelloWorld!", 11); + char buf[12]; + buf[11] = '\0'; + close(fd); + + fd = open("example.txt", O_RDWR); + read(fd, buf, 11); + printf("File content: %s\n", buf); + + // 将文件映射到内存 + void *map = mmap(NULL, 11, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + perror("mmap"); + close(fd); + exit(EXIT_FAILURE); + } + printf("mmap address: %p\n", map); + + // 关闭文件描述符 + // close(fd); + + // 访问和修改文件内容 + char *fileContent = (char *)map; + printf("change 'H' to 'G'\n"); + fileContent[0] = 'G'; // 修改第一个字符为 'G' + printf("mmap content: %s\n", fileContent); + + // 解除映射 + printf("unmap\n"); + if (munmap(map, 11) == -1) + { + perror("munmap"); + exit(EXIT_FAILURE); + } + + fd = open("example.txt", O_RDWR); + read(fd, buf, 11); + printf("File content: %s\n", buf); + + return 0; +} diff --git a/user/dadk/config/test_filemap-0.1.0.dadk b/user/dadk/config/test_filemap-0.1.0.dadk new file mode 100644 index 00000000..2a7becb6 --- /dev/null +++ b/user/dadk/config/test_filemap-0.1.0.dadk @@ -0,0 +1,23 @@ +{ + "name": "test_filemap", + "version": "0.1.0", + "description": "测试filemap", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_filemap" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "clean": { + "clean_command": "make clean" + }, + "install": { + "in_dragonos_path": "/bin" + }, + "target_arch": ["x86_64"] +}