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, VmFlags,
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     /// Memory mremapping flags
69     pub struct MremapFlags: u8 {
70         const MREMAP_MAYMOVE = 1;
71         const MREMAP_FIXED = 2;
72         const MREMAP_DONTUNMAP = 4;
73     }
74 }
75 
76 impl From<MapFlags> for VmFlags {
from(map_flags: MapFlags) -> Self77     fn from(map_flags: MapFlags) -> Self {
78         let mut vm_flags = VmFlags::VM_NONE;
79 
80         if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
81             vm_flags |= VmFlags::VM_GROWSDOWN;
82         }
83 
84         if map_flags.contains(MapFlags::MAP_LOCKED) {
85             vm_flags |= VmFlags::VM_LOCKED;
86         }
87 
88         if map_flags.contains(MapFlags::MAP_SYNC) {
89             vm_flags |= VmFlags::VM_SYNC;
90         }
91 
92         vm_flags
93     }
94 }
95 
96 impl From<ProtFlags> for VmFlags {
from(prot_flags: ProtFlags) -> Self97     fn from(prot_flags: ProtFlags) -> Self {
98         let mut vm_flags = VmFlags::VM_NONE;
99 
100         if prot_flags.contains(ProtFlags::PROT_READ) {
101             vm_flags |= VmFlags::VM_READ;
102         }
103 
104         if prot_flags.contains(ProtFlags::PROT_WRITE) {
105             vm_flags |= VmFlags::VM_WRITE;
106         }
107 
108         if prot_flags.contains(ProtFlags::PROT_EXEC) {
109             vm_flags |= VmFlags::VM_EXEC;
110         }
111 
112         vm_flags
113     }
114 }
115 
116 impl Into<MapFlags> for VmFlags {
into(self) -> MapFlags117     fn into(self) -> MapFlags {
118         let mut map_flags = MapFlags::MAP_NONE;
119 
120         if self.contains(VmFlags::VM_GROWSDOWN) {
121             map_flags |= MapFlags::MAP_GROWSDOWN;
122         }
123 
124         if self.contains(VmFlags::VM_LOCKED) {
125             map_flags |= MapFlags::MAP_LOCKED;
126         }
127 
128         if self.contains(VmFlags::VM_SYNC) {
129             map_flags |= MapFlags::MAP_SYNC;
130         }
131 
132         if self.contains(VmFlags::VM_MAYSHARE) {
133             map_flags |= MapFlags::MAP_SHARED;
134         }
135 
136         map_flags
137     }
138 }
139 
140 impl Into<ProtFlags> for VmFlags {
into(self) -> ProtFlags141     fn into(self) -> ProtFlags {
142         let mut prot_flags = ProtFlags::PROT_NONE;
143 
144         if self.contains(VmFlags::VM_READ) {
145             prot_flags |= ProtFlags::PROT_READ;
146         }
147 
148         if self.contains(VmFlags::VM_WRITE) {
149             prot_flags |= ProtFlags::PROT_WRITE;
150         }
151 
152         if self.contains(VmFlags::VM_EXEC) {
153             prot_flags |= ProtFlags::PROT_EXEC;
154         }
155 
156         prot_flags
157     }
158 }
159 
160 impl Syscall {
brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError>161     pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
162         // kdebug!("brk: new_addr={:?}", new_addr);
163         let address_space = AddressSpace::current()?;
164         let mut address_space = address_space.write();
165 
166         if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
167             return Ok(address_space.brk);
168         }
169         if new_addr == address_space.brk {
170             return Ok(address_space.brk);
171         }
172 
173         unsafe {
174             address_space
175                 .set_brk(VirtAddr::new(page_align_up(new_addr.data())))
176                 .ok();
177 
178             return Ok(address_space.sbrk(0).unwrap());
179         }
180     }
181 
sbrk(incr: isize) -> Result<VirtAddr, SystemError>182     pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
183         let address_space = AddressSpace::current()?;
184         assert!(address_space.read().user_mapper.utable.is_current());
185         let mut address_space = address_space.write();
186         let r = unsafe { address_space.sbrk(incr) };
187 
188         return r;
189     }
190 
191     /// ## mmap系统调用
192     ///
193     /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
194     ///
195     /// ## 参数
196     ///
197     /// - `start_vaddr`:映射的起始地址
198     /// - `len`:映射的长度
199     /// - `prot`:保护标志
200     /// - `flags`:映射标志
201     /// - `fd`:文件描述符(暂时不支持)
202     /// - `offset`:文件偏移量 (暂时不支持)
203     ///
204     /// ## 返回值
205     ///
206     /// 成功时返回映射的起始地址,失败时返回错误码
mmap( start_vaddr: VirtAddr, len: usize, prot_flags: usize, map_flags: usize, _fd: i32, _offset: usize, ) -> Result<usize, SystemError>207     pub fn mmap(
208         start_vaddr: VirtAddr,
209         len: usize,
210         prot_flags: usize,
211         map_flags: usize,
212         _fd: i32,
213         _offset: usize,
214     ) -> Result<usize, SystemError> {
215         let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
216         let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
217 
218         if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
219             && map_flags.contains(MapFlags::MAP_FIXED)
220         {
221             kerror!(
222                 "mmap: MAP_FIXED is not supported for address below {}",
223                 DEFAULT_MMAP_MIN_ADDR
224             );
225             return Err(SystemError::EINVAL);
226         }
227         // 暂时不支持除匿名页以外的映射
228         if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
229             kerror!("mmap: not support file mapping");
230             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
231         }
232 
233         // 暂时不支持巨页映射
234         if map_flags.contains(MapFlags::MAP_HUGETLB) {
235             kerror!("mmap: not support huge page mapping");
236             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
237         }
238         let current_address_space = AddressSpace::current()?;
239         let start_page = current_address_space.write().map_anonymous(
240             start_vaddr,
241             len,
242             prot_flags,
243             map_flags,
244             true,
245         )?;
246         return Ok(start_page.virt_address().data());
247     }
248 
249     /// ## mremap系统调用
250     ///
251     ///
252     /// ## 参数
253     ///
254     /// - `old_vaddr`:原映射的起始地址
255     /// - `old_len`:原映射的长度
256     /// - `new_len`:重新映射的长度
257     /// - `mremap_flags`:重映射标志
258     /// - `new_vaddr`:重新映射的起始地址
259     ///
260     /// ## 返回值
261     ///
262     /// 成功时返回重映射的起始地址,失败时返回错误码
mremap( old_vaddr: VirtAddr, old_len: usize, new_len: usize, mremap_flags: MremapFlags, new_vaddr: VirtAddr, ) -> Result<usize, SystemError>263     pub fn mremap(
264         old_vaddr: VirtAddr,
265         old_len: usize,
266         new_len: usize,
267         mremap_flags: MremapFlags,
268         new_vaddr: VirtAddr,
269     ) -> Result<usize, SystemError> {
270         // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
271         if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
272             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
273                 || new_vaddr == VirtAddr::new(0))
274         {
275             return Err(SystemError::EINVAL);
276         }
277 
278         // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
279         if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
280             && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
281         {
282             return Err(SystemError::EINVAL);
283         }
284 
285         // 旧内存地址必须对齐
286         if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
287             return Err(SystemError::EINVAL);
288         }
289 
290         // 将old_len、new_len 对齐页面大小
291         let old_len = page_align_up(old_len);
292         let new_len = page_align_up(new_len);
293 
294         // 不允许重映射内存区域大小为0
295         if new_len == 0 {
296             return Err(SystemError::EINVAL);
297         }
298 
299         let current_address_space = AddressSpace::current()?;
300         let vma = current_address_space.read().mappings.contains(old_vaddr);
301         if vma.is_none() {
302             return Err(SystemError::EINVAL);
303         }
304         let vma = vma.unwrap();
305         let vm_flags = vma.lock().vm_flags().clone();
306 
307         // 暂时不支持巨页映射
308         if vm_flags.contains(VmFlags::VM_HUGETLB) {
309             kerror!("mmap: not support huge page mapping");
310             return Err(SystemError::ENOSYS);
311         }
312 
313         // 缩小旧内存映射区域
314         if old_len > new_len {
315             Self::munmap(old_vaddr + new_len, old_len - new_len)?;
316             return Ok(old_vaddr.data());
317         }
318 
319         // 重映射到新内存区域
320         let r = current_address_space.write().mremap(
321             old_vaddr,
322             old_len,
323             new_len,
324             mremap_flags,
325             new_vaddr,
326             vm_flags,
327         )?;
328 
329         if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
330             Self::munmap(old_vaddr, old_len)?;
331         }
332 
333         return Ok(r.data());
334     }
335 
336     /// ## munmap系统调用
337     ///
338     /// ## 参数
339     ///
340     /// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
341     /// - `len`:取消映射的字节数(已经对齐到页)
342     ///
343     /// ## 返回值
344     ///
345     /// 成功时返回0,失败时返回错误码
munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError>346     pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
347         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
348         assert!(check_aligned(len, MMArch::PAGE_SIZE));
349 
350         if unlikely(verify_area(start_vaddr, len).is_err()) {
351             return Err(SystemError::EINVAL);
352         }
353         if unlikely(len == 0) {
354             return Err(SystemError::EINVAL);
355         }
356 
357         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
358         let start_frame = VirtPageFrame::new(start_vaddr);
359         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
360 
361         current_address_space
362             .write()
363             .munmap(start_frame, page_count)
364             .map_err(|_| SystemError::EINVAL)?;
365 
366         return Ok(0);
367     }
368 
369     /// ## mprotect系统调用
370     ///
371     /// ## 参数
372     ///
373     /// - `start_vaddr`:起始地址(已经对齐到页)
374     /// - `len`:长度(已经对齐到页)
375     /// - `prot_flags`:保护标志
mprotect( start_vaddr: VirtAddr, len: usize, prot_flags: usize, ) -> Result<usize, SystemError>376     pub fn mprotect(
377         start_vaddr: VirtAddr,
378         len: usize,
379         prot_flags: usize,
380     ) -> Result<usize, SystemError> {
381         assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
382         assert!(check_aligned(len, MMArch::PAGE_SIZE));
383 
384         if unlikely(verify_area(start_vaddr, len).is_err()) {
385             return Err(SystemError::EINVAL);
386         }
387         if unlikely(len == 0) {
388             return Err(SystemError::EINVAL);
389         }
390 
391         let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
392 
393         let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
394         let start_frame = VirtPageFrame::new(start_vaddr);
395         let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
396 
397         current_address_space
398             .write()
399             .mprotect(start_frame, page_count, prot_flags)
400             .map_err(|_| SystemError::EINVAL)?;
401         return Ok(0);
402     }
403 }
404