From 0b358b9db50c2780cad8434286603843e6a4ac89 Mon Sep 17 00:00:00 2001 From: kaleidoscope416 <2448956191@qq.com> Date: Thu, 5 Jun 2025 20:06:57 +0800 Subject: [PATCH] =?UTF-8?q?refactor(mm/syscall):=20=E9=87=8D=E6=9E=84mm?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8=20(#1185?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(mm/syscall): 把sys_brk加到调用表 * refactor(mm/syscall): 把sys_sbrk加到调用表 * refactor(mm/syscall): 把sys_mmap加到调用表 * refactor(mm/syscall): 把sys_munmap加到调用表 * refactor(mm/syscall): 把sys_mremap加到调用表 * refactor(mm/syscall): 把sys_mprotect加到调用表 * refactor(mm/syscall): 把sys_madvise加到调用表 * refactor(mm/syscall): 把sys_msync加到调用表 --- kernel/src/mm/syscall.rs | 654 -------------------------- kernel/src/mm/syscall/mod.rs | 245 ++++++++++ kernel/src/mm/syscall/sys_brk.rs | 68 +++ kernel/src/mm/syscall/sys_madvise.rs | 84 ++++ kernel/src/mm/syscall/sys_mmap.rs | 137 ++++++ kernel/src/mm/syscall/sys_mprotect.rs | 83 ++++ kernel/src/mm/syscall/sys_mremap.rs | 145 ++++++ kernel/src/mm/syscall/sys_msync.rs | 158 +++++++ kernel/src/mm/syscall/sys_munmap.rs | 89 ++++ kernel/src/mm/syscall/sys_sbrk.rs | 53 +++ kernel/src/syscall/mod.rs | 79 +--- 11 files changed, 1066 insertions(+), 729 deletions(-) delete mode 100644 kernel/src/mm/syscall.rs create mode 100644 kernel/src/mm/syscall/mod.rs create mode 100644 kernel/src/mm/syscall/sys_brk.rs create mode 100644 kernel/src/mm/syscall/sys_madvise.rs create mode 100644 kernel/src/mm/syscall/sys_mmap.rs create mode 100644 kernel/src/mm/syscall/sys_mprotect.rs create mode 100644 kernel/src/mm/syscall/sys_mremap.rs create mode 100644 kernel/src/mm/syscall/sys_msync.rs create mode 100644 kernel/src/mm/syscall/sys_munmap.rs create mode 100644 kernel/src/mm/syscall/sys_sbrk.rs diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs deleted file mode 100644 index 66720d41..00000000 --- a/kernel/src/mm/syscall.rs +++ /dev/null @@ -1,654 +0,0 @@ -use core::{intrinsics::unlikely, slice::from_raw_parts}; - -use alloc::sync::Arc; -use log::error; -use system_error::SystemError; - -use crate::{ - arch::MMArch, - driver::base::block::SeekFrom, - ipc::shm::ShmFlags, - libs::align::{check_aligned, page_align_up}, - mm::MemoryManagementArch, - syscall::Syscall, -}; - -use super::{ - allocator::page_frame::{PageFrameCount, VirtPageFrame}, - ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, - verify_area, MsFlags, VirtAddr, VmFlags, -}; - -bitflags! { - /// Memory protection flags - pub struct ProtFlags: u64 { - const PROT_NONE = 0x0; - const PROT_READ = 0x1; - const PROT_WRITE = 0x2; - const PROT_EXEC = 0x4; - } - - /// Memory mapping flags - pub struct MapFlags: u64 { - const MAP_NONE = 0x0; - /// share changes - const MAP_SHARED = 0x1; - /// changes are private - const MAP_PRIVATE = 0x2; - /// Interpret addr exactly - const MAP_FIXED = 0x10; - /// don't use a file - const MAP_ANONYMOUS = 0x20; - // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 - /// stack-like segment - const MAP_GROWSDOWN = 0x100; - /// ETXTBSY - const MAP_DENYWRITE = 0x800; - /// Mark it as an executable - const MAP_EXECUTABLE = 0x1000; - /// Pages are locked - const MAP_LOCKED = 0x2000; - /// don't check for reservations - const MAP_NORESERVE = 0x4000; - /// populate (prefault) pagetables - const MAP_POPULATE = 0x8000; - /// do not block on IO - const MAP_NONBLOCK = 0x10000; - /// give out an address that is best suited for process/thread stacks - const MAP_STACK = 0x20000; - /// create a huge page mapping - const MAP_HUGETLB = 0x40000; - /// perform synchronous page faults for the mapping - const MAP_SYNC = 0x80000; - /// MAP_FIXED which doesn't unmap underlying mapping - const MAP_FIXED_NOREPLACE = 0x100000; - - /// 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; - } - - - pub struct MadvFlags: u64 { - /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 - const MADV_NORMAL = 0; - /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 - const MADV_RANDOM = 1; - /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 - const MADV_SEQUENTIAL = 2; - /// 通知系统预读某些页面,用于应用程序提前准备数据 - const MADV_WILLNEED = 3; - /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 - const MADV_DONTNEED = 4; - - /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 - const MADV_FREE = 8; - /// 应用程序请求释放指定范围的页面和相关的后备存储 - const MADV_REMOVE = 9; - /// 在 fork 时排除指定区域 - const MADV_DONTFORK = 10; - /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 - const MADV_DOFORK = 11; - /// 模拟内存硬件错误,触发内存错误处理器处理 - const MADV_HWPOISON = 100; - /// 尝试软下线指定的内存范围 - const MADV_SOFT_OFFLINE = 101; - - /// 应用程序建议内核尝试合并指定范围内内容相同的页面 - const MADV_MERGEABLE = 12; - /// 取消 MADV_MERGEABLE 的效果,不再合并页面 - const MADV_UNMERGEABLE = 13; - - /// 应用程序希望将指定范围以透明大页方式支持 - const MADV_HUGEPAGE = 14; - /// 将指定范围标记为不值得用透明大页支持 - const MADV_NOHUGEPAGE = 15; - - /// 应用程序请求在核心转储时排除指定范围内的页面 - const MADV_DONTDUMP = 16; - /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 - const MADV_DODUMP = 17; - - /// 在 fork 时将子进程的该区域内存填充为零 - const MADV_WIPEONFORK = 18; - /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 - const MADV_KEEPONFORK = 19; - - /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 - const MADV_COLD = 20; - /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 - const MADV_PAGEOUT = 21; - - /// 预先填充页面表,可读,通过触发读取故障 - const MADV_POPULATE_READ = 22; - /// 预先填充页面表,可写,通过触发写入故障 - const MADV_POPULATE_WRITE = 23; - - /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 - const MADV_DONTNEED_LOCKED = 24; - - /// 同步将页面合并为新的透明大页 - const MADV_COLLAPSE = 25; - - } -} - -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; - } - - if map_flags.contains(MapFlags::MAP_SHARED) { - vm_flags |= VmFlags::VM_SHARED; - } - - 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 From for VmFlags { - fn from(shm_flags: ShmFlags) -> Self { - let mut vm_flags = VmFlags::VM_NONE; - - if shm_flags.contains(ShmFlags::SHM_RDONLY) { - vm_flags |= VmFlags::VM_READ; - } else { - vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; - } - - if shm_flags.contains(ShmFlags::SHM_EXEC) { - vm_flags |= VmFlags::VM_EXEC; - } - - if shm_flags.contains(ShmFlags::SHM_HUGETLB) { - vm_flags |= VmFlags::VM_HUGETLB; - } - - vm_flags - } -} - -impl From for MapFlags { - fn from(value: VmFlags) -> Self { - let mut map_flags = MapFlags::MAP_NONE; - - if value.contains(VmFlags::VM_GROWSDOWN) { - map_flags |= MapFlags::MAP_GROWSDOWN; - } - - if value.contains(VmFlags::VM_LOCKED) { - map_flags |= MapFlags::MAP_LOCKED; - } - - if value.contains(VmFlags::VM_SYNC) { - map_flags |= MapFlags::MAP_SYNC; - } - - if value.contains(VmFlags::VM_MAYSHARE) { - map_flags |= MapFlags::MAP_SHARED; - } - - map_flags - } -} - -impl From for ProtFlags { - fn from(value: VmFlags) -> Self { - let mut prot_flags = ProtFlags::PROT_NONE; - - if value.contains(VmFlags::VM_READ) { - prot_flags |= ProtFlags::PROT_READ; - } - - if value.contains(VmFlags::VM_WRITE) { - prot_flags |= ProtFlags::PROT_WRITE; - } - - if value.contains(VmFlags::VM_EXEC) { - prot_flags |= ProtFlags::PROT_EXEC; - } - - prot_flags - } -} - -impl Syscall { - pub fn brk(new_addr: VirtAddr) -> Result { - // log::debug!("brk: new_addr={:?}", new_addr); - let address_space = AddressSpace::current()?; - let mut address_space = address_space.write(); - - if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { - return Ok(address_space.brk); - } - if new_addr == address_space.brk { - return Ok(address_space.brk); - } - - unsafe { - // log::debug!("brk: set_brk new_addr={:?}", new_addr); - address_space - .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) - .ok(); - - return Ok(address_space.sbrk(0).unwrap()); - } - } - - pub fn sbrk(incr: isize) -> Result { - let address_space = AddressSpace::current()?; - assert!(address_space.read().user_mapper.utable.is_current()); - let mut address_space = address_space.write(); - let r = unsafe { address_space.sbrk(incr) }; - - return r; - } - - /// ## mmap系统调用 - /// - /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 - /// - /// ## 参数 - /// - /// - `start_vaddr`:映射的起始地址 - /// - `len`:映射的长度 - /// - `prot`:保护标志 - /// - `flags`:映射标志 - /// - `fd`:文件描述符(暂时不支持) - /// - `offset`:文件偏移量 (暂时不支持) - /// - /// ## 返回值 - /// - /// 成功时返回映射的起始地址,失败时返回错误码 - pub fn mmap( - start_vaddr: VirtAddr, - len: usize, - prot_flags: usize, - map_flags: 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); - - if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) - && map_flags.contains(MapFlags::MAP_FIXED) - { - error!( - "mmap: MAP_FIXED is not supported for address below {}", - DEFAULT_MMAP_MIN_ADDR - ); - return Err(SystemError::EINVAL); - } - - // 暂时不支持巨页映射 - if map_flags.contains(MapFlags::MAP_HUGETLB) { - error!("mmap: not support huge page mapping"); - return Err(SystemError::ENOSYS); - } - let current_address_space = AddressSpace::current()?; - 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()); - } - - /// ## 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_irqsave().vm_flags(); - - // 暂时不支持巨页映射 - if vm_flags.contains(VmFlags::VM_HUGETLB) { - error!("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系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) - /// - `len`:取消映射的字节数(已经对齐到页) - /// - /// ## 返回值 - /// - /// 成功时返回0,失败时返回错误码 - pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result { - assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); - assert!(check_aligned(len, MMArch::PAGE_SIZE)); - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .munmap(start_frame, page_count) - .map_err(|_| SystemError::EINVAL)?; - - return Ok(0); - } - - /// ## mprotect系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:起始地址(已经对齐到页) - /// - `len`:长度(已经对齐到页) - /// - `prot_flags`:保护标志 - pub fn mprotect( - start_vaddr: VirtAddr, - len: usize, - prot_flags: usize, - ) -> Result { - assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); - assert!(check_aligned(len, MMArch::PAGE_SIZE)); - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .mprotect(start_frame, page_count, prot_flags) - .map_err(|_| SystemError::EINVAL)?; - return Ok(0); - } - - /// ## madvise系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:起始地址(已经对齐到页) - /// - `len`:长度(已经对齐到页) - /// - `madv_flags`:建议标志 - pub fn madvise( - start_vaddr: VirtAddr, - len: usize, - madv_flags: usize, - ) -> Result { - if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let madv_flags = MadvFlags::from_bits(madv_flags as u64).ok_or(SystemError::EINVAL)?; - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .madvise(start_frame, page_count, madv_flags) - .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/syscall/mod.rs b/kernel/src/mm/syscall/mod.rs new file mode 100644 index 00000000..adb63d12 --- /dev/null +++ b/kernel/src/mm/syscall/mod.rs @@ -0,0 +1,245 @@ +use crate::{ + ipc::shm::ShmFlags, + libs::align::{check_aligned, page_align_up}, +}; + +use super::{allocator::page_frame::PageFrameCount, MsFlags, VmFlags}; + +mod sys_brk; +mod sys_madvise; +mod sys_mmap; +mod sys_mprotect; +mod sys_mremap; +mod sys_msync; +mod sys_munmap; +mod sys_sbrk; + +bitflags! { + /// Memory protection flags + pub struct ProtFlags: u64 { + const PROT_NONE = 0x0; + const PROT_READ = 0x1; + const PROT_WRITE = 0x2; + const PROT_EXEC = 0x4; + } + + /// Memory mapping flags + pub struct MapFlags: u64 { + const MAP_NONE = 0x0; + /// share changes + const MAP_SHARED = 0x1; + /// changes are private + const MAP_PRIVATE = 0x2; + /// Interpret addr exactly + const MAP_FIXED = 0x10; + /// don't use a file + const MAP_ANONYMOUS = 0x20; + // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 + /// stack-like segment + const MAP_GROWSDOWN = 0x100; + /// ETXTBSY + const MAP_DENYWRITE = 0x800; + /// Mark it as an executable + const MAP_EXECUTABLE = 0x1000; + /// Pages are locked + const MAP_LOCKED = 0x2000; + /// don't check for reservations + const MAP_NORESERVE = 0x4000; + /// populate (prefault) pagetables + const MAP_POPULATE = 0x8000; + /// do not block on IO + const MAP_NONBLOCK = 0x10000; + /// give out an address that is best suited for process/thread stacks + const MAP_STACK = 0x20000; + /// create a huge page mapping + const MAP_HUGETLB = 0x40000; + /// perform synchronous page faults for the mapping + const MAP_SYNC = 0x80000; + /// MAP_FIXED which doesn't unmap underlying mapping + const MAP_FIXED_NOREPLACE = 0x100000; + + /// 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; + } + + + pub struct MadvFlags: u64 { + /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 + const MADV_NORMAL = 0; + /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 + const MADV_RANDOM = 1; + /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 + const MADV_SEQUENTIAL = 2; + /// 通知系统预读某些页面,用于应用程序提前准备数据 + const MADV_WILLNEED = 3; + /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 + const MADV_DONTNEED = 4; + + /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 + const MADV_FREE = 8; + /// 应用程序请求释放指定范围的页面和相关的后备存储 + const MADV_REMOVE = 9; + /// 在 fork 时排除指定区域 + const MADV_DONTFORK = 10; + /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 + const MADV_DOFORK = 11; + /// 模拟内存硬件错误,触发内存错误处理器处理 + const MADV_HWPOISON = 100; + /// 尝试软下线指定的内存范围 + const MADV_SOFT_OFFLINE = 101; + + /// 应用程序建议内核尝试合并指定范围内内容相同的页面 + const MADV_MERGEABLE = 12; + /// 取消 MADV_MERGEABLE 的效果,不再合并页面 + const MADV_UNMERGEABLE = 13; + + /// 应用程序希望将指定范围以透明大页方式支持 + const MADV_HUGEPAGE = 14; + /// 将指定范围标记为不值得用透明大页支持 + const MADV_NOHUGEPAGE = 15; + + /// 应用程序请求在核心转储时排除指定范围内的页面 + const MADV_DONTDUMP = 16; + /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 + const MADV_DODUMP = 17; + + /// 在 fork 时将子进程的该区域内存填充为零 + const MADV_WIPEONFORK = 18; + /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 + const MADV_KEEPONFORK = 19; + + /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 + const MADV_COLD = 20; + /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 + const MADV_PAGEOUT = 21; + + /// 预先填充页面表,可读,通过触发读取故障 + const MADV_POPULATE_READ = 22; + /// 预先填充页面表,可写,通过触发写入故障 + const MADV_POPULATE_WRITE = 23; + + /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 + const MADV_DONTNEED_LOCKED = 24; + + /// 同步将页面合并为新的透明大页 + const MADV_COLLAPSE = 25; + + } +} + +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; + } + + if map_flags.contains(MapFlags::MAP_SHARED) { + vm_flags |= VmFlags::VM_SHARED; + } + + 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 From for VmFlags { + fn from(shm_flags: ShmFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if shm_flags.contains(ShmFlags::SHM_RDONLY) { + vm_flags |= VmFlags::VM_READ; + } else { + vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; + } + + if shm_flags.contains(ShmFlags::SHM_EXEC) { + vm_flags |= VmFlags::VM_EXEC; + } + + if shm_flags.contains(ShmFlags::SHM_HUGETLB) { + vm_flags |= VmFlags::VM_HUGETLB; + } + + vm_flags + } +} + +impl From for MapFlags { + fn from(value: VmFlags) -> Self { + let mut map_flags = MapFlags::MAP_NONE; + + if value.contains(VmFlags::VM_GROWSDOWN) { + map_flags |= MapFlags::MAP_GROWSDOWN; + } + + if value.contains(VmFlags::VM_LOCKED) { + map_flags |= MapFlags::MAP_LOCKED; + } + + if value.contains(VmFlags::VM_SYNC) { + map_flags |= MapFlags::MAP_SYNC; + } + + if value.contains(VmFlags::VM_MAYSHARE) { + map_flags |= MapFlags::MAP_SHARED; + } + + map_flags + } +} + +impl From for ProtFlags { + fn from(value: VmFlags) -> Self { + let mut prot_flags = ProtFlags::PROT_NONE; + + if value.contains(VmFlags::VM_READ) { + prot_flags |= ProtFlags::PROT_READ; + } + + if value.contains(VmFlags::VM_WRITE) { + prot_flags |= ProtFlags::PROT_WRITE; + } + + if value.contains(VmFlags::VM_EXEC) { + prot_flags |= ProtFlags::PROT_EXEC; + } + + prot_flags + } +} diff --git a/kernel/src/mm/syscall/sys_brk.rs b/kernel/src/mm/syscall/sys_brk.rs new file mode 100644 index 00000000..ee3fe295 --- /dev/null +++ b/kernel/src/mm/syscall/sys_brk.rs @@ -0,0 +1,68 @@ +//! System call handler for the brk system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_BRK}; +use crate::mm::ucontext::AddressSpace; +use crate::mm::MemoryManagementArch; +use crate::mm::VirtAddr; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handler for the brk system call, which sets the end of the data segment (heap). +pub struct SysBrkHandle; + +impl Syscall for SysBrkHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 1 + } + + /// Handles the brk system call. + /// + /// # Arguments + /// * `args` - The syscall arguments, where args[0] is the new end address of the heap. + /// + /// # Returns + /// * On success, returns the new program break (heap end) as usize. + /// * On failure, returns a SystemError. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let addr = Self::addr(args); + let new_addr = VirtAddr::new(addr); + let address_space = AddressSpace::current()?; + let mut address_space = address_space.write(); + + if new_addr < address_space.brk_start || new_addr >= crate::arch::MMArch::USER_END_VADDR { + return Ok(address_space.brk.data()); + } + if new_addr == address_space.brk { + return Ok(address_space.brk.data()); + } + + unsafe { + address_space + .set_brk(VirtAddr::new(crate::libs::align::page_align_up( + new_addr.data(), + ))) + .ok(); + return Ok(address_space.sbrk(0).unwrap().data()); + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "addr", + format!("{:#x}", Self::addr(args)), + )] + } +} + +impl SysBrkHandle { + /// Extracts the address argument from syscall parameters. + fn addr(args: &[usize]) -> usize { + args[0] + } +} + +syscall_table_macros::declare_syscall!(SYS_BRK, SysBrkHandle); diff --git a/kernel/src/mm/syscall/sys_madvise.rs b/kernel/src/mm/syscall/sys_madvise.rs new file mode 100644 index 00000000..6f251e50 --- /dev/null +++ b/kernel/src/mm/syscall/sys_madvise.rs @@ -0,0 +1,84 @@ +//! System call handler for the madvise system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MADVISE, MMArch}; +use crate::mm::{ + syscall::{check_aligned, MadvFlags, PageFrameCount}, + ucontext::AddressSpace, + MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr}, +}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::sync::Arc; +use alloc::vec::Vec; + +/// Handles the madvise system call, which gives advice about the use of memory. +pub struct SysMadviseHandle; + +impl Syscall for SysMadviseHandle { + fn num_args(&self) -> usize { + 3 + } + + /// ## madvise系统调用 + /// + /// ## 参数 + /// - `start_vaddr`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `madv_flags`:建议标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let madv_flags = + MadvFlags::from_bits(Self::madv_flags(args) as u64).ok_or(SystemError::EINVAL)?; + if Self::start_vaddr(args) & (MMArch::PAGE_SIZE - 1) != 0 { + return Err(SystemError::EINVAL); + } + + if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EINVAL); + } + if len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .madvise(start_frame, page_count, madv_flags) + .map_err(|_| SystemError::EINVAL)?; + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("madv_flags", format!("{:#x}", Self::madv_flags(args))), + ] + } +} + +impl SysMadviseHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the madv_flags argument from syscall parameters. + fn madv_flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MADVISE, SysMadviseHandle); diff --git a/kernel/src/mm/syscall/sys_mmap.rs b/kernel/src/mm/syscall/sys_mmap.rs new file mode 100644 index 00000000..54d84d1b --- /dev/null +++ b/kernel/src/mm/syscall/sys_mmap.rs @@ -0,0 +1,137 @@ +//! System call handler for the mmap system call. + +use super::ProtFlags; +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MMAP}; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::MapFlags; +use crate::mm::ucontext::DEFAULT_MMAP_MIN_ADDR; +use crate::mm::verify_area; +use crate::mm::AddressSpace; +use crate::mm::VirtAddr; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use log::error; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handler for the mmap system call, which maps files or devices into memory. +pub struct SysMmapHandle; + +impl Syscall for SysMmapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 6 + } + + /// ## mmap系统调用 + /// + /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 + /// + /// ## 参数 + /// + /// - `start_vaddr`:映射的起始地址 + /// - `len`:映射的长度 + /// - `prot`:保护标志 + /// - `flags`:映射标志 + /// - `fd`:文件描述符(暂时不支持) + /// - `offset`:文件偏移量 (暂时不支持) + /// + /// ## 返回值 + /// + /// 成功时返回映射的起始地址,失败时返回错误码 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = page_align_up(Self::len(args)); + let prot_flags = Self::prot(args); + let map_flags = Self::flags(args); + let fd = Self::fd(args); + let offset = Self::offset(args); + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EFAULT); + } else { + let map_flags = MapFlags::from_bits_truncate(map_flags as u64); + let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); + + if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) + && map_flags.contains(MapFlags::MAP_FIXED) + { + error!( + "mmap: MAP_FIXED is not supported for address below {}", + DEFAULT_MMAP_MIN_ADDR + ); + return Err(SystemError::EINVAL); + } + + // 暂时不支持巨页映射 + if map_flags.contains(MapFlags::MAP_HUGETLB) { + error!("mmap: not support huge page mapping"); + return Err(SystemError::ENOSYS); + } + let current_address_space = AddressSpace::current()?; + 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()); + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("prot", format!("{:#x}", Self::prot(args))), + FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))), + FormattedSyscallParam::new("fd", format!("{}", Self::fd(args))), + FormattedSyscallParam::new("offset", format!("{:#x}", Self::offset(args))), + ] + } +} + +impl SysMmapHandle { + /// Extracts the start virtual address argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the length argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the protection flags argument from syscall parameters. + fn prot(args: &[usize]) -> usize { + args[2] + } + /// Extracts the mapping flags argument from syscall parameters. + fn flags(args: &[usize]) -> usize { + args[3] + } + /// Extracts the file descriptor argument from syscall parameters. + fn fd(args: &[usize]) -> i32 { + args[4] as i32 + } + /// Extracts the file offset argument from syscall parameters. + fn offset(args: &[usize]) -> usize { + args[5] + } +} +syscall_table_macros::declare_syscall!(SYS_MMAP, SysMmapHandle); diff --git a/kernel/src/mm/syscall/sys_mprotect.rs b/kernel/src/mm/syscall/sys_mprotect.rs new file mode 100644 index 00000000..9d919358 --- /dev/null +++ b/kernel/src/mm/syscall/sys_mprotect.rs @@ -0,0 +1,83 @@ +//! System call handler for the mprotect system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MPROTECT, MMArch}; +use crate::mm::{ + syscall::{check_aligned, PageFrameCount, ProtFlags}, + ucontext::AddressSpace, + MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr}, +}; + +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::sync::Arc; +use alloc::vec::Vec; + +/// Handles the mprotect system call. +pub struct SysMprotectHandle; + +impl Syscall for SysMprotectHandle { + fn num_args(&self) -> usize { + 3 + } + + /// ## mprotect系统调用 + /// + /// ## 参数 + /// + /// - `start_vaddr`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `prot_flags`:保护标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let prot_flags = + ProtFlags::from_bits(Self::prot_flags(args) as u64).ok_or(SystemError::EINVAL)?; + + assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); + assert!(check_aligned(len, MMArch::PAGE_SIZE)); + + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EINVAL); + } + if len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .mprotect(start_frame, page_count, prot_flags) + .map_err(|_| SystemError::EINVAL)?; + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("prot_flags", format!("{:#x}", Self::prot_flags(args))), + ] + } +} + +impl SysMprotectHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the prot_flags argument from syscall parameters. + fn prot_flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MPROTECT, SysMprotectHandle); diff --git a/kernel/src/mm/syscall/sys_mremap.rs b/kernel/src/mm/syscall/sys_mremap.rs new file mode 100644 index 00000000..71692af2 --- /dev/null +++ b/kernel/src/mm/syscall/sys_mremap.rs @@ -0,0 +1,145 @@ +//! System call handler for the mremap system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MREMAP}; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::sys_munmap::do_munmap; +use crate::mm::syscall::MremapFlags; +use crate::mm::ucontext::AddressSpace; +use crate::mm::MemoryManagementArch; +use crate::mm::{MMArch, VirtAddr, VmFlags}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; +/// Handles the mremap system call. +pub struct SysMremapHandle; + +impl Syscall for SysMremapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 5 + } + + /// ## mremap系统调用 + /// + /// + /// ## 参数 + /// + /// - `old_vaddr`:原映射的起始地址 + /// - `old_len`:原映射的长度 + /// - `new_len`:重新映射的长度 + /// - `mremap_flags`:重映射标志 + /// - `new_vaddr`:重新映射的起始地址 + /// + /// ## 返回值 + /// + /// 成功时返回重映射的起始地址,失败时返回错误码 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let old_vaddr = VirtAddr::new(Self::old_vaddr(args)); + let old_len = Self::old_len(args); + let new_len = Self::new_len(args); + let mremap_flags = MremapFlags::from_bits_truncate(Self::mremap_flags(args) as u8); + let new_vaddr = VirtAddr::new(Self::new_vaddr(args)); + + // 需要重映射到新内存区域的情况下,必须包含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_irqsave().vm_flags(); + + // 暂时不支持巨页映射 + if vm_flags.contains(VmFlags::VM_HUGETLB) { + log::error!("mmap: not support huge page mapping"); + return Err(SystemError::ENOSYS); + } + + // 缩小旧内存映射区域 + if old_len > new_len { + do_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) { + do_munmap(old_vaddr, old_len)?; + } + + return Ok(r.data()); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("old_vaddr", format!("{:#x}", Self::old_vaddr(args))), + FormattedSyscallParam::new("old_len", format!("{:#x}", Self::old_len(args))), + FormattedSyscallParam::new("new_len", format!("{:#x}", Self::new_len(args))), + FormattedSyscallParam::new("mremap_flags", format!("{:#x}", Self::mremap_flags(args))), + FormattedSyscallParam::new("new_vaddr", format!("{:#x}", Self::new_vaddr(args))), + ] + } +} + +impl SysMremapHandle { + /// Extracts the old_vaddr argument from syscall parameters. + fn old_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the old_len argument from syscall parameters. + fn old_len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the new_len argument from syscall parameters. + fn new_len(args: &[usize]) -> usize { + args[2] + } + /// Extracts the mremap_flags argument from syscall parameters. + fn mremap_flags(args: &[usize]) -> usize { + args[3] + } + /// Extracts the new_vaddr argument from syscall parameters. + fn new_vaddr(args: &[usize]) -> usize { + args[4] + } +} + +syscall_table_macros::declare_syscall!(SYS_MREMAP, SysMremapHandle); diff --git a/kernel/src/mm/syscall/sys_msync.rs b/kernel/src/mm/syscall/sys_msync.rs new file mode 100644 index 00000000..c4df4bd1 --- /dev/null +++ b/kernel/src/mm/syscall/sys_msync.rs @@ -0,0 +1,158 @@ +//! System call handler for the msync system call. + +use crate::{ + arch::{interrupt::TrapFrame, syscall::nr::SYS_MSYNC, MMArch}, + driver::base::block::SeekFrom, +}; + +use crate::mm::{ + syscall::{check_aligned, MsFlags, VmFlags}, + ucontext::AddressSpace, + unlikely, verify_area, MemoryManagementArch, VirtAddr, +}; + +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handles the msync system call. +pub struct SysMsyncHandle; + +impl Syscall for SysMsyncHandle { + fn num_args(&self) -> usize { + 3 + } + /// ## msync系统调用 + /// + /// ## 参数 + /// + /// - `start`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `flags`:标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let flags = MsFlags::from_bits_truncate(Self::flags(args)); + + 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 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; + 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 { + core::slice::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; + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))), + ] + } +} + +impl SysMsyncHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the flags argument from syscall parameters. + fn flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MSYNC, SysMsyncHandle); diff --git a/kernel/src/mm/syscall/sys_munmap.rs b/kernel/src/mm/syscall/sys_munmap.rs new file mode 100644 index 00000000..8bf31154 --- /dev/null +++ b/kernel/src/mm/syscall/sys_munmap.rs @@ -0,0 +1,89 @@ +//! System call handler for the munmap system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MUNMAP}; +use crate::mm::syscall::check_aligned; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::PageFrameCount; +use crate::mm::ucontext::AddressSpace; +use crate::mm::unlikely; +use crate::mm::MemoryManagementArch; +use crate::mm::{verify_area, MMArch, VirtAddr, VirtPageFrame}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use system_error::SystemError; + +/// ## munmap系统调用 +/// +/// ## 参数 +/// +/// - `start_vaddr`:取消映射的起始地址(已经对齐到页) +/// - `len`:取消映射的字节数(已经对齐到页) +/// +/// ## 返回值 +/// +/// 成功时返回0,失败时返回错误码 +pub struct SysMunmapHandle; + +impl Syscall for SysMunmapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 2 + } + + /// Handles the munmap system call. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let addr = args[0]; + let len = page_align_up(args[1]); + if addr & (MMArch::PAGE_SIZE - 1) != 0 { + // The addr argument is not a multiple of the page size + return Err(SystemError::EINVAL); + } else { + do_munmap(VirtAddr::new(addr), len) + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + ] + } +} + +impl SysMunmapHandle { + /// Extracts the start virtual address argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the length argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } +} + +syscall_table_macros::declare_syscall!(SYS_MUNMAP, SysMunmapHandle); + +pub(super) fn do_munmap(start_vaddr: VirtAddr, len: usize) -> Result { + assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); + assert!(check_aligned(len, MMArch::PAGE_SIZE)); + + if unlikely(verify_area(start_vaddr, len).is_err()) { + return Err(SystemError::EINVAL); + } + if unlikely(len == 0) { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .munmap(start_frame, page_count) + .map_err(|_| SystemError::EINVAL)?; + + return Ok(0); +} diff --git a/kernel/src/mm/syscall/sys_sbrk.rs b/kernel/src/mm/syscall/sys_sbrk.rs new file mode 100644 index 00000000..2fb7c77e --- /dev/null +++ b/kernel/src/mm/syscall/sys_sbrk.rs @@ -0,0 +1,53 @@ +//! System call handler for the sbrk system call. + +use crate::arch::interrupt::TrapFrame; +use crate::mm::ucontext::AddressSpace; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::syscall::SYS_SBRK; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handler for the sbrk system call, which increments the program's data space (heap). +pub struct SysSbrkHandle; + +impl Syscall for SysSbrkHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 1 + } + + /// Handles the sbrk system call. + /// + /// # Arguments + /// * `args` - The syscall arguments, where args[0] is the increment value (isize). + /// + /// # Returns + /// * On success, returns the previous program break (heap end) as usize. + /// * On failure, returns a SystemError. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let incr = Self::incr(args); + let address_space = AddressSpace::current()?; + assert!(address_space.read().user_mapper.utable.is_current()); + let mut address_space = address_space.write(); + let r = unsafe { address_space.sbrk(incr) }?; + return Ok(r.data()); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "incr", + format!("{}", Self::incr(args)), + )] + } +} + +impl SysSbrkHandle { + /// Extracts the increment argument from syscall parameters. + fn incr(args: &[usize]) -> isize { + args[0] as isize + } +} + +syscall_table_macros::declare_syscall!(SYS_SBRK, SysSbrkHandle); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index d51fe6ed..c74b2c2c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -8,7 +8,7 @@ use crate::{ arch::syscall::nr::*, filesystem::vfs::syscall::PosixStatfs, libs::{futex::constant::FutexFlag, rand::GRandFlags}, - mm::{page::PAGE_4K_SIZE, syscall::MremapFlags}, + mm::page::PAGE_4K_SIZE, net::syscall::MsgHdr, process::{ProcessFlags, ProcessManager}, sched::{schedule, SchedMode}, @@ -21,13 +21,12 @@ use system_error::SystemError; use table::{syscall_table, syscall_table_init}; use crate::{ - arch::{interrupt::TrapFrame, MMArch}, + arch::interrupt::TrapFrame, filesystem::vfs::{ fcntl::{AtFlags, FcntlCommand}, syscall::{ModeType, UtimensFlags}, }, - libs::align::page_align_up, - mm::{verify_area, MemoryManagementArch, VirtAddr}, + mm::{verify_area, VirtAddr}, net::syscall::SockAddr, time::{ syscall::{PosixTimeZone, PosixTimeval}, @@ -188,16 +187,6 @@ impl Syscall { Self::pwrite(fd, buf, len, offset) } - SYS_BRK => { - let new_brk = VirtAddr::new(args[0]); - Self::brk(new_brk).map(|vaddr| vaddr.data()) - } - - SYS_SBRK => { - let increment = args[0] as isize; - Self::sbrk(increment).map(|vaddr: VirtAddr| vaddr.data()) - } - SYS_REBOOT => { let magic1 = args[0] as u32; let magic2 = args[1] as u32; @@ -498,51 +487,6 @@ impl Syscall { let timezone_ptr = args[1] as *mut PosixTimeZone; Self::gettimeofday(timeval, timezone_ptr) } - SYS_MMAP => { - let len = page_align_up(args[1]); - let virt_addr = VirtAddr::new(args[0]); - if verify_area(virt_addr, len).is_err() { - Err(SystemError::EFAULT) - } else { - Self::mmap( - VirtAddr::new(args[0]), - len, - args[2], - args[3], - args[4] as i32, - args[5], - ) - } - } - 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]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - // The addr argument is not a multiple of the page size - Err(SystemError::EINVAL) - } else { - Self::munmap(VirtAddr::new(addr), len) - } - } - SYS_MPROTECT => { - let addr = args[0]; - let len = page_align_up(args[1]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - // The addr argument is not a multiple of the page size - Err(SystemError::EINVAL) - } else { - Self::mprotect(VirtAddr::new(addr), len, args[2]) - } - } SYS_GETCWD => { let buf = args[0] as *mut u8; @@ -694,16 +638,6 @@ impl Syscall { Ok(0) } - SYS_MADVISE => { - let addr = args[0]; - let len = page_align_up(args[1]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - Err(SystemError::EINVAL) - } else { - Self::madvise(VirtAddr::new(addr), len, args[2]) - } - } - SYS_SYSLOG => { let syslog_action_type = args[0]; let buf_vaddr = args[1]; @@ -878,12 +812,7 @@ impl Syscall { let second = args[0] as u32; Self::alarm(second) } - 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,