Ver código fonte

update 20240604 0233

MemoryShore 10 meses atrás
pai
commit
95c37e409a
3 arquivos alterados com 184 adições e 23 exclusões
  1. 16 2
      kernel/src/mm/fault.rs
  2. 35 14
      kernel/src/mm/syscall.rs
  3. 133 7
      kernel/src/mm/ucontext.rs

+ 16 - 2
kernel/src/mm/fault.rs

@@ -197,6 +197,9 @@ impl PageFaultHandler {
         pfm: PageFaultMessage,
         mapper: &mut PageMapper,
     ) -> VmFaultReason {
+        if pfm.address.data() == 0x10000 {
+            log::info!("handle_pte_fault: {:?}", pfm);
+        }
         let address = pfm.address_aligned_down();
         let flags = pfm.flags;
         let vma = pfm.vma.clone();
@@ -271,6 +274,7 @@ impl PageFaultHandler {
     /// - VmFaultReason: 页面错误处理信息标志
     #[allow(unused_variables)]
     pub unsafe fn do_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
+        log::info!("do_fault");
         // panic!(
         //     "do_fault has not yet been implemented,
         // fault message: {:?},
@@ -328,6 +332,7 @@ impl PageFaultHandler {
         // );
 
         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault
+        log::info!("do_read_fault");
         let ret = Self::do_fault_around(pfm.clone(), mapper);
         if !ret.is_empty() {
             return ret;
@@ -510,7 +515,11 @@ impl PageFaultHandler {
     ) -> VmFaultReason {
         let vma = pfm.vma();
         let vma_guard = vma.lock();
-        let file = vma_guard.vm_file().expect("no vm_file in vma");
+        let file = vma_guard
+            .vm_file()
+            .expect("no vm_file in vma")
+            .upgrade()
+            .expect("struct file not exist");
         let page_cache = file.inode().page_cache().unwrap();
 
         // 起始页地址
@@ -544,9 +553,14 @@ impl PageFaultHandler {
     }
 
     pub unsafe fn filemap_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
+        log::info!("filemap_fault");
         let vma = pfm.vma();
         let vma_guard = vma.lock();
-        let file = vma_guard.vm_file().expect("no vm_file in vma");
+        let file = vma_guard
+            .vm_file()
+            .expect("no vm_file in vma")
+            .upgrade()
+            .expect("struct file not exist");
         let mut page_cache = file.inode().page_cache().unwrap();
         let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
 

+ 35 - 14
kernel/src/mm/syscall.rs

@@ -296,8 +296,8 @@ impl Syscall {
         len: usize,
         prot_flags: usize,
         map_flags: usize,
-        _fd: i32,
-        _offset: usize,
+        fd: i32,
+        offset: usize,
     ) -> Result<usize, SystemError> {
         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
@@ -312,10 +312,10 @@ 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_ANONYMOUS) {
+        //     error!("mmap: not support file mapping");
+        //     return Err(SystemError::ENOSYS);
+        // }
 
         // 暂时不支持巨页映射
         if map_flags.contains(MapFlags::MAP_HUGETLB) {
@@ -323,14 +323,35 @@ 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,
+            )?
+        };
+        // let start_page = current_address_space.write().map_anonymous(
+        //     start_vaddr,
+        //     len,
+        //     prot_flags,
+        //     map_flags,
+        //     true,
+        //     false,
+        // )?;
         return Ok(start_page.virt_address().data());
     }
 

+ 133 - 7
kernel/src/mm/ucontext.rs

@@ -290,7 +290,7 @@ impl InnerAddressSpace {
                 prot_flags,
                 map_flags,
                 move |page, count, flags, mapper, flusher| {
-                    VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)
+                    VMA::zeroed(page, count, vm_flags, flags, mapper, flusher, None, None)
                 },
             )?
         } else {
@@ -304,6 +304,8 @@ impl InnerAddressSpace {
                         VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE),
                         vm_flags,
                         flags,
+                        None,
+                        None,
                         false,
                     )))
                 },
@@ -313,6 +315,122 @@ impl InnerAddressSpace {
         return Ok(start_page);
     }
 
