xref: /DragonOS/kernel/src/ipc/syscall.rs (revision 2b7818e80e00fcfe4d03533f587cc125ea5e4bec)
1 use core::{
2     ffi::{c_int, c_void},
3     sync::atomic::compiler_fence,
4 };
5 
6 use log::{error, warn};
7 use system_error::SystemError;
8 
9 use crate::{
10     arch::{
11         ipc::signal::{SigCode, SigFlags, SigSet, Signal},
12         MMArch,
13     },
14     filesystem::vfs::{
15         file::{File, FileMode},
16         FilePrivateData,
17     },
18     ipc::shm::{shm_manager_lock, IPC_PRIVATE},
19     libs::align::page_align_up,
20     libs::spinlock::SpinLock,
21     mm::{
22         allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame},
23         page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll},
24         syscall::ProtFlags,
25         ucontext::{AddressSpace, VMA},
26         VirtAddr, VmFlags,
27     },
28     process::{Pid, ProcessManager},
29     syscall::{
30         user_access::{UserBufferReader, UserBufferWriter},
31         Syscall,
32     },
33 };
34 
35 use super::{
36     pipe::{LockedPipeInode, PipeFsPrivateData},
37     shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
38     signal_types::{
39         SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL,
40         USER_SIG_ERR, USER_SIG_IGN,
41     },
42 };
43 
44 impl Syscall {
45     /// # 创建带参数的匿名管道
46     ///
47     /// ## 参数
48     ///
49     /// - `fd`: 用于返回文件描述符的数组
50     /// - `flags`:设置管道的参数
51     pub fn pipe2(fd: *mut i32, flags: FileMode) -> Result<usize, SystemError> {
52         if !flags
53             .difference(FileMode::O_CLOEXEC | FileMode::O_NONBLOCK | FileMode::O_DIRECT)
54             .is_empty()
55         {
56             return Err(SystemError::EINVAL);
57         }
58 
59         let mut user_buffer = UserBufferWriter::new(fd, core::mem::size_of::<[c_int; 2]>(), true)?;
60         let fd = user_buffer.buffer::<i32>(0)?;
61         let pipe_ptr = LockedPipeInode::new();
62 
63         let mut read_file = File::new(
64             pipe_ptr.clone(),
65             FileMode::O_RDONLY | (flags & FileMode::O_NONBLOCK),
66         )?;
67         read_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new(
68             FileMode::O_RDONLY,
69         )));
70 
71         let mut write_file = File::new(
72             pipe_ptr.clone(),
73             FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)),
74         )?;
75         write_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new(
76             FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)),
77         )));
78 
79         if flags.contains(FileMode::O_CLOEXEC) {
80             read_file.set_close_on_exec(true);
81             write_file.set_close_on_exec(true);
82         }
83         let fd_table_ptr = ProcessManager::current_pcb().fd_table();
84         let mut fd_table_guard = fd_table_ptr.write();
85         let read_fd = fd_table_guard.alloc_fd(read_file, None)?;
86         let write_fd = fd_table_guard.alloc_fd(write_file, None)?;
87 
88         drop(fd_table_guard);
89 
90         fd[0] = read_fd;
91         fd[1] = write_fd;
92         Ok(0)
93     }
94 
95     pub fn kill(pid: Pid, sig: c_int) -> Result<usize, SystemError> {
96         let sig = Signal::from(sig);
97         if sig == Signal::INVALID {
98             // 传入的signal数值不合法
99             warn!("Not a valid signal number");
100             return Err(SystemError::EINVAL);
101         }
102 
103         // 初始化signal info
104         let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
105 
106         compiler_fence(core::sync::atomic::Ordering::SeqCst);
107 
108         let retval = sig
109             .send_signal_info(Some(&mut info), pid)
110             .map(|x| x as usize);
111 
112         compiler_fence(core::sync::atomic::Ordering::SeqCst);
113 
114         return retval;
115     }
116 
117     /// 通用信号注册函数
118     ///
119     /// ## 参数
120     ///
121     /// - `sig` 信号的值
122     /// - `act` 用户空间传入的 Sigaction 指针
123     /// - `old_act` 用户空间传入的用来保存旧 Sigaction 的指针
124     /// - `from_user` 用来标识这个函数调用是否来自用户空间
125     ///
126     /// @return int 错误码
127     #[no_mangle]
128     pub fn sigaction(
129         sig: c_int,
130         new_act: usize,
131         old_act: usize,
132         from_user: bool,
133     ) -> Result<usize, SystemError> {
134         // 请注意:用户态传进来的user_sigaction结构体类型,请注意,这个结构体与内核实际的不一样
135         let act: *mut UserSigaction = new_act as *mut UserSigaction;
136         let old_act = old_act as *mut UserSigaction;
137         let mut new_ka: Sigaction = Default::default();
138         let mut old_sigaction: Sigaction = Default::default();
139         // 如果传入的,新的sigaction不为空
140         if !act.is_null() {
141             // 如果参数的范围不在用户空间,则返回错误
142             let r = UserBufferWriter::new(act, core::mem::size_of::<Sigaction>(), from_user);
143             if r.is_err() {
144                 return Err(SystemError::EFAULT);
145             }
146             let mask: SigSet = unsafe { (*act).mask };
147             let input_sighandler = unsafe { (*act).handler as u64 };
148             match input_sighandler {
149                 USER_SIG_DFL => {
150                     new_ka = Sigaction::DEFAULT_SIGACTION;
151                     *new_ka.flags_mut() = unsafe { (*act).flags };
152                     new_ka.set_restorer(None);
153                 }
154 
155                 USER_SIG_IGN => {
156                     new_ka = Sigaction::DEFAULT_SIGACTION_IGNORE;
157                     *new_ka.flags_mut() = unsafe { (*act).flags };
158 
159                     new_ka.set_restorer(None);
160                 }
161                 _ => {
162                     // 从用户空间获得sigaction结构体
163                     // TODO mask是default还是用户空间传入
164                     new_ka = Sigaction::new(
165                         SigactionType::SaHandler(SaHandlerType::Customized(unsafe {
166                             VirtAddr::new((*act).handler as usize)
167                         })),
168                         unsafe { (*act).flags },
169                         SigSet::default(),
170                         unsafe { Some(VirtAddr::new((*act).restorer as usize)) },
171                     );
172                 }
173             }
174 
175             // TODO 如果为空,赋默认值?
176             // debug!("new_ka={:?}", new_ka);
177             // 如果用户手动给了sa_restorer,那么就置位SA_FLAG_RESTORER,否则报错。(用户必须手动指定restorer)
178             if new_ka.restorer().is_some() {
179                 new_ka.flags_mut().insert(SigFlags::SA_RESTORER);
180             } else if new_ka.action().is_customized() {
181                 error!(
182                 "pid:{:?}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.",
183                 ProcessManager::current_pcb().pid(),
184                 sig
185             );
186                 return Err(SystemError::EINVAL);
187             }
188             *new_ka.mask_mut() = mask;
189         }
190 
191         let sig = Signal::from(sig);
192         // 如果给出的信号值不合法
193         if sig == Signal::INVALID {
194             return Err(SystemError::EINVAL);
195         }
196 
197         let retval = super::signal::do_sigaction(
198             sig,
199             if act.is_null() {
200                 None
201             } else {
202                 Some(&mut new_ka)
203             },
204             if old_act.is_null() {
205                 None
206             } else {
207                 Some(&mut old_sigaction)
208             },
209         );
210 
211         //
212         if (retval == Ok(())) && (!old_act.is_null()) {
213             let r =
214                 UserBufferWriter::new(old_act, core::mem::size_of::<UserSigaction>(), from_user);
215             if r.is_err() {
216                 return Err(SystemError::EFAULT);
217             }
218 
219             let sigaction_handler = match old_sigaction.action() {
220                 SigactionType::SaHandler(handler) => {
221                     if let SaHandlerType::Customized(hand) = handler {
222                         hand
223                     } else if handler.is_sig_ignore() {
224                         VirtAddr::new(USER_SIG_IGN as usize)
225                     } else if handler.is_sig_error() {
226                         VirtAddr::new(USER_SIG_ERR as usize)
227                     } else {
228                         VirtAddr::new(USER_SIG_DFL as usize)
229                     }
230                 }
231                 SigactionType::SaSigaction(_) => {
232                     error!("unsupported type: SaSigaction");
233                     VirtAddr::new(USER_SIG_DFL as usize)
234                 }
235             };
236 
237             unsafe {
238                 (*old_act).handler = sigaction_handler.data() as *mut c_void;
239                 (*old_act).flags = old_sigaction.flags();
240                 (*old_act).mask = old_sigaction.mask();
241                 if old_sigaction.restorer().is_some() {
242                     (*old_act).restorer = old_sigaction.restorer().unwrap().data() as *mut c_void;
243                 }
244             }
245         }
246         return retval.map(|_| 0);
247     }
248 
249     /// # SYS_SHMGET系统调用函数,用于获取共享内存
250     ///
251     /// ## 参数
252     ///
253     /// - `key`: 共享内存键值
254     /// - `size`: 共享内存大小(bytes)
255     /// - `shmflg`: 共享内存标志
256     ///
257     /// ## 返回值
258     ///
259     /// 成功:共享内存id
260     /// 失败:错误码
261     pub fn shmget(key: ShmKey, size: usize, shmflg: ShmFlags) -> Result<usize, SystemError> {
262         // 暂不支持巨页
263         if shmflg.contains(ShmFlags::SHM_HUGETLB) {
264             error!("shmget: not support huge page");
265             return Err(SystemError::ENOSYS);
266         }
267 
268         let mut shm_manager_guard = shm_manager_lock();
269         match key {
270             // 创建共享内存段
271             IPC_PRIVATE => shm_manager_guard.add(key, size, shmflg),
272             _ => {
273                 // 查找key对应的共享内存段是否存在
274                 let id = shm_manager_guard.contains_key(&key);
275                 if let Some(id) = id {
276                     // 不能重复创建
277                     if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) {
278                         return Err(SystemError::EEXIST);
279                     }
280 
281                     // key值存在,说明有对应共享内存,返回该共享内存id
282                     return Ok(id.data());
283                 } else {
284                     // key不存在且shm_flags不包含IPC_CREAT创建IPC对象标志,则返回错误码
285                     if !shmflg.contains(ShmFlags::IPC_CREAT) {
286                         return Err(SystemError::ENOENT);
287                     }
288 
289                     // 存在创建IPC对象标志
290                     return shm_manager_guard.add(key, size, shmflg);
291                 }
292             }
293         }
294     }
295 
296     /// # SYS_SHMAT系统调用函数,用于连接共享内存段
297     ///
298     /// ## 参数
299     ///
300     /// - `id`: 共享内存id
301     /// - `vaddr`: 连接共享内存的进程虚拟内存区域起始地址
302     /// - `shmflg`: 共享内存标志
303     ///
304     /// ## 返回值
305     ///
306     /// 成功:映射到共享内存的虚拟内存区域起始地址
307     /// 失败:错误码
308     pub fn shmat(id: ShmId, vaddr: VirtAddr, shmflg: ShmFlags) -> Result<usize, SystemError> {
309         let mut shm_manager_guard = shm_manager_lock();
310         let current_address_space = AddressSpace::current()?;
311         let mut address_write_guard = current_address_space.write();
312 
313         let kernel_shm = shm_manager_guard.get_mut(&id).ok_or(SystemError::EINVAL)?;
314         let size = page_align_up(kernel_shm.size());
315         let mut phys = PhysPageFrame::new(kernel_shm.start_paddr());
316         let count = PageFrameCount::from_bytes(size).unwrap();
317         let r = match vaddr.data() {
318             // 找到空闲区域并映射到共享内存
319             0 => {
320                 // 找到空闲区域
321                 let region = address_write_guard
322                     .mappings
323                     .find_free(vaddr, size)
324                     .ok_or(SystemError::EINVAL)?;
325                 let vm_flags = VmFlags::from(shmflg);
326                 let destination = VirtPageFrame::new(region.start());
327                 let page_flags: EntryFlags<MMArch> =
328                     EntryFlags::from_prot_flags(ProtFlags::from(vm_flags), true);
329                 let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
330 
331                 // 将共享内存映射到对应虚拟区域
332                 let vma = VMA::physmap(
333                     phys,
334                     destination,
335                     count,
336                     vm_flags,
337                     page_flags,
338                     &mut address_write_guard.user_mapper.utable,
339                     flusher,
340                 )?;
341 
342                 // 将VMA加入到当前进程的VMA列表中
343                 address_write_guard.mappings.insert_vma(vma);
344 
345                 region.start().data()
346             }
347             // 指定虚拟地址
348             _ => {
349                 // 获取对应vma
350                 let vma = address_write_guard
351                     .mappings
352                     .contains(vaddr)
353                     .ok_or(SystemError::EINVAL)?;
354                 if vma.lock_irqsave().region().start() != vaddr {
355                     return Err(SystemError::EINVAL);
356                 }
357 
358                 // 验证用户虚拟内存区域是否有效
359                 let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?;
360 
361                 // 必须在取消映射前获取到EntryFlags
362                 let page_flags = address_write_guard
363                     .user_mapper
364                     .utable
365                     .translate(vaddr)
366                     .ok_or(SystemError::EINVAL)?
367                     .1;
368 
369                 // 取消原映射
370                 let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
371                 vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
372 
373                 // 将该虚拟内存区域映射到共享内存区域
374                 let mut page_manager_guard = page_manager_lock_irqsave();
375                 let mut virt = VirtPageFrame::new(vaddr);
376                 for _ in 0..count.data() {
377                     let r = unsafe {
378                         address_write_guard.user_mapper.utable.map_phys(
379                             virt.virt_address(),
380                             phys.phys_address(),
381                             page_flags,
382                         )
383                     }
384                     .expect("Failed to map zero, may be OOM error");
385                     r.flush();
386 
387                     // 将vma加入到对应Page的anon_vma
388                     page_manager_guard
389                         .get_unwrap(&phys.phys_address())
390                         .write_irqsave()
391                         .insert_vma(vma.clone());
392 
393                     phys = phys.next();
394                     virt = virt.next();
395                 }
396 
397                 // 更新vma的映射状态
398                 vma.lock_irqsave().set_mapped(true);
399 
400                 vaddr.data()
401             }
402         };
403 
404         // 更新最后一次连接时间
405         kernel_shm.update_atim();
406 
407         Ok(r)
408     }
409 
410     /// # SYS_SHMDT系统调用函数,用于取消对共享内存的连接
411     ///
412     /// ## 参数
413     ///
414     /// - `vaddr`:  需要取消映射的虚拟内存区域起始地址
415     ///
416     /// ## 返回值
417     ///
418     /// 成功:0
419     /// 失败:错误码
420     pub fn shmdt(vaddr: VirtAddr) -> Result<usize, SystemError> {
421         let current_address_space = AddressSpace::current()?;
422         let mut address_write_guard = current_address_space.write();
423 
424         // 获取vma
425         let vma = address_write_guard
426             .mappings
427             .contains(vaddr)
428             .ok_or(SystemError::EINVAL)?;
429 
430         // 判断vaddr是否为起始地址
431         if vma.lock_irqsave().region().start() != vaddr {
432             return Err(SystemError::EINVAL);
433         }
434 
435         // 获取映射的物理地址
436         let paddr = address_write_guard
437             .user_mapper
438             .utable
439             .translate(vaddr)
440             .ok_or(SystemError::EINVAL)?
441             .0;
442 
443         // 如果物理页的shm_id为None,代表不是共享页
444         let mut page_manager_guard = page_manager_lock_irqsave();
445         let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?;
446         let shm_id = page.read_irqsave().shm_id().ok_or(SystemError::EINVAL)?;
447         drop(page_manager_guard);
448 
449         // 获取对应共享页管理信息
450         let mut shm_manager_guard = shm_manager_lock();
451         let kernel_shm = shm_manager_guard
452             .get_mut(&shm_id)
453             .ok_or(SystemError::EINVAL)?;
454         // 更新最后一次断开连接时间
455         kernel_shm.update_dtim();
456         drop(shm_manager_guard);
457 
458         // 取消映射
459         let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
460         vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
461 
462         return Ok(0);
463     }
464 
465     /// # SYS_SHMCTL系统调用函数,用于管理共享内存段
466     ///
467     /// ## 参数
468     ///
469     /// - `id`: 共享内存id
470     /// - `cmd`: 操作码
471     /// - `user_buf`: 用户缓冲区
472     /// - `from_user`: buf_vaddr是否来自用户地址空间
473     ///
474     /// ## 返回值
475     ///
476     /// 成功:0
477     /// 失败:错误码
478     pub fn shmctl(
479         id: ShmId,
480         cmd: ShmCtlCmd,
481         user_buf: *const u8,
482         from_user: bool,
483     ) -> Result<usize, SystemError> {
484         let mut shm_manager_guard = shm_manager_lock();
485 
486         match cmd {
487             // 查看共享内存元信息
488             ShmCtlCmd::IpcInfo => shm_manager_guard.ipc_info(user_buf, from_user),
489             // 查看共享内存使用信息
490             ShmCtlCmd::ShmInfo => shm_manager_guard.shm_info(user_buf, from_user),
491             // 查看id对应的共享内存信息
492             ShmCtlCmd::ShmStat | ShmCtlCmd::ShmtStatAny | ShmCtlCmd::IpcStat => {
493                 shm_manager_guard.shm_stat(id, cmd, user_buf, from_user)
494             }
495             // 设置KernIpcPerm
496             ShmCtlCmd::IpcSet => shm_manager_guard.ipc_set(id, user_buf, from_user),
497             // 将共享内存段设置为可回收状态
498             ShmCtlCmd::IpcRmid => shm_manager_guard.ipc_rmid(id),
499             // 锁住共享内存段,不允许内存置换
500             ShmCtlCmd::ShmLock => shm_manager_guard.shm_lock(id),
501             // 解锁共享内存段,允许内存置换
502             ShmCtlCmd::ShmUnlock => shm_manager_guard.shm_unlock(id),
503             // 无效操作码
504             ShmCtlCmd::Default => Err(SystemError::EINVAL),
505         }
506     }
507 }
508