xref: /DragonOS/kernel/src/mm/syscall.rs (revision 3055390c25bb7b12279df174689ba09ec50c7d46)
140fe15e0SLoGin use core::intrinsics::unlikely;
240fe15e0SLoGin 
340fe15e0SLoGin use alloc::sync::Arc;
491e9d4abSLoGin use system_error::SystemError;
540fe15e0SLoGin 
6ab5c8ca4Slogin use crate::{
740fe15e0SLoGin     arch::MMArch,
840fe15e0SLoGin     kerror,
940fe15e0SLoGin     libs::align::{check_aligned, page_align_up},
1040fe15e0SLoGin     mm::MemoryManagementArch,
1191e9d4abSLoGin     syscall::Syscall,
12ab5c8ca4Slogin };
13ab5c8ca4Slogin 
1440fe15e0SLoGin use super::{
1540fe15e0SLoGin     allocator::page_frame::{PageFrameCount, VirtPageFrame},
1640fe15e0SLoGin     ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
174cfa009bSJomo     verify_area, VirtAddr, VmFlags,
1840fe15e0SLoGin };
1940fe15e0SLoGin 
2040fe15e0SLoGin bitflags! {
2140fe15e0SLoGin     /// Memory protection flags
2240fe15e0SLoGin     pub struct ProtFlags: u64 {
2340fe15e0SLoGin         const PROT_NONE = 0x0;
2440fe15e0SLoGin         const PROT_READ = 0x1;
2540fe15e0SLoGin         const PROT_WRITE = 0x2;
2640fe15e0SLoGin         const PROT_EXEC = 0x4;
27ab5c8ca4Slogin     }
2840fe15e0SLoGin 
2940fe15e0SLoGin     /// Memory mapping flags
3040fe15e0SLoGin     pub struct MapFlags: u64 {
3140fe15e0SLoGin         const MAP_NONE = 0x0;
3240fe15e0SLoGin         /// share changes
3340fe15e0SLoGin         const MAP_SHARED = 0x1;
3440fe15e0SLoGin         /// changes are private
3540fe15e0SLoGin         const MAP_PRIVATE = 0x2;
3640fe15e0SLoGin         /// Interpret addr exactly
3740fe15e0SLoGin         const MAP_FIXED = 0x10;
3840fe15e0SLoGin         /// don't use a file
3940fe15e0SLoGin         const MAP_ANONYMOUS = 0x20;
4040fe15e0SLoGin         // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
4140fe15e0SLoGin         /// stack-like segment
4240fe15e0SLoGin         const MAP_GROWSDOWN = 0x100;
4340fe15e0SLoGin         /// ETXTBSY
4440fe15e0SLoGin         const MAP_DENYWRITE = 0x800;
4540fe15e0SLoGin         /// Mark it as an executable
4640fe15e0SLoGin         const MAP_EXECUTABLE = 0x1000;
4740fe15e0SLoGin         /// Pages are locked
4840fe15e0SLoGin         const MAP_LOCKED = 0x2000;
4940fe15e0SLoGin         /// don't check for reservations
5040fe15e0SLoGin         const MAP_NORESERVE = 0x4000;
5140fe15e0SLoGin         /// populate (prefault) pagetables
5240fe15e0SLoGin         const MAP_POPULATE = 0x8000;
5340fe15e0SLoGin         /// do not block on IO
5440fe15e0SLoGin         const MAP_NONBLOCK = 0x10000;
5540fe15e0SLoGin         /// give out an address that is best suited for process/thread stacks
5640fe15e0SLoGin         const MAP_STACK = 0x20000;
5740fe15e0SLoGin         /// create a huge page mapping
5840fe15e0SLoGin         const MAP_HUGETLB = 0x40000;
5940fe15e0SLoGin         /// perform synchronous page faults for the mapping
6040fe15e0SLoGin         const MAP_SYNC = 0x80000;
6140fe15e0SLoGin         /// MAP_FIXED which doesn't unmap underlying mapping
6240fe15e0SLoGin         const MAP_FIXED_NOREPLACE = 0x100000;
6340fe15e0SLoGin 
6440fe15e0SLoGin         /// For anonymous mmap, memory could be uninitialized
6540fe15e0SLoGin         const MAP_UNINITIALIZED = 0x4000000;
664cfa009bSJomo     }
6740fe15e0SLoGin 
684cfa009bSJomo     /// Memory mremapping flags
694cfa009bSJomo     pub struct MremapFlags: u8 {
704cfa009bSJomo         const MREMAP_MAYMOVE = 1;
714cfa009bSJomo         const MREMAP_FIXED = 2;
724cfa009bSJomo         const MREMAP_DONTUNMAP = 4;
734cfa009bSJomo     }
744cfa009bSJomo }
754cfa009bSJomo 
764cfa009bSJomo impl From<MapFlags> for VmFlags {
774cfa009bSJomo     fn from(map_flags: MapFlags) -> Self {
784cfa009bSJomo         let mut vm_flags = VmFlags::VM_NONE;
794cfa009bSJomo 
804cfa009bSJomo         if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
814cfa009bSJomo             vm_flags |= VmFlags::VM_GROWSDOWN;
824cfa009bSJomo         }
834cfa009bSJomo 
844cfa009bSJomo         if map_flags.contains(MapFlags::MAP_LOCKED) {
854cfa009bSJomo             vm_flags |= VmFlags::VM_LOCKED;
864cfa009bSJomo         }
874cfa009bSJomo 
884cfa009bSJomo         if map_flags.contains(MapFlags::MAP_SYNC) {
894cfa009bSJomo             vm_flags |= VmFlags::VM_SYNC;
904cfa009bSJomo         }
914cfa009bSJomo 
924cfa009bSJomo         vm_flags
934cfa009bSJomo     }
944cfa009bSJomo }
954cfa009bSJomo 
964cfa009bSJomo impl From<ProtFlags> for VmFlags {
974cfa009bSJomo     fn from(prot_flags: ProtFlags) -> Self {
984cfa009bSJomo         let mut vm_flags = VmFlags::VM_NONE;
994cfa009bSJomo 
1004cfa009bSJomo         if prot_flags.contains(ProtFlags::PROT_READ) {
1014cfa009bSJomo             vm_flags |= VmFlags::VM_READ;
1024cfa009bSJomo         }
1034cfa009bSJomo 
1044cfa009bSJomo         if prot_flags.contains(ProtFlags::PROT_WRITE) {
1054cfa009bSJomo             vm_flags |= VmFlags::VM_WRITE;
1064cfa009bSJomo         }
1074cfa009bSJomo 
1084cfa009bSJomo         if prot_flags.contains(ProtFlags::PROT_EXEC) {
1094cfa009bSJomo             vm_flags |= VmFlags::VM_EXEC;
1104cfa009bSJomo         }
1114cfa009bSJomo 
1124cfa009bSJomo         vm_flags
1134cfa009bSJomo     }
1144cfa009bSJomo }
1154cfa009bSJomo 
1164cfa009bSJomo impl Into<MapFlags> for VmFlags {
1174cfa009bSJomo     fn into(self) -> MapFlags {
1184cfa009bSJomo         let mut map_flags = MapFlags::MAP_NONE;
1194cfa009bSJomo 
1204cfa009bSJomo         if self.contains(VmFlags::VM_GROWSDOWN) {
1214cfa009bSJomo             map_flags |= MapFlags::MAP_GROWSDOWN;
1224cfa009bSJomo         }
1234cfa009bSJomo 
1244cfa009bSJomo         if self.contains(VmFlags::VM_LOCKED) {
1254cfa009bSJomo             map_flags |= MapFlags::MAP_LOCKED;
1264cfa009bSJomo         }
1274cfa009bSJomo 
1284cfa009bSJomo         if self.contains(VmFlags::VM_SYNC) {
1294cfa009bSJomo             map_flags |= MapFlags::MAP_SYNC;
1304cfa009bSJomo         }
1314cfa009bSJomo 
132*3055390cSJomo         if self.contains(VmFlags::VM_MAYSHARE) {
133*3055390cSJomo             map_flags |= MapFlags::MAP_SHARED;
134*3055390cSJomo         }
135*3055390cSJomo 
1364cfa009bSJomo         map_flags
1374cfa009bSJomo     }
1384cfa009bSJomo }
1394cfa009bSJomo 
1404cfa009bSJomo impl Into<ProtFlags> for VmFlags {
1414cfa009bSJomo     fn into(self) -> ProtFlags {
1424cfa009bSJomo         let mut prot_flags = ProtFlags::PROT_NONE;
1434cfa009bSJomo 
1444cfa009bSJomo         if self.contains(VmFlags::VM_READ) {
1454cfa009bSJomo             prot_flags |= ProtFlags::PROT_READ;
1464cfa009bSJomo         }
1474cfa009bSJomo 
1484cfa009bSJomo         if self.contains(VmFlags::VM_WRITE) {
1494cfa009bSJomo             prot_flags |= ProtFlags::PROT_WRITE;
1504cfa009bSJomo         }
1514cfa009bSJomo 
1524cfa009bSJomo         if self.contains(VmFlags::VM_EXEC) {
1534cfa009bSJomo             prot_flags |= ProtFlags::PROT_EXEC;
1544cfa009bSJomo         }
1554cfa009bSJomo 
1564cfa009bSJomo         prot_flags
15740fe15e0SLoGin     }
15840fe15e0SLoGin }
15940fe15e0SLoGin 
160ab5c8ca4Slogin impl Syscall {
16140fe15e0SLoGin     pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
16240fe15e0SLoGin         // kdebug!("brk: new_addr={:?}", new_addr);
16340fe15e0SLoGin         let address_space = AddressSpace::current()?;
16440fe15e0SLoGin         let mut address_space = address_space.write();
16540fe15e0SLoGin 
1666d81180bSLoGin         if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
1676d81180bSLoGin             return Ok(address_space.brk);
1686d81180bSLoGin         }
1696d81180bSLoGin         if new_addr == address_space.brk {
1706d81180bSLoGin             return Ok(address_space.brk);
1716d81180bSLoGin         }
1726d81180bSLoGin 
17340fe15e0SLoGin         unsafe {
17440fe15e0SLoGin             address_space
17540fe15e0SLoGin                 .set_brk(VirtAddr::new(page_align_up(new_addr.data())))
17640fe15e0SLoGin                 .ok();
17740fe15e0SLoGin 
17840fe15e0SLoGin             return Ok(address_space.sbrk(0).unwrap());
179ab5c8ca4Slogin         }
180d8ad0a5eSLoGin     }
181d8ad0a5eSLoGin 
18240fe15e0SLoGin     pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
18340fe15e0SLoGin         let address_space = AddressSpace::current()?;
1841496ba7bSLoGin         assert!(address_space.read().user_mapper.utable.is_current());
18540fe15e0SLoGin         let mut address_space = address_space.write();
18640fe15e0SLoGin         let r = unsafe { address_space.sbrk(incr) };
18740fe15e0SLoGin 
18840fe15e0SLoGin         return r;
189d8ad0a5eSLoGin     }
190d8ad0a5eSLoGin 
19140fe15e0SLoGin     /// ## mmap系统调用
192d8ad0a5eSLoGin     ///
19340fe15e0SLoGin     /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
19440fe15e0SLoGin     ///
19540fe15e0SLoGin     /// ## 参数
19640fe15e0SLoGin     ///
19740fe15e0SLoGin     /// - `start_vaddr`:映射的起始地址
19840fe15e0SLoGin     /// - `len`:映射的长度
19940fe15e0SLoGin     /// - `prot`:保护标志
20040fe15e0SLoGin     /// - `flags`:映射标志
20140fe15e0SLoGin     /// - `fd`:文件描述符(暂时不支持)
20240fe15e0SLoGin     /// - `offset`:文件偏移量 (暂时不支持)
20340fe15e0SLoGin     ///
20440fe15e0SLoGin     /// ## 返回值
20540fe15e0SLoGin     ///
20640fe15e0SLoGin     /// 成功时返回映射的起始地址,失败时返回错误码
20740fe15e0SLoGin     pub fn mmap(
20840fe15e0SLoGin         start_vaddr: VirtAddr,
20940fe15e0SLoGin         len: usize,
21040fe15e0SLoGin         prot_flags: usize,
21140fe15e0SLoGin         map_flags: usize,
21240fe15e0SLoGin         _fd: i32,
21340fe15e0SLoGin         _offset: usize,
21440fe15e0SLoGin     ) -> Result<usize, SystemError> {
21540fe15e0SLoGin         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
21640fe15e0SLoGin         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
21740fe15e0SLoGin 
21840fe15e0SLoGin         if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
21940fe15e0SLoGin             && map_flags.contains(MapFlags::MAP_FIXED)
22040fe15e0SLoGin         {
22140fe15e0SLoGin             kerror!(
22240fe15e0SLoGin                 "mmap: MAP_FIXED is not supported for address below {}",
22340fe15e0SLoGin                 DEFAULT_MMAP_MIN_ADDR
22440fe15e0SLoGin             );
22540fe15e0SLoGin             return Err(SystemError::EINVAL);
226d8ad0a5eSLoGin         }
22740fe15e0SLoGin         // 暂时不支持除匿名页以外的映射
22840fe15e0SLoGin         if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
22940fe15e0SLoGin             kerror!("mmap: not support file mapping");
23040fe15e0SLoGin             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
23140fe15e0SLoGin         }
23240fe15e0SLoGin 
23340fe15e0SLoGin         // 暂时不支持巨页映射
23440fe15e0SLoGin         if map_flags.contains(MapFlags::MAP_HUGETLB) {
23540fe15e0SLoGin             kerror!("mmap: not support huge page mapping");
23640fe15e0SLoGin             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
23740fe15e0SLoGin         }
23840fe15e0SLoGin         let current_address_space = AddressSpace::current()?;
23940fe15e0SLoGin         let start_page = current_address_space.write().map_anonymous(
24040fe15e0SLoGin             start_vaddr,
24140fe15e0SLoGin             len,
24240fe15e0SLoGin             prot_flags,
24340fe15e0SLoGin             map_flags,
24440fe15e0SLoGin             true,
24540fe15e0SLoGin         )?;
24640fe15e0SLoGin         return Ok(start_page.virt_address().data());
24740fe15e0SLoGin     }
24840fe15e0SLoGin 
2494cfa009bSJomo     /// ## mremap系统调用
2504cfa009bSJomo     ///
2514cfa009bSJomo     ///
2524cfa009bSJomo     /// ## 参数
2534cfa009bSJomo     ///
2544cfa009bSJomo     /// - `old_vaddr`:原映射的起始地址
2554cfa009bSJomo     /// - `old_len`:原映射的长度
2564cfa009bSJomo     /// - `new_len`:重新映射的长度
2574cfa009bSJomo     /// - `mremap_flags`:重映射标志
2584cfa009bSJomo     /// - `new_vaddr`:重新映射的起始地址
2594cfa009bSJomo     ///
2604cfa009bSJomo     /// ## 返回值
2614cfa009bSJomo     ///
2624cfa009bSJomo     /// 成功时返回重映射的起始地址,失败时返回错误码
2634cfa009bSJomo     pub fn mremap(
2644cfa009bSJomo         old_vaddr: VirtAddr,
2654cfa009bSJomo         old_len: usize,
2664cfa009bSJomo         new_len: usize,
2674cfa009bSJomo         mremap_flags: MremapFlags,
2684cfa009bSJomo         new_vaddr: VirtAddr,
2694cfa009bSJomo     ) -> Result<usize, SystemError> {
2704cfa009bSJomo         // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
2714cfa009bSJomo         if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
2724cfa009bSJomo             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
2734cfa009bSJomo                 || new_vaddr == VirtAddr::new(0))
2744cfa009bSJomo         {
2754cfa009bSJomo             return Err(SystemError::EINVAL);
2764cfa009bSJomo         }
2774cfa009bSJomo 
2784cfa009bSJomo         // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
2794cfa009bSJomo         if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
2804cfa009bSJomo             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
2814cfa009bSJomo         {
2824cfa009bSJomo             return Err(SystemError::EINVAL);
2834cfa009bSJomo         }
2844cfa009bSJomo 
2854cfa009bSJomo         // 旧内存地址必须对齐
2864cfa009bSJomo         if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
2874cfa009bSJomo             return Err(SystemError::EINVAL);
2884cfa009bSJomo         }
2894cfa009bSJomo 
2904cfa009bSJomo         // 将old_len、new_len 对齐页面大小
2914cfa009bSJomo         let old_len = page_align_up(old_len);
2924cfa009bSJomo         let new_len = page_align_up(new_len);
2934cfa009bSJomo 
2944cfa009bSJomo         // 不允许重映射内存区域大小为0
2954cfa009bSJomo         if new_len == 0 {
2964cfa009bSJomo             return Err(SystemError::EINVAL);
2974cfa009bSJomo         }
2984cfa009bSJomo 
2994cfa009bSJomo         let current_address_space = AddressSpace::current()?;
3004cfa009bSJomo         let vma = current_address_space.read().mappings.contains(old_vaddr);
3014cfa009bSJomo         if vma.is_none() {
3024cfa009bSJomo             return Err(SystemError::EINVAL);
3034cfa009bSJomo         }
3044cfa009bSJomo         let vma = vma.unwrap();
3054cfa009bSJomo         let vm_flags = vma.lock().vm_flags().clone();
3064cfa009bSJomo 
3074cfa009bSJomo         // 暂时不支持巨页映射
3084cfa009bSJomo         if vm_flags.contains(VmFlags::VM_HUGETLB) {
3094cfa009bSJomo             kerror!("mmap: not support huge page mapping");
3104cfa009bSJomo             return Err(SystemError::ENOSYS);
3114cfa009bSJomo         }
3124cfa009bSJomo 
3134cfa009bSJomo         // 缩小旧内存映射区域
3144cfa009bSJomo         if old_len > new_len {
3154cfa009bSJomo             Self::munmap(old_vaddr + new_len, old_len - new_len)?;
3164cfa009bSJomo             return Ok(old_vaddr.data());
3174cfa009bSJomo         }
3184cfa009bSJomo 
3194cfa009bSJomo         // 重映射到新内存区域
3204cfa009bSJomo         let r = current_address_space.write().mremap(
3214cfa009bSJomo             old_vaddr,
3224cfa009bSJomo             old_len,
3234cfa009bSJomo             new_len,
3244cfa009bSJomo             mremap_flags,
3254cfa009bSJomo             new_vaddr,
3264cfa009bSJomo             vm_flags,
3274cfa009bSJomo         )?;
3284cfa009bSJomo 
3294cfa009bSJomo         if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
3304cfa009bSJomo             Self::munmap(old_vaddr, old_len)?;
3314cfa009bSJomo         }
3324cfa009bSJomo 
3334cfa009bSJomo         return Ok(r.data());
3344cfa009bSJomo     }
3354cfa009bSJomo 
33640fe15e0SLoGin     /// ## munmap系统调用
33740fe15e0SLoGin     ///
33840fe15e0SLoGin     /// ## 参数
33940fe15e0SLoGin     ///
34040fe15e0SLoGin     /// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
34140fe15e0SLoGin     /// - `len`:取消映射的字节数(已经对齐到页)
34240fe15e0SLoGin     ///
34340fe15e0SLoGin     /// ## 返回值
34440fe15e0SLoGin     ///
34540fe15e0SLoGin     /// 成功时返回0,失败时返回错误码
34640fe15e0SLoGin     pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
34740fe15e0SLoGin         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
34840fe15e0SLoGin         assert!(check_aligned(len, MMArch::PAGE_SIZE));
34940fe15e0SLoGin 
35040fe15e0SLoGin         if unlikely(verify_area(start_vaddr, len).is_err()) {
35140fe15e0SLoGin             return Err(SystemError::EINVAL);
35240fe15e0SLoGin         }
35340fe15e0SLoGin         if unlikely(len == 0) {
35440fe15e0SLoGin             return Err(SystemError::EINVAL);
35540fe15e0SLoGin         }
35640fe15e0SLoGin 
35740fe15e0SLoGin         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
35840fe15e0SLoGin         let start_frame = VirtPageFrame::new(start_vaddr);
35940fe15e0SLoGin         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
36040fe15e0SLoGin 
36140fe15e0SLoGin         current_address_space
36240fe15e0SLoGin             .write()
36340fe15e0SLoGin             .munmap(start_frame, page_count)
36440fe15e0SLoGin             .map_err(|_| SystemError::EINVAL)?;
3654cfa009bSJomo 
36640fe15e0SLoGin         return Ok(0);
36740fe15e0SLoGin     }
36840fe15e0SLoGin 
36940fe15e0SLoGin     /// ## mprotect系统调用
37040fe15e0SLoGin     ///
37140fe15e0SLoGin     /// ## 参数
37240fe15e0SLoGin     ///
37340fe15e0SLoGin     /// - `start_vaddr`:起始地址(已经对齐到页)
37440fe15e0SLoGin     /// - `len`:长度(已经对齐到页)
37540fe15e0SLoGin     /// - `prot_flags`:保护标志
37640fe15e0SLoGin     pub fn mprotect(
37740fe15e0SLoGin         start_vaddr: VirtAddr,
37840fe15e0SLoGin         len: usize,
37940fe15e0SLoGin         prot_flags: usize,
38040fe15e0SLoGin     ) -> Result<usize, SystemError> {
38140fe15e0SLoGin         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
38240fe15e0SLoGin         assert!(check_aligned(len, MMArch::PAGE_SIZE));
38340fe15e0SLoGin 
38440fe15e0SLoGin         if unlikely(verify_area(start_vaddr, len).is_err()) {
38540fe15e0SLoGin             return Err(SystemError::EINVAL);
38640fe15e0SLoGin         }
38740fe15e0SLoGin         if unlikely(len == 0) {
38840fe15e0SLoGin             return Err(SystemError::EINVAL);
38940fe15e0SLoGin         }
39040fe15e0SLoGin 
39140fe15e0SLoGin         let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
39240fe15e0SLoGin 
39340fe15e0SLoGin         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
39440fe15e0SLoGin         let start_frame = VirtPageFrame::new(start_vaddr);
39540fe15e0SLoGin         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
39640fe15e0SLoGin 
39740fe15e0SLoGin         current_address_space
39840fe15e0SLoGin             .write()
39940fe15e0SLoGin             .mprotect(start_frame, page_count, prot_flags)
40040fe15e0SLoGin             .map_err(|_| SystemError::EINVAL)?;
40140fe15e0SLoGin         return Ok(0);
402ab5c8ca4Slogin     }
403ab5c8ca4Slogin }
404