+    /// 进行文件页映射
+    ///
+    /// ## 参数
+    ///
+    /// - `start_vaddr`:映射的起始地址
+    /// - `len`:映射的长度
+    /// - `prot_flags`:保护标志
+    /// - `map_flags`:映射标志
+    /// - `round_to_min`:是否将`start_vaddr`对齐到`mmap_min`,如果为`true`,则当`start_vaddr`不为0时,会对齐到`mmap_min`,否则仅向下对齐到页边界
+    /// - `allocate_at_once`:是否立即分配物理空间
+    ///
+    /// ## 返回
+    ///
+    /// 返回映射的起始虚拟页帧
+    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<VirtPageFrame, SystemError> {
+        log::info!("file_mapping");
+        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);
+
+        let file = Arc::downgrade(&file.unwrap());
+
+        // offset需要4K对齐
+        if !offset & (MMArch::PAGE_SIZE - 1) == 0 {
+            return Err(SystemError::EINVAL);
+        }
+        let pgoff = offset >> MMArch::PAGE_SHIFT;
+
+        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,
+                        Some(file),
+                        Some(pgoff),
+                    )
+                },
+            )?
+        } else {
+            self.mmap(
+                round_hint_to_min(start_vaddr),
+                PageFrameCount::from_bytes(len).unwrap(),
+                prot_flags,
+                map_flags,
+                move |page, count, flags, _mapper, _flusher| {
+                    Ok(LockedVMA::new(VMA::new(
+                        VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE),
+                        vm_flags,
+                        flags,
+                        Some(file),
+                        Some(pgoff),
+                        false,
+                    )))
+                },
+            )?
+        };
+        return Ok(start_page);
+    }
+
     /// 向进程的地址空间映射页面
     ///
     /// # 参数
@@ -1188,8 +1306,8 @@ impl LockedVMA {
 
     /// 判断VMA是否为匿名映射
     pub fn is_anonymous(&self) -> bool {
-        //TODO: 实现匿名映射判断逻辑,目前仅支持匿名映射
-        true
+        let guard = self.lock();
+        guard.vm_file.is_none()
     }
 
     /// 判断VMA是否为大页映射
@@ -1241,7 +1359,7 @@ pub struct VMA {
     user_address_space: Option<Weak<AddressSpace>>,
     self_ref: Weak<LockedVMA>,
 
-    vm_file: Option<Arc<File>>,
+    vm_file: Option<Weak<File>>,
     /// VMA映射的文件部分相对于整个文件的偏移页数
     file_pgoff: Option<usize>,
 
@@ -1268,6 +1386,8 @@ impl VMA {
         region: VirtRegion,
         vm_flags: VmFlags,
         flags: EntryFlags<MMArch>,
+        file: Option<Weak<File>>,
+        pgoff: Option<usize>,
         mapped: bool,
     ) -> Self {
         VMA {
@@ -1278,8 +1398,8 @@ impl VMA {
             user_address_space: None,
             self_ref: Weak::default(),
             provider: Provider::Allocated,
-            file_pgoff: None,
-            vm_file: None,
+            vm_file: file,
+            file_pgoff: pgoff,
         }
     }
 
@@ -1291,7 +1411,7 @@ impl VMA {
         return &self.vm_flags;
     }
 
-    pub fn vm_file(&self) -> Option<Arc<File>> {
+    pub fn vm_file(&self) -> Option<Weak<File>> {
         return self.vm_file.clone();
     }
 
@@ -1438,6 +1558,8 @@ impl VMA {
             VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE),
             vm_flags,
             flags,
+            None,
+            None,
             true,
         ));
 
@@ -1470,6 +1592,8 @@ impl VMA {
         flags: EntryFlags<MMArch>,
         mapper: &mut PageMapper,
         mut flusher: impl Flusher<MMArch>,
+        file: Option<Weak<File>>,
+        pgoff: Option<usize>,
     ) -> Result<Arc<LockedVMA>, SystemError> {
         let mut cur_dest: VirtPageFrame = destination;
         // debug!(
@@ -1496,6 +1620,8 @@ impl VMA {
             ),
             vm_flags,
             flags,
+            file,
+            pgoff,
             true,
         ));
         drop(flusher);