Jelajahi Sumber

feat(mm):添加MAP_FIXED处理 (#804)

* fix(mm):优化extract中对before和after VMA映射情况的判断 (#802)

* 添加mmap对MAP_FIXED的处理 (#706)
Jomo 1 tahun lalu
induk
melakukan
62da39bb0c
1 mengubah file dengan 51 tambahan dan 41 penghapusan
  1. 51 41
      kernel/src/mm/ucontext.rs

+ 51 - 41
kernel/src/mm/ucontext.rs

@@ -353,8 +353,7 @@ impl InnerAddressSpace {
         // 找到未使用的区域
         let region = match addr {
             Some(vaddr) => {
-                self.mappings
-                    .find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)?
+                self.find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)?
             }
             None => self
                 .mappings
@@ -693,6 +692,56 @@ impl InnerAddressSpace {
 
         return self.set_brk(new_brk);
     }
+
+    pub fn find_free_at(
+        &mut self,
+        min_vaddr: VirtAddr,
+        vaddr: VirtAddr,
+        size: usize,
+        flags: MapFlags,
+    ) -> Result<VirtRegion, SystemError> {
+        // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。
+        if vaddr == VirtAddr::new(0) {
+            return self
+                .mappings
+                .find_free(min_vaddr, size)
+                .ok_or(SystemError::ENOMEM);
+        }
+
+        // 如果指定了地址,那么就检查指定的地址是否可用。
+        let requested = VirtRegion::new(vaddr, size);
+
+        if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) {
+            return Err(SystemError::EINVAL);
+        }
+
+        let intersect_vma = self.mappings.conflicts(requested).next();
+        if let Some(vma) = intersect_vma {
+            if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
+                // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正
+                return Err(SystemError::EEXIST);
+            }
+
+            if flags.contains(MapFlags::MAP_FIXED) {
+                // 对已有的VMA进行覆盖
+                let intersect_region = vma.lock().region.intersect(&requested).unwrap();
+                self.munmap(
+                    VirtPageFrame::new(intersect_region.start),
+                    PageFrameCount::from_bytes(intersect_region.size).unwrap(),
+                )?;
+                return Ok(requested);
+            }
+
+            // 如果没有指定MAP_FIXED标志,那么就对地址做修正
+            let requested = self
+                .mappings
+                .find_free(min_vaddr, size)
+                .ok_or(SystemError::ENOMEM)?;
+            return Ok(requested);
+        }
+
+        return Ok(requested);
+    }
 }
 
 impl Drop for InnerAddressSpace {
@@ -844,45 +893,6 @@ impl UserMappings {
         return Some(region);
     }
 
-    pub fn find_free_at(
-        &self,
-        min_vaddr: VirtAddr,
-        vaddr: VirtAddr,
-        size: usize,
-        flags: MapFlags,
-    ) -> Result<VirtRegion, SystemError> {
-        // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。
-        if vaddr == VirtAddr::new(0) {
-            return self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM);
-        }
-
-        // 如果指定了地址,那么就检查指定的地址是否可用。
-
-        let requested = VirtRegion::new(vaddr, size);
-
-        if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) {
-            return Err(SystemError::EINVAL);
-        }
-
-        if let Some(_x) = self.conflicts(requested).next() {
-            if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
-                // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正
-                return Err(SystemError::EEXIST);
-            }
-
-            if flags.contains(MapFlags::MAP_FIXED) {
-                // todo: 支持MAP_FIXED标志对已有的VMA进行覆盖
-                return Err(SystemError::ENOSYS);
-            }
-
-            // 如果没有指定MAP_FIXED标志,那么就对地址做修正
-            let requested = self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM)?;
-            return Ok(requested);
-        }
-
-        return Ok(requested);
-    }
-
     /// 在当前进程的地址空间中,保留一个指定大小的区域,使得该区域不在空洞中。
     /// 该函数会修改vm_holes中的空洞信息。
     ///