1use super::{error::SyscallError, SyscallFrame};
6use crate::process::{
7 block_current_task, create_session, current_pgid, current_task_clone, current_task_id,
8 current_tid, get_child_task_id_by_tid, get_parent_pid, get_pgid_by_pid, get_sid_by_pid,
9 get_task_ids_in_tgid, kill_task,
10 scheduler::add_task_with_parent,
11 set_process_group,
12 task::{CpuContext, ExtendedState, KernelStack, SyncUnsafeCell, Task},
13 WaitChildResult,
14};
15use alloc::{boxed::Box, sync::Arc};
16use core::{mem::offset_of, sync::atomic::Ordering};
17
18#[repr(C)]
19#[derive(Clone, Copy)]
20struct ThreadUserContext {
21 entry: u64,
22 stack_top: u64,
23 arg0: u64,
24 user_cs: u64,
25 user_rflags: u64,
26 user_ss: u64,
27}
28
29const THREAD_OFF_ENTRY: usize = offset_of!(ThreadUserContext, entry);
30const THREAD_OFF_STACK_TOP: usize = offset_of!(ThreadUserContext, stack_top);
31const THREAD_OFF_ARG0: usize = offset_of!(ThreadUserContext, arg0);
32const THREAD_OFF_USER_CS: usize = offset_of!(ThreadUserContext, user_cs);
33const THREAD_OFF_USER_RFLAGS: usize = offset_of!(ThreadUserContext, user_rflags);
34const THREAD_OFF_USER_SS: usize = offset_of!(ThreadUserContext, user_ss);
35
36extern "C" fn thread_child_start(ctx_ptr: u64) -> ! {
38 let boxed = unsafe { Box::from_raw(ctx_ptr as *mut ThreadUserContext) };
41 let ctx = *boxed;
42 unsafe { thread_iret_from_ctx(&ctx as *const ThreadUserContext) }
44}
45
46#[unsafe(naked)]
48unsafe extern "C" fn thread_iret_from_ctx(_ctx: *const ThreadUserContext) -> ! {
49 core::arch::naked_asm!(
50 "cli",
52 "mov rsi, rdi",
53 "mov r8, [rsi + {off_user_ss}]",
55 "push r8",
56 "mov r8, [rsi + {off_stack_top}]",
57 "push r8",
58 "mov r8, [rsi + {off_user_rflags}]",
59 "push r8",
60 "mov r8, [rsi + {off_user_cs}]",
61 "push r8",
62 "mov r8, [rsi + {off_entry}]",
63 "push r8",
64 "mov rdi, [rsi + {off_arg0}]",
66 "xor rax, rax",
68 "swapgs",
69 "iretq",
70 off_entry = const THREAD_OFF_ENTRY,
71 off_stack_top = const THREAD_OFF_STACK_TOP,
72 off_arg0 = const THREAD_OFF_ARG0,
73 off_user_cs = const THREAD_OFF_USER_CS,
74 off_user_rflags = const THREAD_OFF_USER_RFLAGS,
75 off_user_ss = const THREAD_OFF_USER_SS,
76 );
77}
78
79fn build_user_thread_task(
81 parent: &Arc<Task>,
82 bootstrap_ctx: Box<ThreadUserContext>,
83 tls_base: u64,
84) -> Result<Arc<Task>, SyscallError> {
85 let kernel_stack =
86 KernelStack::allocate(Task::DEFAULT_STACK_SIZE).map_err(|_| SyscallError::OutOfMemory)?;
87 let context = CpuContext::new(thread_child_start as *const () as u64, &kernel_stack);
88 let (pid, tid, _) = Task::allocate_process_ids();
89
90 let parent_fpu = unsafe { &*parent.fpu_state.get() };
91 let mut child_fpu = ExtendedState::new();
92 child_fpu.copy_from(parent_fpu);
93 let interrupt_frame = crate::syscall::SyscallFrame {
94 r15: 0,
95 r14: 0,
96 r13: 0,
97 r12: 0,
98 rbp: 0,
99 rbx: 0,
100 r11: bootstrap_ctx.user_rflags,
101 r10: 0,
102 r9: 0,
103 r8: 0,
104 rsi: 0,
105 rdi: bootstrap_ctx.arg0,
106 rdx: 0,
107 rcx: bootstrap_ctx.entry,
108 rax: 0,
109 iret_rip: bootstrap_ctx.entry,
110 iret_cs: bootstrap_ctx.user_cs,
111 iret_rflags: bootstrap_ctx.user_rflags,
112 iret_rsp: bootstrap_ctx.stack_top,
113 iret_ss: bootstrap_ctx.user_ss,
114 };
115
116 let task = Arc::new(Task {
117 id: crate::process::TaskId::new(),
118 pid,
119 tid,
120 tgid: parent.tgid,
121 pgid: core::sync::atomic::AtomicU32::new(parent.pgid.load(Ordering::Relaxed)),
122 sid: core::sync::atomic::AtomicU32::new(parent.sid.load(Ordering::Relaxed)),
123 uid: core::sync::atomic::AtomicU32::new(parent.uid.load(Ordering::Relaxed)),
124 euid: core::sync::atomic::AtomicU32::new(parent.euid.load(Ordering::Relaxed)),
125 gid: core::sync::atomic::AtomicU32::new(parent.gid.load(Ordering::Relaxed)),
126 egid: core::sync::atomic::AtomicU32::new(parent.egid.load(Ordering::Relaxed)),
127 state: core::sync::atomic::AtomicU8::new(crate::process::TaskState::Ready as u8),
128 priority: parent.priority,
129 context: SyncUnsafeCell::new(context),
130 resume_kind: SyncUnsafeCell::new(crate::process::task::ResumeKind::RetFrame),
131 interrupt_rsp: core::sync::atomic::AtomicU64::new(0),
132 kernel_stack,
133 user_stack: None,
134 name: "user-thread",
135 process: parent.process.clone(),
136 pending_signals: crate::process::signal::SignalSet::new(),
137 blocked_signals: parent.blocked_signals.clone(),
138 irq_signal_delivery_blocked: core::sync::atomic::AtomicBool::new(false),
139 signal_stack: SyncUnsafeCell::new(None),
140 itimers: crate::process::timer::ITimers::new(),
141 wake_pending: core::sync::atomic::AtomicBool::new(false),
142 wake_deadline_ns: core::sync::atomic::AtomicU64::new(0),
143 trampoline_entry: core::sync::atomic::AtomicU64::new(0),
144 trampoline_stack_top: core::sync::atomic::AtomicU64::new(0),
145 trampoline_arg0: core::sync::atomic::AtomicU64::new(0),
146 ticks: core::sync::atomic::AtomicU64::new(0),
147 sched_policy: SyncUnsafeCell::new(parent.sched_policy()),
148 home_cpu: core::sync::atomic::AtomicUsize::new(usize::MAX),
149 vruntime: core::sync::atomic::AtomicU64::new(parent.vruntime()),
150 fair_rq_generation: core::sync::atomic::AtomicU64::new(0),
151 fair_on_rq: core::sync::atomic::AtomicBool::new(false),
152 clear_child_tid: core::sync::atomic::AtomicU64::new(0),
153 robust_list_head: core::sync::atomic::AtomicU64::new(0),
154 robust_list_len: core::sync::atomic::AtomicUsize::new(0),
155 user_fs_base: core::sync::atomic::AtomicU64::new(tls_base),
156 fpu_state: SyncUnsafeCell::new(child_fpu),
157 xcr0_mask: core::sync::atomic::AtomicU64::new(parent.xcr0_mask.load(Ordering::Relaxed)),
158 rt_link: intrusive_collections::LinkedListLink::new(),
159 });
160
161 unsafe {
164 let ctx = &mut *task.context.get();
165 let frame = ctx.saved_rsp as *mut u64;
166 *frame.add(2) = Box::into_raw(bootstrap_ctx) as u64;
167 }
168
169 task.seed_interrupt_frame(interrupt_frame);
170
171 Ok(task)
172}
173
174pub fn sys_getpid() -> Result<u64, SyscallError> {
178 current_task_clone()
179 .map(|task| task.tgid as u64)
180 .ok_or(SyscallError::Fault)
181}
182
183pub fn sys_gettid() -> Result<u64, SyscallError> {
187 current_tid()
188 .map(|tid| tid as u64)
189 .ok_or(SyscallError::Fault)
190}
191
192pub fn sys_thread_create(
194 frame: &SyscallFrame,
195 entry: u64,
196 stack_top: u64,
197 arg0: u64,
198 flags: u64,
199 tls_base: u64,
200) -> Result<u64, SyscallError> {
201 const USER_TOP_EXCLUSIVE: u64 = 0x0000_8000_0000_0000;
202
203 if flags != 0 {
204 return Err(SyscallError::InvalidArgument);
205 }
206
207 if entry == 0
208 || stack_top == 0
209 || entry >= USER_TOP_EXCLUSIVE
210 || stack_top >= USER_TOP_EXCLUSIVE
211 || (stack_top & 0x7) != 0
212 {
214 return Err(SyscallError::InvalidArgument);
215 }
216
217 let parent = current_task_clone().ok_or(SyscallError::Fault)?;
218 if parent.is_kernel() {
219 return Err(SyscallError::PermissionDenied);
220 }
221
222 let user_ctx = Box::new(ThreadUserContext {
223 entry,
224 stack_top,
225 arg0,
226 user_cs: frame.iret_cs,
227 user_rflags: frame.iret_rflags | (1 << 9),
228 user_ss: frame.iret_ss,
229 });
230
231 let child = build_user_thread_task(&parent, user_ctx, tls_base)?;
232 let tid = child.tid as u64;
233 add_task_with_parent(child, parent.id);
234 Ok(tid)
235}
236
237pub fn sys_thread_join(tid: u64, status_ptr: u64, flags: u64) -> Result<u64, SyscallError> {
239 if flags != 0 {
240 return Err(SyscallError::InvalidArgument);
241 }
242
243 let wait_tid = u32::try_from(tid).map_err(|_| SyscallError::InvalidArgument)?;
244 let current = current_task_clone().ok_or(SyscallError::Fault)?;
245 if wait_tid == current.tid {
246 return Err(SyscallError::InvalidArgument);
247 }
248
249 let parent_id = current_task_id().ok_or(SyscallError::Fault)?;
250 let child_id = get_child_task_id_by_tid(parent_id, wait_tid).ok_or(SyscallError::NotFound)?;
251
252 loop {
253 match crate::process::try_wait_child(parent_id, Some(child_id)) {
254 WaitChildResult::Reaped { status, .. } => {
255 if status_ptr != 0 {
256 let out = crate::memory::UserSliceWrite::new(status_ptr, 4)
257 .map_err(|_| SyscallError::Fault)?;
258 out.copy_from(&(status as i32).to_ne_bytes());
259 }
260 return Ok(wait_tid as u64);
261 }
262 WaitChildResult::NoChildren => return Err(SyscallError::NotFound),
263 WaitChildResult::StillRunning => block_current_task(),
264 }
265 }
266}
267
268pub fn sys_thread_exit(exit_code: u64) -> Result<u64, SyscallError> {
270 let code = i32::try_from(exit_code).map_err(|_| SyscallError::InvalidArgument)?;
271 crate::process::scheduler::exit_current_task(code)
272}
273
274pub fn sys_getppid() -> Result<u64, SyscallError> {
276 let child = current_task_id().ok_or(SyscallError::Fault)?;
277 Ok(get_parent_pid(child).map(|p| p as u64).unwrap_or(0))
278}
279
280pub fn sys_getpgid(pid: i64) -> Result<u64, SyscallError> {
282 if pid < 0 {
283 return Err(SyscallError::InvalidArgument);
284 }
285 if pid == 0 {
286 return current_pgid()
287 .map(|pgid| pgid as u64)
288 .ok_or(SyscallError::Fault);
289 }
290 get_pgid_by_pid(pid as u32)
291 .map(|pgid| pgid as u64)
292 .ok_or(SyscallError::NotFound)
293}
294
295pub fn sys_getpgrp() -> Result<u64, SyscallError> {
297 current_pgid()
298 .map(|pgid| pgid as u64)
299 .ok_or(SyscallError::Fault)
300}
301
302pub fn sys_getsid(pid: i64) -> Result<u64, SyscallError> {
304 if pid < 0 {
305 return Err(SyscallError::InvalidArgument);
306 }
307 if pid == 0 {
308 return crate::process::current_sid()
309 .map(|sid| sid as u64)
310 .ok_or(SyscallError::Fault);
311 }
312 get_sid_by_pid(pid as u32)
313 .map(|sid| sid as u64)
314 .ok_or(SyscallError::NotFound)
315}
316
317pub fn sys_setpgid(pid: i64, pgid: i64) -> Result<u64, SyscallError> {
319 if pid < 0 || pgid < 0 {
320 return Err(SyscallError::InvalidArgument);
321 }
322 let caller = current_task_id().ok_or(SyscallError::Fault)?;
323 let target_pid = if pid == 0 { None } else { Some(pid as u32) };
324 let new_pgid = if pgid == 0 { None } else { Some(pgid as u32) };
325 let final_pgid = set_process_group(caller, target_pid, new_pgid)?;
326 Ok(final_pgid as u64)
327}
328
329pub fn sys_setsid() -> Result<u64, SyscallError> {
331 let caller = current_task_id().ok_or(SyscallError::Fault)?;
332 create_session(caller).map(|sid| sid as u64)
333}
334
335pub fn sys_getuid() -> Result<u64, SyscallError> {
339 let task = current_task_clone().ok_or(SyscallError::Fault)?;
340 Ok(task.uid.load(Ordering::Relaxed) as u64)
341}
342
343pub fn sys_geteuid() -> Result<u64, SyscallError> {
345 let task = current_task_clone().ok_or(SyscallError::Fault)?;
346 Ok(task.euid.load(Ordering::Relaxed) as u64)
347}
348
349pub fn sys_getgid() -> Result<u64, SyscallError> {
351 let task = current_task_clone().ok_or(SyscallError::Fault)?;
352 Ok(task.gid.load(Ordering::Relaxed) as u64)
353}
354
355pub fn sys_getegid() -> Result<u64, SyscallError> {
357 let task = current_task_clone().ok_or(SyscallError::Fault)?;
358 Ok(task.egid.load(Ordering::Relaxed) as u64)
359}
360
361pub fn sys_setuid(uid: u64) -> Result<u64, SyscallError> {
363 if uid > u32::MAX as u64 {
364 return Err(SyscallError::InvalidArgument);
365 }
366 let task = current_task_clone().ok_or(SyscallError::Fault)?;
367 let euid = task.euid.load(Ordering::Relaxed);
369 let cur_uid = task.uid.load(Ordering::Relaxed);
370 if euid != 0 && uid as u32 != cur_uid && uid as u32 != euid {
371 return Err(SyscallError::PermissionDenied);
372 }
373 task.uid.store(uid as u32, Ordering::Relaxed);
374 task.euid.store(uid as u32, Ordering::Relaxed);
375 Ok(0)
376}
377
378pub fn sys_setgid(gid: u64) -> Result<u64, SyscallError> {
380 if gid > u32::MAX as u64 {
381 return Err(SyscallError::InvalidArgument);
382 }
383 let task = current_task_clone().ok_or(SyscallError::Fault)?;
384 let euid = task.euid.load(Ordering::Relaxed);
385 let cur_gid = task.gid.load(Ordering::Relaxed);
386 let egid = task.egid.load(Ordering::Relaxed);
387 if euid != 0 && gid as u32 != cur_gid && gid as u32 != egid {
388 return Err(SyscallError::PermissionDenied);
389 }
390 task.gid.store(gid as u32, Ordering::Relaxed);
391 task.egid.store(gid as u32, Ordering::Relaxed);
392 Ok(0)
393}
394
395pub fn sys_set_tid_address(tidptr: u64) -> Result<u64, SyscallError> {
402 let task = current_task_clone().ok_or(SyscallError::Fault)?;
403 task.clear_child_tid.store(tidptr, Ordering::Relaxed);
404 Ok(task.tid as u64)
405}
406
407pub fn sys_exit_group(exit_code: u64) -> Result<u64, SyscallError> {
409 let current = current_task_clone().ok_or(SyscallError::Fault)?;
410 for sibling_id in get_task_ids_in_tgid(current.tgid) {
411 if sibling_id != current.id {
412 let _ = kill_task(sibling_id);
413 }
414 }
415
416 crate::process::scheduler::exit_current_task(exit_code as i32)
418}
419
420const ARCH_SET_GS: u64 = 0x1001;
424const ARCH_SET_FS: u64 = 0x1002;
425const ARCH_GET_FS: u64 = 0x1003;
426const ARCH_GET_GS: u64 = 0x1004;
427
428const MSR_FS_BASE: u32 = 0xC000_0100;
430const MSR_GS_BASE: u32 = 0xC000_0101;
431
432pub fn sys_arch_prctl(code: u64, addr: u64) -> Result<u64, SyscallError> {
438 let task = current_task_clone().ok_or(SyscallError::Fault)?;
439 match code {
440 ARCH_SET_FS => {
441 task.user_fs_base.store(addr, Ordering::Relaxed);
443 unsafe { wrmsr(MSR_FS_BASE, addr) };
445 Ok(0)
446 }
447 ARCH_GET_FS => {
448 let base = task.user_fs_base.load(Ordering::Relaxed);
449 use crate::memory::UserSliceWrite;
451 let out = UserSliceWrite::new(addr, 8).map_err(|_| SyscallError::Fault)?;
452 out.copy_from(&base.to_ne_bytes());
453 Ok(0)
454 }
455 ARCH_SET_GS => {
456 unsafe { wrmsr(MSR_GS_BASE, addr) };
458 Ok(0)
459 }
460 ARCH_GET_GS => {
461 let base = unsafe { rdmsr(MSR_GS_BASE) };
462 use crate::memory::UserSliceWrite;
463 let out = UserSliceWrite::new(addr, 8).map_err(|_| SyscallError::Fault)?;
464 out.copy_from(&base.to_ne_bytes());
465 Ok(0)
466 }
467 _ => Err(SyscallError::InvalidArgument),
468 }
469}
470
471#[inline]
476unsafe fn wrmsr(msr: u32, value: u64) {
477 let lo = value as u32;
478 let hi = (value >> 32) as u32;
479 unsafe {
480 core::arch::asm!(
481 "wrmsr",
482 in("ecx") msr,
483 in("eax") lo,
484 in("edx") hi,
485 options(nostack, preserves_flags),
486 );
487 }
488}
489
490#[inline]
495unsafe fn rdmsr(msr: u32) -> u64 {
496 let lo: u32;
497 let hi: u32;
498 unsafe {
499 core::arch::asm!(
500 "rdmsr",
501 in("ecx") msr,
502 out("eax") lo,
503 out("edx") hi,
504 options(nostack, preserves_flags),
505 );
506 }
507 lo as u64 | ((hi as u64) << 32)
508}
509
510pub fn sys_tgkill(tgid: u64, tid: u64, signum: u64) -> Result<u64, SyscallError> {
517 use crate::process::{get_task_by_pid, send_signal, Signal};
518
519 if signum as u32 >= 64 {
521 return Err(SyscallError::InvalidArgument);
522 }
523
524 let task = get_task_by_pid(tgid as u32).ok_or(SyscallError::NotFound)?;
526
527 if task.tid as u64 != tid && task.pid as u64 != tid {
529 return Err(SyscallError::NotFound);
530 }
531
532 if signum == 0 {
533 return Ok(0); }
535
536 let sig = Signal::from_u32(signum as u32).ok_or(SyscallError::InvalidArgument)?;
537 send_signal(task.id, sig)?;
538 Ok(0)
539}