xref: /DragonOS/kernel/src/mm/syscall.rs (revision 1f4877a4c512eb5ad232436128a0c52287b39aaa)
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     pub struct MadvFlags: u64 {
78         /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景
79         const MADV_NORMAL = 0;
80         /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景
81         const MADV_RANDOM = 1;
82         /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景
83         const MADV_SEQUENTIAL = 2;
84         /// 通知系统预读某些页面,用于应用程序提前准备数据
85         const MADV_WILLNEED = 3;
86         /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源
87         const MADV_DONTNEED = 4;
88 
89         /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时
90         const MADV_FREE = 8;
91         /// 应用程序请求释放指定范围的页面和相关的后备存储
92         const MADV_REMOVE = 9;
93         /// 在 fork 时排除指定区域
94         const MADV_DONTFORK = 10;
95         /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域
96         const MADV_DOFORK = 11;
97         /// 模拟内存硬件错误,触发内存错误处理器处理
98         const MADV_HWPOISON = 100;
99         /// 尝试软下线指定的内存范围
100         const MADV_SOFT_OFFLINE = 101;
101 
102         /// 应用程序建议内核尝试合并指定范围内内容相同的页面
103         const MADV_MERGEABLE = 12;
104         /// 取消 MADV_MERGEABLE 的效果,不再合并页面
105         const MADV_UNMERGEABLE = 13;
106 
107         /// 应用程序希望将指定范围以透明大页方式支持
108         const MADV_HUGEPAGE = 14;
109         /// 将指定范围标记为不值得用透明大页支持
110         const MADV_NOHUGEPAGE = 15;
111 
112         /// 应用程序请求在核心转储时排除指定范围内的页面
113         const MADV_DONTDUMP = 16;
114         /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面
115         const MADV_DODUMP = 17;
116 
117         /// 在 fork 时将子进程的该区域内存填充为零
118         const MADV_WIPEONFORK = 18;
119         /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存
120         const MADV_KEEPONFORK = 19;
121 
122         /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收
123         const MADV_COLD = 20;
124         /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出
125         const MADV_PAGEOUT = 21;
126 
127         /// 预先填充页面表,可读,通过触发读取故障
128         const MADV_POPULATE_READ = 22;
129         /// 预先填充页面表,可写,通过触发写入故障
130         const MADV_POPULATE_WRITE = 23;
131 
132         /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放
133         const MADV_DONTNEED_LOCKED = 24;
134 
135         /// 同步将页面合并为新的透明大页
136         const MADV_COLLAPSE = 25;
137 
138     }
139 }
140 
141 impl From<MapFlags> for VmFlags {
142     fn from(map_flags: MapFlags) -> Self {
143         let mut vm_flags = VmFlags::VM_NONE;
144 
145         if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
146             vm_flags |= VmFlags::VM_GROWSDOWN;
147         }
148 
149         if map_flags.contains(MapFlags::MAP_LOCKED) {
150             vm_flags |= VmFlags::VM_LOCKED;
151         }
152 
153         if map_flags.contains(MapFlags::MAP_SYNC) {
154             vm_flags |= VmFlags::VM_SYNC;
155         }
156 
157         vm_flags
158     }
159 }
160 
161 impl From<ProtFlags> for VmFlags {
162     fn from(prot_flags: ProtFlags) -> Self {
163         let mut vm_flags = VmFlags::VM_NONE;
164 
165         if prot_flags.contains(ProtFlags::PROT_READ) {
166             vm_flags |= VmFlags::VM_READ;
167         }
168 
169         if prot_flags.contains(ProtFlags::PROT_WRITE) {
170             vm_flags |= VmFlags::VM_WRITE;
171         }
172 
173         if prot_flags.contains(ProtFlags::PROT_EXEC) {
174             vm_flags |= VmFlags::VM_EXEC;
175         }
176 
177         vm_flags
178     }
179 }
180 
181 impl From<ShmFlags> for VmFlags {
182     fn from(shm_flags: ShmFlags) -> Self {
183         let mut vm_flags = VmFlags::VM_NONE;
184 
185         if shm_flags.contains(ShmFlags::SHM_RDONLY) {
186             vm_flags |= VmFlags::VM_READ;
187         } else {
188             vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE;
189         }
190 
191         if shm_flags.contains(ShmFlags::SHM_EXEC) {
192             vm_flags |= VmFlags::VM_EXEC;
193         }
194 
195         if shm_flags.contains(ShmFlags::SHM_HUGETLB) {
196             vm_flags |= VmFlags::VM_HUGETLB;
197         }
198 
199         vm_flags
200     }
201 }
202 
203 impl From<VmFlags> for MapFlags {
204     fn from(value: VmFlags) -> Self {
205         let mut map_flags = MapFlags::MAP_NONE;
206 
207         if value.contains(VmFlags::VM_GROWSDOWN) {
208             map_flags |= MapFlags::MAP_GROWSDOWN;
209         }
210 
211         if value.contains(VmFlags::VM_LOCKED) {
212             map_flags |= MapFlags::MAP_LOCKED;
213         }
214 
215         if value.contains(VmFlags::VM_SYNC) {
216             map_flags |= MapFlags::MAP_SYNC;
217         }
218 
219         if value.contains(VmFlags::VM_MAYSHARE) {
220             map_flags |= MapFlags::MAP_SHARED;
221         }
222 
223         map_flags
224     }
225 }
226 
227 impl From<VmFlags> for ProtFlags {
228     fn from(value: VmFlags) -> Self {
229         let mut prot_flags = ProtFlags::PROT_NONE;
230 
231         if value.contains(VmFlags::VM_READ) {
232             prot_flags |= ProtFlags::PROT_READ;
233         }
234 
235         if value.contains(VmFlags::VM_WRITE) {
236             prot_flags |= ProtFlags::PROT_WRITE;
237         }
238 
239         if value.contains(VmFlags::VM_EXEC) {
240             prot_flags |= ProtFlags::PROT_EXEC;
241         }
242 
243         prot_flags
244     }
245 }
246 
247 impl Syscall {
248     pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
249         // kdebug!("brk: new_addr={:?}", new_addr);
250         let address_space = AddressSpace::current()?;
251         let mut address_space = address_space.write();
252 
253         if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
254             return Ok(address_space.brk);
255         }
256         if new_addr == address_space.brk {
257             return Ok(address_space.brk);
258         }
259 
260         unsafe {
261             address_space
262                 .set_brk(VirtAddr::new(page_align_up(new_addr.data())))
263                 .ok();
264 
265             return Ok(address_space.sbrk(0).unwrap());
266         }
267     }
268 
269     pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
270         let address_space = AddressSpace::current()?;
271         assert!(address_space.read().user_mapper.utable.is_current());
272         let mut address_space = address_space.write();
273         let r = unsafe { address_space.sbrk(incr) };
274 
275         return r;
276     }
277 
278     /// ## mmap系统调用
279     ///
280     /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
281     ///
282     /// ## 参数
283     ///
284     /// - `start_vaddr`:映射的起始地址
285     /// - `len`:映射的长度
286     /// - `prot`:保护标志
287     /// - `flags`:映射标志
288     /// - `fd`:文件描述符(暂时不支持)
289     /// - `offset`:文件偏移量 (暂时不支持)
290     ///
291     /// ## 返回值
292     ///
293     /// 成功时返回映射的起始地址,失败时返回错误码
294     pub fn mmap(
295         start_vaddr: VirtAddr,
296         len: usize,
297         prot_flags: usize,
298         map_flags: usize,
299         _fd: i32,
300         _offset: usize,
301     ) -> Result<usize, SystemError> {
302         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
303         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
304 
305         if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
306             && map_flags.contains(MapFlags::MAP_FIXED)
307         {
308             kerror!(
309                 "mmap: MAP_FIXED is not supported for address below {}",
310                 DEFAULT_MMAP_MIN_ADDR
311             );
312             return Err(SystemError::EINVAL);
313         }
314         // 暂时不支持除匿名页以外的映射
315         if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
316             kerror!("mmap: not support file mapping");
317             return Err(SystemError::ENOSYS);
318         }
319 
320         // 暂时不支持巨页映射
321         if map_flags.contains(MapFlags::MAP_HUGETLB) {
322             kerror!("mmap: not support huge page mapping");
323             return Err(SystemError::ENOSYS);
324         }
325         let current_address_space = AddressSpace::current()?;
326         let start_page = current_address_space.write().map_anonymous(
327             start_vaddr,
328             len,
329             prot_flags,
330             map_flags,
331             true,
332             true,
333         )?;
334         return Ok(start_page.virt_address().data());
335     }
336 
337     /// ## mremap系统调用
338     ///
339     ///
340     /// ## 参数
341     ///
342     /// - `old_vaddr`:原映射的起始地址
343     /// - `old_len`:原映射的长度
344     /// - `new_len`:重新映射的长度
345     /// - `mremap_flags`:重映射标志
346     /// - `new_vaddr`:重新映射的起始地址
347     ///
348     /// ## 返回值
349     ///
350     /// 成功时返回重映射的起始地址,失败时返回错误码
351     pub fn mremap(
352         old_vaddr: VirtAddr,
353         old_len: usize,
354         new_len: usize,
355         mremap_flags: MremapFlags,
356         new_vaddr: VirtAddr,
357     ) -> Result<usize, SystemError> {
358         // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
359         if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
360             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
361                 || new_vaddr == VirtAddr::new(0))
362         {
363             return Err(SystemError::EINVAL);
364         }
365 
366         // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
367         if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
368             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
369         {
370             return Err(SystemError::EINVAL);
371         }
372 
373         // 旧内存地址必须对齐
374         if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
375             return Err(SystemError::EINVAL);
376         }
377 
378         // 将old_len、new_len 对齐页面大小
379         let old_len = page_align_up(old_len);
380         let new_len = page_align_up(new_len);
381 
382         // 不允许重映射内存区域大小为0
383         if new_len == 0 {
384             return Err(SystemError::EINVAL);
385         }
386 
387         let current_address_space = AddressSpace::current()?;
388         let vma = current_address_space.read().mappings.contains(old_vaddr);
389         if vma.is_none() {
390             return Err(SystemError::EINVAL);
391         }
392         let vma = vma.unwrap();
393         let vm_flags = *vma.lock().vm_flags();
394 
395         // 暂时不支持巨页映射
396         if vm_flags.contains(VmFlags::VM_HUGETLB) {
397             kerror!("mmap: not support huge page mapping");
398             return Err(SystemError::ENOSYS);
399         }
400 
401         // 缩小旧内存映射区域
402         if old_len > new_len {
403             Self::munmap(old_vaddr + new_len, old_len - new_len)?;
404             return Ok(old_vaddr.data());
405         }
406 
407         // 重映射到新内存区域
408         let r = current_address_space.write().mremap(
409             old_vaddr,
410             old_len,
411             new_len,
412             mremap_flags,
413             new_vaddr,
414             vm_flags,
415         )?;
416 
417         if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
418             Self::munmap(old_vaddr, old_len)?;
419         }
420 
421         return Ok(r.data());
422     }
423 
424     /// ## munmap系统调用
425     ///
426     /// ## 参数
427     ///
428     /// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
429     /// - `len`:取消映射的字节数(已经对齐到页)
430     ///
431     /// ## 返回值
432     ///
433     /// 成功时返回0,失败时返回错误码
434     pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
435         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
436         assert!(check_aligned(len, MMArch::PAGE_SIZE));
437 
438         if unlikely(verify_area(start_vaddr, len).is_err()) {
439             return Err(SystemError::EINVAL);
440         }
441         if unlikely(len == 0) {
442             return Err(SystemError::EINVAL);
443         }
444 
445         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
446         let start_frame = VirtPageFrame::new(start_vaddr);
447         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
448 
449         current_address_space
450             .write()
451             .munmap(start_frame, page_count)
452             .map_err(|_| SystemError::EINVAL)?;
453 
454         return Ok(0);
455     }
456 
457     /// ## mprotect系统调用
458     ///
459     /// ## 参数
460     ///
461     /// - `start_vaddr`:起始地址(已经对齐到页)
462     /// - `len`:长度(已经对齐到页)
463     /// - `prot_flags`:保护标志
464     pub fn mprotect(
465         start_vaddr: VirtAddr,
466         len: usize,
467         prot_flags: usize,
468     ) -> Result<usize, SystemError> {
469         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
470         assert!(check_aligned(len, MMArch::PAGE_SIZE));
471 
472         if unlikely(verify_area(start_vaddr, len).is_err()) {
473             return Err(SystemError::EINVAL);
474         }
475         if unlikely(len == 0) {
476             return Err(SystemError::EINVAL);
477         }
478 
479         let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
480 
481         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
482         let start_frame = VirtPageFrame::new(start_vaddr);
483         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
484 
485         current_address_space
486             .write()
487             .mprotect(start_frame, page_count, prot_flags)
488             .map_err(|_| SystemError::EINVAL)?;
489         return Ok(0);
490     }
491 
492     /// ## madvise系统调用
493     ///
494     /// ## 参数
495     ///
496     /// - `start_vaddr`:起始地址(已经对齐到页)
497     /// - `len`:长度(已经对齐到页)
498     /// - `madv_flags`:建议标志
499     pub fn madvise(
500         start_vaddr: VirtAddr,
501         len: usize,
502         madv_flags: usize,
503     ) -> Result<usize, SystemError> {
504         if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
505             return Err(SystemError::EINVAL);
506         }
507 
508         if unlikely(verify_area(start_vaddr, len).is_err()) {
509             return Err(SystemError::EINVAL);
510         }
511         if unlikely(len == 0) {
512             return Err(SystemError::EINVAL);
513         }
514 
515         let madv_flags = MadvFlags::from_bits(madv_flags as u64).ok_or(SystemError::EINVAL)?;
516 
517         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
518         let start_frame = VirtPageFrame::new(start_vaddr);
519         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
520 
521         current_address_space
522             .write()
523             .madvise(start_frame, page_count, madv_flags)
524             .map_err(|_| SystemError::EINVAL)?;
525         return Ok(0);
526     }
527 }
528