Browse Source

实现mremap系统调用 (#518)

* mremap系统调用
Jomo 1 year ago
parent
commit
4cfa009b87
4 changed files with 342 additions and 4 deletions
  1. 39 0
      kernel/src/mm/mod.rs
  2. 175 1
      kernel/src/mm/syscall.rs
  3. 118 3
      kernel/src/mm/ucontext.rs
  4. 10 0
      kernel/src/syscall/mod.rs

+ 39 - 0
kernel/src/mm/mod.rs

@@ -35,6 +35,45 @@ pub mod ucontext;
 /// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化)
 static mut __INITIAL_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = 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)]

+ 175 - 1
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<MapFlags> 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<ProtFlags> 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<MapFlags> 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<ProtFlags> 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<usize, SystemError> {
+        // 需要重映射到新内存区域的情况下,必须包含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);
     }
 

+ 118 - 3
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<VirtAddr, SystemError> {
+        // 检查新内存地址是否对齐
+        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<MMArch>,
     /// VMA内的页帧是否已经映射到页表
@@ -970,10 +1051,39 @@ pub enum Provider {
 
 #[allow(dead_code)]
 impl VMA {
+    pub fn new(
+        region: VirtRegion,
+        vm_flags: VmFlags,
+        flags: PageFlags<MMArch>,
+        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<MMArch>,
         mapper: &mut PageMapper,
         mut flusher: impl Flusher<MMArch>,
@@ -1086,6 +1198,7 @@ impl VMA {
 
         let r: Arc<LockedVMA> = 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<MMArch>,
         mapper: &mut PageMapper,
         mut flusher: impl Flusher<MMArch>,
@@ -1135,6 +1249,7 @@ impl VMA {
                 destination.virt_address(),
                 page_count.data() * MMArch::PAGE_SIZE,
             ),
+            vm_flags,
             flags,
             mapped: true,
             user_address_space: None,

+ 10 - 0
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]);