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