xref: /DragonOS/kernel/src/mm/syscall.rs (revision 2709e017d0d216d61b2caed3c7286459de7794c7)
1 use core::intrinsics::unlikely;
2 
3 use alloc::sync::Arc;
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::MMArch,
8     ipc::shm::ShmFlags,
9     kerror,
10     libs::align::{check_aligned, page_align_up},
11     mm::MemoryManagementArch,
12     syscall::Syscall,
13 };
14 
15 use super::{
16     allocator::page_frame::{PageFrameCount, VirtPageFrame},
17     ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
18     verify_area, VirtAddr, VmFlags,
19 };
20 
21 bitflags! {
22     /// Memory protection flags
23     pub struct ProtFlags: u64 {
24         const PROT_NONE = 0x0;
25         const PROT_READ = 0x1;
26         const PROT_WRITE = 0x2;
27         const PROT_EXEC = 0x4;
28     }
29 
30     /// Memory mapping flags
31     pub struct MapFlags: u64 {
32         const MAP_NONE = 0x0;
33         /// share changes
34         const MAP_SHARED = 0x1;
35         /// changes are private
36         const MAP_PRIVATE = 0x2;
37         /// Interpret addr exactly
38         const MAP_FIXED = 0x10;
39         /// don't use a file
40         const MAP_ANONYMOUS = 0x20;
41         // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
42         /// stack-like segment
43         const MAP_GROWSDOWN = 0x100;
44         /// ETXTBSY
45         const MAP_DENYWRITE = 0x800;
46         /// Mark it as an executable
47         const MAP_EXECUTABLE = 0x1000;
48         /// Pages are locked
49         const MAP_LOCKED = 0x2000;
50         /// don't check for reservations
51         const MAP_NORESERVE = 0x4000;
52         /// populate (prefault) pagetables
53         const MAP_POPULATE = 0x8000;
54         /// do not block on IO
55         const MAP_NONBLOCK = 0x10000;
56         /// give out an address that is best suited for process/thread stacks
57         const MAP_STACK = 0x20000;
58         /// create a huge page mapping
59         const MAP_HUGETLB = 0x40000;
60         /// perform synchronous page faults for the mapping
61         const MAP_SYNC = 0x80000;
62         /// MAP_FIXED which doesn't unmap underlying mapping
63         const MAP_FIXED_NOREPLACE = 0x100000;
64 
65         /// For anonymous mmap, memory could be uninitialized
66         const MAP_UNINITIALIZED = 0x4000000;
67     }
68 
69     /// Memory mremapping flags
70     pub struct MremapFlags: u8 {
71         const MREMAP_MAYMOVE = 1;
72         const MREMAP_FIXED = 2;
73         const MREMAP_DONTUNMAP = 4;
74     }
75 }
76 
77 impl From<MapFlags> for VmFlags {
78     fn from(map_flags: MapFlags) -> Self {
79         let mut vm_flags = VmFlags::VM_NONE;
80 
81         if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
82             vm_flags |= VmFlags::VM_GROWSDOWN;
83         }
84 
85         if map_flags.contains(MapFlags::MAP_LOCKED) {
86             vm_flags |= VmFlags::VM_LOCKED;
87         }
88 
89         if map_flags.contains(MapFlags::MAP_SYNC) {
90             vm_flags |= VmFlags::VM_SYNC;
91         }
92 
93         vm_flags
94     }
95 }
96 
97 impl From<ProtFlags> for VmFlags {
98     fn from(prot_flags: ProtFlags) -> Self {
99         let mut vm_flags = VmFlags::VM_NONE;
100 
101         if prot_flags.contains(ProtFlags::PROT_READ) {
102             vm_flags |= VmFlags::VM_READ;
103         }
104 
105         if prot_flags.contains(ProtFlags::PROT_WRITE) {
106             vm_flags |= VmFlags::VM_WRITE;
107         }
108 
109         if prot_flags.contains(ProtFlags::PROT_EXEC) {
110             vm_flags |= VmFlags::VM_EXEC;
111         }
112 
113         vm_flags
114     }
115 }
116 
117 impl From<ShmFlags> for VmFlags {
118     fn from(shm_flags: ShmFlags) -> Self {
119         let mut vm_flags = VmFlags::VM_NONE;
120 
121         if shm_flags.contains(ShmFlags::SHM_RDONLY) {
122             vm_flags |= VmFlags::VM_READ;
123         } else {
124             vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE;
125         }
126 
127         if shm_flags.contains(ShmFlags::SHM_EXEC) {
128             vm_flags |= VmFlags::VM_EXEC;
129         }
130 
131         if shm_flags.contains(ShmFlags::SHM_HUGETLB) {
132             vm_flags |= VmFlags::VM_HUGETLB;
133         }
134 
135         vm_flags
136     }
137 }
138 
139 impl From<VmFlags> for MapFlags {
140     fn from(value: VmFlags) -> Self {
141         let mut map_flags = MapFlags::MAP_NONE;
142 
143         if value.contains(VmFlags::VM_GROWSDOWN) {
144             map_flags |= MapFlags::MAP_GROWSDOWN;
145         }
146 
147         if value.contains(VmFlags::VM_LOCKED) {
148             map_flags |= MapFlags::MAP_LOCKED;
149         }
150 
151         if value.contains(VmFlags::VM_SYNC) {
152             map_flags |= MapFlags::MAP_SYNC;
153         }
154 
155         if value.contains(VmFlags::VM_MAYSHARE) {
156             map_flags |= MapFlags::MAP_SHARED;
157         }
158 
159         map_flags
160     }
161 }
162 
163 impl From<VmFlags> for ProtFlags {
164     fn from(value: VmFlags) -> Self {
165         let mut prot_flags = ProtFlags::PROT_NONE;
166 
167         if value.contains(VmFlags::VM_READ) {
168             prot_flags |= ProtFlags::PROT_READ;
169         }
170 
171         if value.contains(VmFlags::VM_WRITE) {
172             prot_flags |= ProtFlags::PROT_WRITE;
173         }
174 
175         if value.contains(VmFlags::VM_EXEC) {
176             prot_flags |= ProtFlags::PROT_EXEC;
177         }
178 
179         prot_flags
180     }
181 }
182 
183 impl Syscall {
184     pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
185         // kdebug!("brk: new_addr={:?}", new_addr);
186         let address_space = AddressSpace::current()?;
187         let mut address_space = address_space.write();
188 
189         if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
190             return Ok(address_space.brk);
191         }
192         if new_addr == address_space.brk {
193             return Ok(address_space.brk);
194         }
195 
196         unsafe {
197             address_space
198                 .set_brk(VirtAddr::new(page_align_up(new_addr.data())))
199                 .ok();
200 
201             return Ok(address_space.sbrk(0).unwrap());
202         }
203     }
204 
205     pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
206         let address_space = AddressSpace::current()?;
207         assert!(address_space.read().user_mapper.utable.is_current());
208         let mut address_space = address_space.write();
209         let r = unsafe { address_space.sbrk(incr) };
210 
211         return r;
212     }
213 
214     /// ## mmap系统调用
215     ///
216     /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
217     ///
218     /// ## 参数
219     ///
220     /// - `start_vaddr`:映射的起始地址
221     /// - `len`:映射的长度
222     /// - `prot`:保护标志
223     /// - `flags`:映射标志
224     /// - `fd`:文件描述符(暂时不支持)
225     /// - `offset`:文件偏移量 (暂时不支持)
226     ///
227     /// ## 返回值
228     ///
229     /// 成功时返回映射的起始地址,失败时返回错误码
230     pub fn mmap(
231         start_vaddr: VirtAddr,
232         len: usize,
233         prot_flags: usize,
234         map_flags: usize,
235         _fd: i32,
236         _offset: usize,
237     ) -> Result<usize, SystemError> {
238         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
239         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
240 
241         if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
242             && map_flags.contains(MapFlags::MAP_FIXED)
243         {
244             kerror!(
245                 "mmap: MAP_FIXED is not supported for address below {}",
246                 DEFAULT_MMAP_MIN_ADDR
247             );
248             return Err(SystemError::EINVAL);
249         }
250         // 暂时不支持除匿名页以外的映射
251         if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
252             kerror!("mmap: not support file mapping");
253             return Err(SystemError::ENOSYS);
254         }
255 
256         // 暂时不支持巨页映射
257         if map_flags.contains(MapFlags::MAP_HUGETLB) {
258             kerror!("mmap: not support huge page mapping");
259             return Err(SystemError::ENOSYS);
260         }
261         let current_address_space = AddressSpace::current()?;
262         let start_page = current_address_space.write().map_anonymous(
263             start_vaddr,
264             len,
265             prot_flags,
266             map_flags,
267             true,
268         )?;
269         return Ok(start_page.virt_address().data());
270     }
271 
272     /// ## mremap系统调用
273     ///
274     ///
275     /// ## 参数
276     ///
277     /// - `old_vaddr`:原映射的起始地址
278     /// - `old_len`:原映射的长度
279     /// - `new_len`:重新映射的长度
280     /// - `mremap_flags`:重映射标志
281     /// - `new_vaddr`:重新映射的起始地址
282     ///
283     /// ## 返回值
284     ///
285     /// 成功时返回重映射的起始地址,失败时返回错误码
286     pub fn mremap(
287         old_vaddr: VirtAddr,
288         old_len: usize,
289         new_len: usize,
290         mremap_flags: MremapFlags,
291         new_vaddr: VirtAddr,
292     ) -> Result<usize, SystemError> {
293         // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
294         if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
295             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
296                 || new_vaddr == VirtAddr::new(0))
297         {
298             return Err(SystemError::EINVAL);
299         }
300 
301         // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
302         if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
303             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
304         {
305             return Err(SystemError::EINVAL);
306         }
307 
308         // 旧内存地址必须对齐
309         if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
310             return Err(SystemError::EINVAL);
311         }
312 
313         // 将old_len、new_len 对齐页面大小
314         let old_len = page_align_up(old_len);
315         let new_len = page_align_up(new_len);
316 
317         // 不允许重映射内存区域大小为0
318         if new_len == 0 {
319             return Err(SystemError::EINVAL);
320         }
321 
322         let current_address_space = AddressSpace::current()?;
323         let vma = current_address_space.read().mappings.contains(old_vaddr);
324         if vma.is_none() {
325             return Err(SystemError::EINVAL);
326         }
327         let vma = vma.unwrap();
328         let vm_flags = *vma.lock().vm_flags();
329 
330         // 暂时不支持巨页映射
331         if vm_flags.contains(VmFlags::VM_HUGETLB) {
332             kerror!("mmap: not support huge page mapping");
333             return Err(SystemError::ENOSYS);
334         }
335 
336         // 缩小旧内存映射区域
337         if old_len > new_len {
338             Self::munmap(old_vaddr + new_len, old_len - new_len)?;
339             return Ok(old_vaddr.data());
340         }
341 
342         // 重映射到新内存区域
343         let r = current_address_space.write().mremap(
344             old_vaddr,
345             old_len,
346             new_len,
347             mremap_flags,
348             new_vaddr,
349             vm_flags,
350         )?;
351 
352         if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
353             Self::munmap(old_vaddr, old_len)?;
354         }
355 
356         return Ok(r.data());
357     }
358 
359     /// ## munmap系统调用
360     ///
361     /// ## 参数
362     ///
363     /// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
364     /// - `len`:取消映射的字节数(已经对齐到页)
365     ///
366     /// ## 返回值
367     ///
368     /// 成功时返回0,失败时返回错误码
369     pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
370         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
371         assert!(check_aligned(len, MMArch::PAGE_SIZE));
372 
373         if unlikely(verify_area(start_vaddr, len).is_err()) {
374             return Err(SystemError::EINVAL);
375         }
376         if unlikely(len == 0) {
377             return Err(SystemError::EINVAL);
378         }
379 
380         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
381         let start_frame = VirtPageFrame::new(start_vaddr);
382         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
383 
384         current_address_space
385             .write()
386             .munmap(start_frame, page_count)
387             .map_err(|_| SystemError::EINVAL)?;
388 
389         return Ok(0);
390     }
391 
392     /// ## mprotect系统调用
393     ///
394     /// ## 参数
395     ///
396     /// - `start_vaddr`:起始地址(已经对齐到页)
397     /// - `len`:长度(已经对齐到页)
398     /// - `prot_flags`:保护标志
399     pub fn mprotect(
400         start_vaddr: VirtAddr,
401         len: usize,
402         prot_flags: usize,
403     ) -> Result<usize, SystemError> {
404         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
405         assert!(check_aligned(len, MMArch::PAGE_SIZE));
406 
407         if unlikely(verify_area(start_vaddr, len).is_err()) {
408             return Err(SystemError::EINVAL);
409         }
410         if unlikely(len == 0) {
411             return Err(SystemError::EINVAL);
412         }
413 
414         let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
415 
416         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
417         let start_frame = VirtPageFrame::new(start_vaddr);
418         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
419 
420         current_address_space
421             .write()
422             .mprotect(start_frame, page_count, prot_flags)
423             .map_err(|_| SystemError::EINVAL)?;
424         return Ok(0);
425     }
426 }
427