xref: /DragonOS/kernel/src/mm/syscall.rs (revision d8e29bffeee4fe4fe76ead3c761dd03f5395e6c2)
1 use core::intrinsics::unlikely;
2 
3 use alloc::sync::Arc;
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::MMArch,
8     kerror,
9     libs::align::{check_aligned, page_align_up},
10     mm::MemoryManagementArch,
11     syscall::Syscall,
12 };
13 
14 use super::{
15     allocator::page_frame::{PageFrameCount, VirtPageFrame},
16     ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
17     verify_area, VirtAddr,
18 };
19 
20 bitflags! {
21     /// Memory protection flags
22     pub struct ProtFlags: u64 {
23         const PROT_NONE = 0x0;
24         const PROT_READ = 0x1;
25         const PROT_WRITE = 0x2;
26         const PROT_EXEC = 0x4;
27     }
28 
29     /// Memory mapping flags
30     pub struct MapFlags: u64 {
31         const MAP_NONE = 0x0;
32         /// share changes
33         const MAP_SHARED = 0x1;
34         /// changes are private
35         const MAP_PRIVATE = 0x2;
36         /// Interpret addr exactly
37         const MAP_FIXED = 0x10;
38         /// don't use a file
39         const MAP_ANONYMOUS = 0x20;
40         // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
41         /// stack-like segment
42         const MAP_GROWSDOWN = 0x100;
43         /// ETXTBSY
44         const MAP_DENYWRITE = 0x800;
45         /// Mark it as an executable
46         const MAP_EXECUTABLE = 0x1000;
47         /// Pages are locked
48         const MAP_LOCKED = 0x2000;
49         /// don't check for reservations
50         const MAP_NORESERVE = 0x4000;
51         /// populate (prefault) pagetables
52         const MAP_POPULATE = 0x8000;
53         /// do not block on IO
54         const MAP_NONBLOCK = 0x10000;
55         /// give out an address that is best suited for process/thread stacks
56         const MAP_STACK = 0x20000;
57         /// create a huge page mapping
58         const MAP_HUGETLB = 0x40000;
59         /// perform synchronous page faults for the mapping
60         const MAP_SYNC = 0x80000;
61         /// MAP_FIXED which doesn't unmap underlying mapping
62         const MAP_FIXED_NOREPLACE = 0x100000;
63 
64         /// For anonymous mmap, memory could be uninitialized
65         const MAP_UNINITIALIZED = 0x4000000;
66 
67     }
68 }
69 
70 impl Syscall {
71     pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
72         // kdebug!("brk: new_addr={:?}", new_addr);
73         let address_space = AddressSpace::current()?;
74         let mut address_space = address_space.write();
75 
76         if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
77             return Ok(address_space.brk);
78         }
79         if new_addr == address_space.brk {
80             return Ok(address_space.brk);
81         }
82 
83         unsafe {
84             address_space
85                 .set_brk(VirtAddr::new(page_align_up(new_addr.data())))
86                 .ok();
87 
88             return Ok(address_space.sbrk(0).unwrap());
89         }
90     }
91 
92     pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
93         let address_space = AddressSpace::current()?;
94         assert!(address_space.read().user_mapper.utable.is_current());
95         let mut address_space = address_space.write();
96         let r = unsafe { address_space.sbrk(incr) };
97 
98         return r;
99     }
100 
101     /// ## mmap系统调用
102     ///
103     /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
104     ///
105     /// ## 参数
106     ///
107     /// - `start_vaddr`:映射的起始地址
108     /// - `len`:映射的长度
109     /// - `prot`:保护标志
110     /// - `flags`:映射标志
111     /// - `fd`:文件描述符(暂时不支持)
112     /// - `offset`:文件偏移量 (暂时不支持)
113     ///
114     /// ## 返回值
115     ///
116     /// 成功时返回映射的起始地址,失败时返回错误码
117     pub fn mmap(
118         start_vaddr: VirtAddr,
119         len: usize,
120         prot_flags: usize,
121         map_flags: usize,
122         _fd: i32,
123         _offset: usize,
124     ) -> Result<usize, SystemError> {
125         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
126         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
127 
128         if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
129             && map_flags.contains(MapFlags::MAP_FIXED)
130         {
131             kerror!(
132                 "mmap: MAP_FIXED is not supported for address below {}",
133                 DEFAULT_MMAP_MIN_ADDR
134             );
135             return Err(SystemError::EINVAL);
136         }
137         // 暂时不支持除匿名页以外的映射
138         if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
139             kerror!("mmap: not support file mapping");
140             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
141         }
142 
143         // 暂时不支持巨页映射
144         if map_flags.contains(MapFlags::MAP_HUGETLB) {
145             kerror!("mmap: not support huge page mapping");
146             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
147         }
148         let current_address_space = AddressSpace::current()?;
149         let start_page = current_address_space.write().map_anonymous(
150             start_vaddr,
151             len,
152             prot_flags,
153             map_flags,
154             true,
155         )?;
156         return Ok(start_page.virt_address().data());
157     }
158 
159     /// ## munmap系统调用
160     ///
161     /// ## 参数
162     ///
163     /// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
164     /// - `len`:取消映射的字节数(已经对齐到页)
165     ///
166     /// ## 返回值
167     ///
168     /// 成功时返回0,失败时返回错误码
169     pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
170         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
171         assert!(check_aligned(len, MMArch::PAGE_SIZE));
172 
173         if unlikely(verify_area(start_vaddr, len).is_err()) {
174             return Err(SystemError::EINVAL);
175         }
176         if unlikely(len == 0) {
177             return Err(SystemError::EINVAL);
178         }
179 
180         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
181         let start_frame = VirtPageFrame::new(start_vaddr);
182         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
183 
184         current_address_space
185             .write()
186             .munmap(start_frame, page_count)
187             .map_err(|_| SystemError::EINVAL)?;
188         return Ok(0);
189     }
190 
191     /// ## mprotect系统调用
192     ///
193     /// ## 参数
194     ///
195     /// - `start_vaddr`:起始地址(已经对齐到页)
196     /// - `len`:长度(已经对齐到页)
197     /// - `prot_flags`:保护标志
198     pub fn mprotect(
199         start_vaddr: VirtAddr,
200         len: usize,
201         prot_flags: usize,
202     ) -> Result<usize, SystemError> {
203         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
204         assert!(check_aligned(len, MMArch::PAGE_SIZE));
205 
206         if unlikely(verify_area(start_vaddr, len).is_err()) {
207             return Err(SystemError::EINVAL);
208         }
209         if unlikely(len == 0) {
210             return Err(SystemError::EINVAL);
211         }
212 
213         let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
214 
215         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
216         let start_frame = VirtPageFrame::new(start_vaddr);
217         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
218 
219         current_address_space
220             .write()
221             .mprotect(start_frame, page_count, prot_flags)
222             .map_err(|_| SystemError::EINVAL)?;
223         return Ok(0);
224     }
225 }
226