strat9_kernel/syscall/
process.rs1use super::{error::SyscallError, SyscallFrame};
10use crate::process::{
11 create_session, current_pgid, current_task_clone, current_task_id, current_tid, get_parent_pid,
12 get_pgid_by_pid, get_sid_by_pid, get_task_ids_in_tgid, kill_task, set_process_group,
13 thread_ops,
14};
15use core::sync::atomic::Ordering;
16
17pub fn sys_getpid() -> Result<u64, SyscallError> {
21 current_task_clone()
22 .map(|task| task.tgid as u64)
23 .ok_or(SyscallError::Fault)
24}
25
26pub fn sys_gettid() -> Result<u64, SyscallError> {
30 current_tid()
31 .map(|tid| tid as u64)
32 .ok_or(SyscallError::Fault)
33}
34
35pub fn sys_thread_create(
37 frame: &SyscallFrame,
38 entry: u64,
39 stack_top: u64,
40 arg0: u64,
41 flags: u64,
42 tls_base: u64,
43) -> Result<u64, SyscallError> {
44 let child = thread_ops::create_user_thread(
45 thread_ops::UserEntryContext::from_frame(frame),
46 entry,
47 stack_top,
48 arg0,
49 flags,
50 tls_base,
51 )?;
52 Ok(child.tid as u64)
53}
54
55pub fn sys_thread_join(tid: u64, status_ptr: u64, flags: u64) -> Result<u64, SyscallError> {
57 if flags != 0 {
58 return Err(SyscallError::InvalidArgument);
59 }
60
61 let wait_tid = u32::try_from(tid).map_err(|_| SyscallError::InvalidArgument)?;
62 let (joined_tid, status) = thread_ops::join_task(wait_tid)?;
63 if status_ptr != 0 {
64 let out =
65 crate::memory::UserSliceWrite::new(status_ptr, 4).map_err(|_| SyscallError::Fault)?;
66 out.copy_from(&(status as i32).to_ne_bytes());
67 }
68 Ok(joined_tid as u64)
69}
70
71pub fn sys_thread_exit(exit_code: u64) -> Result<u64, SyscallError> {
73 let code = i32::try_from(exit_code).map_err(|_| SyscallError::InvalidArgument)?;
74 thread_ops::exit_current_thread(code)
75}
76
77pub fn sys_getppid() -> Result<u64, SyscallError> {
79 let child = current_task_id().ok_or(SyscallError::Fault)?;
80 Ok(get_parent_pid(child).map(|p| p as u64).unwrap_or(0))
81}
82
83pub fn sys_getpgid(pid: i64) -> Result<u64, SyscallError> {
85 if pid < 0 {
86 return Err(SyscallError::InvalidArgument);
87 }
88 if pid == 0 {
89 return current_pgid()
90 .map(|pgid| pgid as u64)
91 .ok_or(SyscallError::Fault);
92 }
93 get_pgid_by_pid(pid as u32)
94 .map(|pgid| pgid as u64)
95 .ok_or(SyscallError::NotFound)
96}
97
98pub fn sys_getpgrp() -> Result<u64, SyscallError> {
100 current_pgid()
101 .map(|pgid| pgid as u64)
102 .ok_or(SyscallError::Fault)
103}
104
105pub fn sys_getsid(pid: i64) -> Result<u64, SyscallError> {
107 if pid < 0 {
108 return Err(SyscallError::InvalidArgument);
109 }
110 if pid == 0 {
111 return crate::process::current_sid()
112 .map(|sid| sid as u64)
113 .ok_or(SyscallError::Fault);
114 }
115 get_sid_by_pid(pid as u32)
116 .map(|sid| sid as u64)
117 .ok_or(SyscallError::NotFound)
118}
119
120pub fn sys_setpgid(pid: i64, pgid: i64) -> Result<u64, SyscallError> {
122 if pid < 0 || pgid < 0 {
123 return Err(SyscallError::InvalidArgument);
124 }
125 let caller = current_task_id().ok_or(SyscallError::Fault)?;
126 let target_pid = if pid == 0 { None } else { Some(pid as u32) };
127 let new_pgid = if pgid == 0 { None } else { Some(pgid as u32) };
128 let final_pgid = set_process_group(caller, target_pid, new_pgid)?;
129 Ok(final_pgid as u64)
130}
131
132pub fn sys_setsid() -> Result<u64, SyscallError> {
134 let caller = current_task_id().ok_or(SyscallError::Fault)?;
135 create_session(caller).map(|sid| sid as u64)
136}
137
138pub fn sys_getuid() -> Result<u64, SyscallError> {
142 let task = current_task_clone().ok_or(SyscallError::Fault)?;
143 Ok(task.uid.load(Ordering::Relaxed) as u64)
144}
145
146pub fn sys_geteuid() -> Result<u64, SyscallError> {
148 let task = current_task_clone().ok_or(SyscallError::Fault)?;
149 Ok(task.euid.load(Ordering::Relaxed) as u64)
150}
151
152pub fn sys_getgid() -> Result<u64, SyscallError> {
154 let task = current_task_clone().ok_or(SyscallError::Fault)?;
155 Ok(task.gid.load(Ordering::Relaxed) as u64)
156}
157
158pub fn sys_getegid() -> Result<u64, SyscallError> {
160 let task = current_task_clone().ok_or(SyscallError::Fault)?;
161 Ok(task.egid.load(Ordering::Relaxed) as u64)
162}
163
164pub fn sys_setuid(uid: u64) -> Result<u64, SyscallError> {
166 if uid > u32::MAX as u64 {
167 return Err(SyscallError::InvalidArgument);
168 }
169 let task = current_task_clone().ok_or(SyscallError::Fault)?;
170 let euid = task.euid.load(Ordering::Relaxed);
172 let cur_uid = task.uid.load(Ordering::Relaxed);
173 if euid != 0 && uid as u32 != cur_uid && uid as u32 != euid {
174 return Err(SyscallError::PermissionDenied);
175 }
176 task.uid.store(uid as u32, Ordering::Relaxed);
177 task.euid.store(uid as u32, Ordering::Relaxed);
178 Ok(0)
179}
180
181pub fn sys_setgid(gid: u64) -> Result<u64, SyscallError> {
183 if gid > u32::MAX as u64 {
184 return Err(SyscallError::InvalidArgument);
185 }
186 let task = current_task_clone().ok_or(SyscallError::Fault)?;
187 let euid = task.euid.load(Ordering::Relaxed);
188 let cur_gid = task.gid.load(Ordering::Relaxed);
189 let egid = task.egid.load(Ordering::Relaxed);
190 if euid != 0 && gid as u32 != cur_gid && gid as u32 != egid {
191 return Err(SyscallError::PermissionDenied);
192 }
193 task.gid.store(gid as u32, Ordering::Relaxed);
194 task.egid.store(gid as u32, Ordering::Relaxed);
195 Ok(0)
196}
197
198pub fn sys_set_tid_address(tidptr: u64) -> Result<u64, SyscallError> {
205 let task = current_task_clone().ok_or(SyscallError::Fault)?;
206 task.clear_child_tid.store(tidptr, Ordering::Relaxed);
207 Ok(task.tid as u64)
208}
209
210pub fn sys_exit_group(exit_code: u64) -> Result<u64, SyscallError> {
212 let current = current_task_clone().ok_or(SyscallError::Fault)?;
213 for sibling_id in get_task_ids_in_tgid(current.tgid) {
214 if sibling_id != current.id {
215 let _ = kill_task(sibling_id);
216 }
217 }
218
219 crate::process::scheduler::exit_current_task(exit_code as i32)
221}
222
223const ARCH_SET_GS: u64 = 0x1001;
227const ARCH_SET_FS: u64 = 0x1002;
228const ARCH_GET_FS: u64 = 0x1003;
229const ARCH_GET_GS: u64 = 0x1004;
230
231const MSR_FS_BASE: u32 = 0xC000_0100;
233const MSR_GS_BASE: u32 = 0xC000_0101;
234
235pub fn sys_arch_prctl(code: u64, addr: u64) -> Result<u64, SyscallError> {
241 let task = current_task_clone().ok_or(SyscallError::Fault)?;
242 match code {
243 ARCH_SET_FS => {
244 task.user_fs_base.store(addr, Ordering::Relaxed);
246 unsafe { wrmsr(MSR_FS_BASE, addr) };
248 Ok(0)
249 }
250 ARCH_GET_FS => {
251 let base = task.user_fs_base.load(Ordering::Relaxed);
252 use crate::memory::UserSliceWrite;
254 let out = UserSliceWrite::new(addr, 8).map_err(|_| SyscallError::Fault)?;
255 out.copy_from(&base.to_ne_bytes());
256 Ok(0)
257 }
258 ARCH_SET_GS => {
259 unsafe { wrmsr(MSR_GS_BASE, addr) };
261 Ok(0)
262 }
263 ARCH_GET_GS => {
264 let base = unsafe { rdmsr(MSR_GS_BASE) };
265 use crate::memory::UserSliceWrite;
266 let out = UserSliceWrite::new(addr, 8).map_err(|_| SyscallError::Fault)?;
267 out.copy_from(&base.to_ne_bytes());
268 Ok(0)
269 }
270 _ => Err(SyscallError::InvalidArgument),
271 }
272}
273
274#[inline]
279unsafe fn wrmsr(msr: u32, value: u64) {
280 let lo = value as u32;
281 let hi = (value >> 32) as u32;
282 unsafe {
283 core::arch::asm!(
284 "wrmsr",
285 in("ecx") msr,
286 in("eax") lo,
287 in("edx") hi,
288 options(nostack, preserves_flags),
289 );
290 }
291}
292
293#[inline]
298unsafe fn rdmsr(msr: u32) -> u64 {
299 let lo: u32;
300 let hi: u32;
301 unsafe {
302 core::arch::asm!(
303 "rdmsr",
304 in("ecx") msr,
305 out("eax") lo,
306 out("edx") hi,
307 options(nostack, preserves_flags),
308 );
309 }
310 lo as u64 | ((hi as u64) << 32)
311}
312
313pub fn sys_tgkill(tgid: u64, tid: u64, signum: u64) -> Result<u64, SyscallError> {
320 use crate::process::{get_task_by_pid, send_signal, Signal};
321
322 if signum as u32 >= 64 {
324 return Err(SyscallError::InvalidArgument);
325 }
326
327 let task = get_task_by_pid(tgid as u32).ok_or(SyscallError::NotFound)?;
329
330 if task.tid as u64 != tid && task.pid as u64 != tid {
332 return Err(SyscallError::NotFound);
333 }
334
335 if signum == 0 {
336 return Ok(0); }
338
339 let sig = Signal::from_u32(signum as u32).ok_or(SyscallError::InvalidArgument)?;
340 send_signal(task.id, sig)?;
341 Ok(0)
342}