From 4cfa009b87c8431a41fab740ffdbd7b008965c9a Mon Sep 17 00:00:00 2001 From: Jomo Date: Mon, 19 Feb 2024 14:54:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0mremap=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E8=B0=83=E7=94=A8=20(#518)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * mremap系统调用 --- kernel/src/mm/mod.rs | 39 +++++++++ kernel/src/mm/syscall.rs | 176 +++++++++++++++++++++++++++++++++++++- kernel/src/mm/ucontext.rs | 121 +++++++++++++++++++++++++- kernel/src/syscall/mod.rs | 10 +++ 4 files changed, 342 insertions(+), 4 deletions(-) diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 23229b11..8a0c1e39 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -35,6 +35,45 @@ pub mod ucontext; /// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化) static mut __INITIAL_PROCESS_ADDRESS_SPACE: Option> = None; +bitflags! { + /// Virtual memory flags + pub struct VmFlags:u32{ + const VM_NONE = 0x00000000; + + const VM_READ = 0x00000001; + const VM_WRITE = 0x00000002; + const VM_EXEC = 0x00000004; + const VM_SHARED = 0x00000008; + + const VM_MAYREAD = 0x00000010; + const VM_MAYWRITE = 0x00000020; + const VM_MAYEXEC = 0x00000040; + const VM_MAYSHARE = 0x00000080; + + const VM_GROWSDOWN = 0x00000100; + const VM_UFFD_MISSING = 0x00000200; + const VM_PFNMAP = 0x00000400; + const VM_UFFD_WP = 0x00001000; + + const VM_LOCKED = 0x00002000; + const VM_IO = 0x00004000; + + const VM_SEQ_READ = 0x00008000; + const VM_RAND_READ = 0x00010000; + + const VM_DONTCOPY = 0x00020000; + const VM_DONTEXPAND = 0x00040000; + const VM_LOCKONFAULT = 0x00080000; + const VM_ACCOUNT = 0x00100000; + const VM_NORESERVE = 0x00200000; + const VM_HUGETLB = 0x00400000; + const VM_SYNC = 0x00800000; + const VM_ARCH_1 = 0x01000000; + const VM_WIPEONFORK = 0x02000000; + const VM_DONTDUMP = 0x04000000; + } +} + /// 获取内核INIT进程的用户地址空间结构体 #[allow(non_snake_case)] #[inline(always)] diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs index 76934b9e..4d0cde0d 100644 --- a/kernel/src/mm/syscall.rs +++ b/kernel/src/mm/syscall.rs @@ -14,7 +14,7 @@ use crate::{ use super::{ allocator::page_frame::{PageFrameCount, VirtPageFrame}, ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, - verify_area, VirtAddr, + verify_area, VirtAddr, VmFlags, }; bitflags! { @@ -63,7 +63,93 @@ bitflags! { /// For anonymous mmap, memory could be uninitialized const MAP_UNINITIALIZED = 0x4000000; + } + /// Memory mremapping flags + pub struct MremapFlags: u8 { + const MREMAP_MAYMOVE = 1; + const MREMAP_FIXED = 2; + const MREMAP_DONTUNMAP = 4; + } +} + +impl From for VmFlags { + fn from(map_flags: MapFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if map_flags.contains(MapFlags::MAP_GROWSDOWN) { + vm_flags |= VmFlags::VM_GROWSDOWN; + } + + if map_flags.contains(MapFlags::MAP_LOCKED) { + vm_flags |= VmFlags::VM_LOCKED; + } + + if map_flags.contains(MapFlags::MAP_SYNC) { + vm_flags |= VmFlags::VM_SYNC; + } + + vm_flags + } +} + +impl From for VmFlags { + fn from(prot_flags: ProtFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if prot_flags.contains(ProtFlags::PROT_READ) { + vm_flags |= VmFlags::VM_READ; + } + + if prot_flags.contains(ProtFlags::PROT_WRITE) { + vm_flags |= VmFlags::VM_WRITE; + } + + if prot_flags.contains(ProtFlags::PROT_EXEC) { + vm_flags |= VmFlags::VM_EXEC; + } + + vm_flags + } +} + +impl Into for VmFlags { + fn into(self) -> MapFlags { + let mut map_flags = MapFlags::MAP_NONE; + + if self.contains(VmFlags::VM_GROWSDOWN) { + map_flags |= MapFlags::MAP_GROWSDOWN; + } + + if self.contains(VmFlags::VM_LOCKED) { + map_flags |= MapFlags::MAP_LOCKED; + } + + if self.contains(VmFlags::VM_SYNC) { + map_flags |= MapFlags::MAP_SYNC; + } + + map_flags + } +} + +impl Into for VmFlags { + fn into(self) -> ProtFlags { + let mut prot_flags = ProtFlags::PROT_NONE; + + if self.contains(VmFlags::VM_READ) { + prot_flags |= ProtFlags::PROT_READ; + } + + if self.contains(VmFlags::VM_WRITE) { + prot_flags |= ProtFlags::PROT_WRITE; + } + + if self.contains(VmFlags::VM_EXEC) { + prot_flags |= ProtFlags::PROT_EXEC; + } + + prot_flags } } @@ -156,6 +242,93 @@ impl Syscall { return Ok(start_page.virt_address().data()); } + /// ## mremap系统调用 + /// + /// + /// ## 参数 + /// + /// - `old_vaddr`:原映射的起始地址 + /// - `old_len`:原映射的长度 + /// - `new_len`:重新映射的长度 + /// - `mremap_flags`:重映射标志 + /// - `new_vaddr`:重新映射的起始地址 + /// + /// ## 返回值 + /// + /// 成功时返回重映射的起始地址,失败时返回错误码 + pub fn mremap( + old_vaddr: VirtAddr, + old_len: usize, + new_len: usize, + mremap_flags: MremapFlags, + new_vaddr: VirtAddr, + ) -> Result { + // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 + if mremap_flags.contains(MremapFlags::MREMAP_FIXED) + && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) + || new_vaddr == VirtAddr::new(0)) + { + return Err(SystemError::EINVAL); + } + + // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 + if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) + && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) + { + return Err(SystemError::EINVAL); + } + + // 旧内存地址必须对齐 + if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + // 将old_len、new_len 对齐页面大小 + let old_len = page_align_up(old_len); + let new_len = page_align_up(new_len); + + // 不允许重映射内存区域大小为0 + if new_len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space = AddressSpace::current()?; + let vma = current_address_space.read().mappings.contains(old_vaddr); + if vma.is_none() { + return Err(SystemError::EINVAL); + } + let vma = vma.unwrap(); + let vm_flags = vma.lock().vm_flags().clone(); + + // 暂时不支持巨页映射 + if vm_flags.contains(VmFlags::VM_HUGETLB) { + kerror!("mmap: not support huge page mapping"); + return Err(SystemError::ENOSYS); + } + + // 缩小旧内存映射区域 + if old_len > new_len { + Self::munmap(old_vaddr + new_len, old_len - new_len)?; + return Ok(old_vaddr.data()); + } + + // 重映射到新内存区域 + let r = current_address_space.write().mremap( + old_vaddr, + old_len, + new_len, + mremap_flags, + new_vaddr, + vm_flags, + )?; + + if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { + Self::munmap(old_vaddr, old_len)?; + } + + return Ok(r.data()); + } + /// ## munmap系统调用 /// /// ## 参数 @@ -185,6 +358,7 @@ impl Syscall { .write() .munmap(start_frame, page_count) .map_err(|_| SystemError::EINVAL)?; + return Ok(0); } diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 4813dd34..10ef700d 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -25,6 +25,7 @@ use crate::{ spinlock::{SpinLock, SpinLockGuard}, }, process::ProcessManager, + syscall::user_access::{UserBufferReader, UserBufferWriter}, }; use super::{ @@ -32,8 +33,8 @@ use super::{ deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter, }, page::{Flusher, InactiveFlusher, PageFlags, PageFlushAll}, - syscall::{MapFlags, ProtFlags}, - MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, + syscall::{MapFlags, MremapFlags, ProtFlags}, + MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags, }; /// MMAP_MIN_ADDR的默认值 @@ -177,6 +178,7 @@ impl InnerAddressSpace { let new_vma = VMA::zeroed( VirtPageFrame::new(vma_guard.region.start()), PageFrameCount::new(vma_guard.region.size() / MMArch::PAGE_SIZE), + vma_guard.vm_flags().clone(), tmp_flags, &mut new_guard.user_mapper.utable, (), @@ -271,6 +273,12 @@ impl InnerAddressSpace { 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; + // kdebug!("map_anonymous: len = {}", len); let start_page: VirtPageFrame = self.mmap( @@ -279,7 +287,7 @@ impl InnerAddressSpace { prot_flags, map_flags, move |page, count, flags, mapper, flusher| { - Ok(VMA::zeroed(page, count, flags, mapper, flusher)?) + Ok(VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)?) }, )?; @@ -362,6 +370,76 @@ impl InnerAddressSpace { return Ok(page); } + /// 重映射内存区域 + /// + /// # 参数 + /// + /// - `old_vaddr`:原映射的起始地址 + /// - `old_len`:原映射的长度 + /// - `new_len`:重新映射的长度 + /// - `mremap_flags`:重映射标志 + /// - `new_vaddr`:重新映射的起始地址 + /// - `vm_flags`:旧内存区域标志 + /// + /// # Returns + /// + /// 返回重映射的起始虚拟页帧地址 + /// + /// # Errors + /// + /// - `EINVAL`:参数错误 + pub fn mremap( + &mut self, + old_vaddr: VirtAddr, + old_len: usize, + new_len: usize, + mremap_flags: MremapFlags, + new_vaddr: VirtAddr, + vm_flags: VmFlags, + ) -> Result { + // 检查新内存地址是否对齐 + if !new_vaddr.check_aligned(MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + // 检查新、旧内存区域是否冲突 + let old_region = VirtRegion::new(old_vaddr, old_len); + let new_region = VirtRegion::new(new_vaddr, new_len); + if old_region.collide(&new_region) { + return Err(SystemError::EINVAL); + } + + // 取消新内存区域的原映射 + if mremap_flags.contains(MremapFlags::MREMAP_FIXED) { + let start_page = VirtPageFrame::new(new_vaddr); + let page_count = PageFrameCount::from_bytes(new_len).unwrap(); + self.munmap(start_page, page_count)?; + } + + // 初始化映射标志 + let map_flags: MapFlags = vm_flags.into(); + // 初始化内存区域保护标志 + let prot_flags: ProtFlags = vm_flags.into(); + + // 获取映射后的新内存页面 + let new_page = self.map_anonymous(new_vaddr, new_len, prot_flags, map_flags, true)?; + let new_page_vaddr = new_page.virt_address(); + + // 拷贝旧内存区域内容到新内存区域 + let old_buffer_reader = + UserBufferReader::new(old_vaddr.data() as *const u8, old_len, true)?; + let old_buf: &[u8] = old_buffer_reader.read_from_user(0)?; + let mut new_buffer_writer = + UserBufferWriter::new(new_page_vaddr.data() as *mut u8, new_len, true)?; + let new_buf: &mut [u8] = new_buffer_writer.buffer(0)?; + let len = old_buf.len().min(new_buf.len()); + for i in 0..len { + new_buf[i] = old_buf[i]; + } + + return Ok(new_page_vaddr); + } + /// 取消进程的地址空间中的映射 /// /// # 参数 @@ -660,6 +738,7 @@ impl UserMappings { // 创建一个新的虚拟内存范围。 let region = VirtRegion::new(cmp::max(*hole_vaddr, min_vaddr), *size); + return Some(region); } @@ -943,6 +1022,8 @@ impl LockedVMA { pub struct VMA { /// 虚拟内存区域对应的虚拟地址范围 region: VirtRegion, + /// 虚拟内存区域标志 + vm_flags: VmFlags, /// VMA内的页帧的标志 flags: PageFlags, /// VMA内的页帧是否已经映射到页表 @@ -970,10 +1051,39 @@ pub enum Provider { #[allow(dead_code)] impl VMA { + pub fn new( + region: VirtRegion, + vm_flags: VmFlags, + flags: PageFlags, + mapped: bool, + ) -> Self { + VMA { + region, + vm_flags, + flags, + mapped, + user_address_space: None, + self_ref: Weak::default(), + provider: Provider::Allocated, + } + } + pub fn region(&self) -> &VirtRegion { return &self.region; } + pub fn vm_flags(&self) -> &VmFlags { + return &self.vm_flags; + } + + pub fn set_vm_flags(&mut self, vm_flags: VmFlags) { + self.vm_flags = vm_flags; + } + + pub fn set_region_size(&mut self, new_region_size: usize) { + self.region.set_size(new_region_size); + } + /// # 拷贝当前VMA的内容 /// /// ### 安全性 @@ -982,6 +1092,7 @@ impl VMA { pub unsafe fn clone(&self) -> Self { return Self { region: self.region, + vm_flags: self.vm_flags, flags: self.flags, mapped: self.mapped, user_address_space: self.user_address_space.clone(), @@ -1057,6 +1168,7 @@ impl VMA { phys: PhysPageFrame, destination: VirtPageFrame, count: PageFrameCount, + vm_flags: VmFlags, flags: PageFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, @@ -1086,6 +1198,7 @@ impl VMA { let r: Arc = LockedVMA::new(VMA { region: VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE), + vm_flags, flags, mapped: true, user_address_space: None, @@ -1107,6 +1220,7 @@ impl VMA { pub fn zeroed( destination: VirtPageFrame, page_count: PageFrameCount, + vm_flags: VmFlags, flags: PageFlags, mapper: &mut PageMapper, mut flusher: impl Flusher, @@ -1135,6 +1249,7 @@ impl VMA { destination.virt_address(), page_count.data() * MMArch::PAGE_SIZE, ), + vm_flags, flags, mapped: true, user_address_space: None, diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 94e92211..1a74881f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -7,6 +7,7 @@ use crate::{ arch::{ipc::signal::SigSet, syscall::nr::*}, driver::base::device::device_number::DeviceNumber, libs::{futex::constant::FutexFlag, rand::GRandFlags}, + mm::syscall::MremapFlags, net::syscall::MsgHdr, process::{ fork::KernelCloneArgs, @@ -612,6 +613,15 @@ impl Syscall { ) } } + SYS_MREMAP => { + let old_vaddr = VirtAddr::new(args[0]); + let old_len = args[1]; + let new_len = args[2]; + let mremap_flags = MremapFlags::from_bits_truncate(args[3] as u8); + let new_vaddr = VirtAddr::new(args[4]); + + Self::mremap(old_vaddr, old_len, new_len, mremap_flags, new_vaddr) + } SYS_MUNMAP => { let addr = args[0]; let len = page_align_up(args[1]);