kernel/abi/linux/riscv64/
proc.rs

1use crate::{
2    abi::linux::riscv64::LinuxRiscv64Abi,
3    arch::{Trapframe, get_cpu},
4    sched::scheduler::get_scheduler,
5    task::{CloneFlags, mytask},
6};
7
8// /// VFS v2 helper function for path absolutization
9// /// TODO: Move this to a shared helper module when VFS v2 provides public API
10// fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
11//     if path.starts_with('/') {
12//         Ok(path.to_string())
13//     } else {
14//         let cwd = task.cwd.clone().ok_or(())?;
15//         let mut absolute_path = cwd;
16//         if !absolute_path.ends_with('/') {
17//             absolute_path.push('/');
18//         }
19//         absolute_path.push_str(path);
20//         // Simple normalization (removes "//", ".", etc.)
21//         let mut components = alloc::vec::Vec::new();
22//         for comp in absolute_path.split('/') {
23//             match comp {
24//                 "" | "." => {},
25//                 ".." => { components.pop(); },
26//                 _ => components.push(comp),
27//             }
28//         }
29//         Ok("/".to_string() + &components.join("/"))
30//     }
31// }
32
33// /// Helper function to replace the missing get_path_str function
34// /// TODO: This should be moved to a shared helper when VFS v2 provides public API
35// fn get_path_str_v2(ptr: *const u8) -> Result<String, ()> {
36//     const MAX_PATH_LENGTH: usize = 128;
37//     cstring_to_string(ptr, MAX_PATH_LENGTH).map(|(s, _)| s).map_err(|_| ())
38// }
39
40// pub fn sys_fork(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
41//     let parent_task = mytask().unwrap();
42
43//     trapframe.increment_pc_next(parent_task); /* Increment the program counter */
44//     /* Save the trapframe to the task before cloning */
45//     parent_task.vcpu.lock().store(trapframe);
46
47//     /* Clone the task */
48//     match parent_task.clone_task(CloneFlags::default()) {
49//         Ok(mut child_task) => {
50//             let child_id = child_task.get_id();
51//             child_task.vcpu.regs.reg[10] = 0; /* Set the return value (a0) to 0 in the child proc */
52//             get_scheduler().add_task(child_task, get_cpu().get_cpuid());
53//             /* Return the child task ID as pid to the parent proc */
54//             child_id
55//         },
56//         Err(_) => {
57//             usize::MAX /* Return -1 on error */
58//         }
59//     }
60// }
61
62pub fn sys_set_tid_address(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
63    let task = mytask().unwrap();
64    let tid_ptr = trapframe.get_arg(0);
65
66    let tid_opt = (tid_ptr != 0).then_some(tid_ptr);
67    abi.thread_state_mut().clear_child_tid_ptr = tid_opt;
68
69    trapframe.increment_pc_next(task);
70
71    // Return current task namespace ID (Linux TID visible to user space)
72    task.get_namespace_id()
73}
74
75pub fn sys_exit(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
76    let task = mytask().unwrap();
77    task.vcpu.lock().store(trapframe);
78    let exit_code = trapframe.get_arg(0) as i32;
79
80    task.exit(exit_code);
81    get_scheduler().schedule(trapframe);
82    usize::MAX
83}
84
85pub fn sys_exit_group(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
86    let task = mytask().unwrap();
87    task.vcpu.lock().store(trapframe);
88    let exit_code = trapframe.get_arg(0) as i32;
89    task.exit(exit_code);
90    get_scheduler().schedule(trapframe);
91    usize::MAX
92}
93
94pub fn sys_set_robust_list(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
95    let task = mytask().unwrap();
96    let head = trapframe.get_arg(0);
97    let len = trapframe.get_arg(1);
98
99    let head_opt = (head != 0).then_some(head);
100    let state = abi.thread_state_mut();
101    state.robust_list_head = head_opt;
102    state.robust_list_len = len as usize;
103
104    trapframe.increment_pc_next(task);
105
106    0
107}
108
109// pub fn sys_wait(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
110//     let task = mytask().unwrap();
111//     let status_ptr = trapframe.get_arg(0) as *mut i32;
112
113//     for pid in task.get_children().clone() {
114//         match task.wait(pid) {
115//             Ok(status) => {
116//                 // If the child proc is exited, we can return the status
117//                 if status_ptr != core::ptr::null_mut() {
118//                     let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
119//                     unsafe {
120//                         *status_ptr = status;
121//                     }
122//                 }
123//                 trapframe.increment_pc_next(task);
124//                 return pid;
125//             },
126//             Err(error) => {
127//                 match error {
128//                     WaitError::ChildNotExited(_) => continue,
129//                     _ => {
130//                         return trapframe.get_return_value();
131//                     },
132//                 }
133//             }
134//         }
135//     }
136
137//     // No child has exited yet, block until one does
138//     // xv6's wait() is equivalent to waitpid(-1), so we use the parent waker
139//     let parent_waker = get_parent_waker(task.get_id());
140//     parent_waker.wait(task, trapframe);
141// }
142
143#[allow(dead_code)]
144pub fn sys_kill(_abi: &mut LinuxRiscv64Abi, _trapframe: &mut Trapframe) -> usize {
145    // Implement the kill syscall
146    // This syscall is not yet implemented. Returning ENOSYS error code (-1).
147    usize::MAX
148}
149
150#[allow(dead_code)]
151pub fn sys_sbrk(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
152    let task = mytask().unwrap();
153    let increment = trapframe.get_arg(0) as isize; // Treat as signed increment
154    let current_brk = task.get_brk();
155    trapframe.increment_pc_next(task);
156
157    // Handle increment of 0 (query current brk)
158    if increment == 0 {
159        return current_brk;
160    }
161
162    let new_brk = if increment > 0 {
163        current_brk.checked_add(increment as usize)
164    } else {
165        // Handle negative increment (decrease brk)
166        current_brk.checked_sub((-increment) as usize)
167    };
168
169    let new_brk = match new_brk {
170        Some(brk) => brk,
171        None => {
172            // Overflow/underflow
173            use super::errno;
174            return errno::to_result(errno::ENOMEM);
175        }
176    };
177
178    match task.set_brk(new_brk) {
179        Ok(_) => {
180            let new_actual = task.get_brk();
181            // crate::println!("[brk] sbrk inc={} old={:#x} new={:#x}", increment, current_brk, new_actual);
182            new_actual
183        }
184        Err(_) => {
185            use super::errno;
186            // crate::println!("[brk] sbrk fail inc={} old={:#x}", increment, current_brk);
187            errno::to_result(errno::ENOMEM)
188        }
189    }
190}
191
192pub fn sys_brk(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
193    let task = mytask().unwrap();
194    let new_brk = trapframe.get_arg(0);
195    trapframe.increment_pc_next(task);
196
197    // If new_brk is 0, just return current brk (query current brk)
198    if new_brk == 0 {
199        return task.get_brk();
200    }
201
202    let _old = task.get_brk();
203    match task.set_brk(new_brk) {
204        Ok(_) => {
205            let actual = task.get_brk();
206            // crate::println!("[brk] brk req={:#x} old={:#x} -> {:#x}", new_brk, old, actual);
207            actual
208        }
209        Err(_) => {
210            let cur = task.get_brk();
211            // crate::println!("[brk] brk fail req={:#x} keep={:#x}", new_brk, cur);
212            cur
213        }
214    }
215}
216
217// pub fn sys_chdir(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
218//     let task = mytask().unwrap();
219//     trapframe.increment_pc_next(task);
220
221//     let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0) as usize).unwrap() as *const u8;
222//     let path = match get_path_str_v2(path_ptr) {
223//         Ok(p) => match to_absolute_path_v2(&task, &p) {
224//             Ok(abs_path) => abs_path,
225//             Err(_) => return usize::MAX,
226//         },
227//         Err(_) => return usize::MAX, /* -1 */
228//     };
229
230//     // Try to open the file
231//     let file = match task.vfs.read().clone() {
232//         Some(vfs) => vfs.open(&path, 0),
233//         None => return usize::MAX, // VFS not initialized
234//     };
235//     if file.is_err() {
236//         return usize::MAX; // -1
237//     }
238//     let kernel_obj = file.unwrap();
239//     let file_handle = kernel_obj.as_file().unwrap();
240//     // Check if the file is a directory
241//     if file_handle.metadata().unwrap().file_type != FileType::Directory {
242//         return usize::MAX; // -1
243//     }
244
245//     task.cwd = Some(path); // Update the current working directory
246
247//     0
248// }
249
250pub fn sys_getpid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
251    let task = mytask().unwrap();
252    // Return TGID for Linux semantics; fallback to Task ID if unset
253    let tgid = _abi.thread_state().tgid;
254    trapframe.increment_pc_next(task);
255    if tgid != 0 { tgid } else { task.get_id() }
256}
257
258pub fn sys_getppid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
259    let task = mytask().unwrap();
260    trapframe.increment_pc_next(task);
261    task.get_parent_id().unwrap_or(1) // Return parent PID or 1 if none
262}
263
264/// Linux gettid system call implementation
265/// Returns the calling thread ID (TID). For now, this equals Scarlet Task ID.
266pub fn sys_gettid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
267    let task = mytask().unwrap();
268    trapframe.increment_pc_next(task);
269    task.get_id()
270}
271
272/// Linux prctl system call (syscall 167)
273///
274/// Operations on a process or thread. This is a stub implementation
275/// that returns success for common operations.
276///
277/// Arguments:
278///   - arg0: option (PR_* operation)
279///   - arg1-arg4: operation-specific arguments
280///
281/// Returns:
282/// - 0 on success
283/// - usize::MAX (Linux -1) for unsupported operations
284pub fn sys_prctl(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
285    let task = mytask().unwrap();
286    let option = trapframe.get_arg(0) as i32;
287    let _arg2 = trapframe.get_arg(1);
288    let _arg3 = trapframe.get_arg(2);
289    let _arg4 = trapframe.get_arg(3);
290    let _arg5 = trapframe.get_arg(4);
291
292    trapframe.increment_pc_next(task);
293
294    crate::println!(
295        "[stub] sys_prctl: option={}, arg2={:#x}, arg3={:#x}, arg4={:#x}, arg5={:#x}",
296        option,
297        _arg2,
298        _arg3,
299        _arg4,
300        _arg5
301    );
302
303    // Common PR_* operations (from include/uapi/linux/prctl.h)
304    // For now, just return success for all operations
305    // Specific operations can be implemented as needed
306    0
307}
308
309pub fn sys_setpgid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
310    let task = mytask().unwrap();
311    let _pid = trapframe.get_arg(0);
312    let _pgid = trapframe.get_arg(1);
313    trapframe.increment_pc_next(task);
314    0 // Always succeed
315}
316
317pub fn sys_getpgid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
318    let task = mytask().unwrap();
319    let _pid = trapframe.get_arg(0);
320    trapframe.increment_pc_next(task);
321    task.get_id() // Return current task ID as process group ID
322}
323
324pub fn sys_prlimit64(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
325    let task = mytask().unwrap();
326    let _pid = trapframe.get_arg(0) as i32;
327    let _resource = trapframe.get_arg(1);
328    let _new_rlim_ptr = trapframe.get_arg(2);
329    let old_rlim_ptr = trapframe.get_arg(3);
330
331    trapframe.increment_pc_next(task);
332
333    // If old_rlim is requested, write some reasonable default values
334    if old_rlim_ptr != 0 {
335        if let Some(old_rlim_paddr) = task.vm_manager.translate_vaddr(old_rlim_ptr) {
336            unsafe {
337                // Write a simple rlimit structure with high limits
338                // struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; }
339                let rlimit = old_rlim_paddr as *mut [u64; 2];
340                *rlimit = [
341                    0xFFFFFFFF, // rlim_cur - current limit (high value)
342                    0xFFFFFFFF, // rlim_max - maximum limit (high value)
343                ];
344            }
345        }
346    }
347
348    0 // Always succeed
349}
350
351pub fn sys_getuid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
352    let task = mytask().unwrap();
353    trapframe.increment_pc_next(task);
354
355    0 // Return 0 for the root user (UID 0)
356}
357
358pub fn sys_geteuid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
359    let task = mytask().unwrap();
360    trapframe.increment_pc_next(task);
361
362    0 // Return 0 for the root user (EUID 0)
363}
364
365pub fn sys_getgid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
366    let task = mytask().unwrap();
367    trapframe.increment_pc_next(task);
368
369    0 // Return 0 for the root group (GID 0)
370}
371
372pub fn sys_getegid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
373    let task = mytask().unwrap();
374    trapframe.increment_pc_next(task);
375
376    0 // Return 0 for the root group (EGID 0)
377}
378
379/// Linux utsname structure for uname system call
380/// This structure must match Linux's struct utsname layout
381#[repr(C)]
382#[derive(Debug, Clone, Copy)]
383pub struct UtsName {
384    /// System name (e.g., "Linux")
385    pub sysname: [u8; 65],
386    /// Node name (hostname)
387    pub nodename: [u8; 65],
388    /// Release (kernel version)
389    pub release: [u8; 65],
390    /// Version (kernel build info)
391    pub version: [u8; 65],
392    /// Machine (hardware architecture)
393    pub machine: [u8; 65],
394    /// Domain name (GNU extension)
395    pub domainname: [u8; 65],
396}
397
398impl UtsName {
399    /// Create a new UtsName with Scarlet system information
400    pub fn new() -> Self {
401        let mut uts = UtsName {
402            sysname: [0; 65],
403            nodename: [0; 65],
404            release: [0; 65],
405            version: [0; 65],
406            machine: [0; 65],
407            domainname: [0; 65],
408        };
409
410        // System name - identify as Linux for compatibility
411        let sysname = b"Linux";
412        uts.sysname[..sysname.len()].copy_from_slice(sysname);
413
414        // Node name (hostname)
415        let nodename = b"scarlet";
416        uts.nodename[..nodename.len()].copy_from_slice(nodename);
417
418        // Release (kernel version)
419        let release = b"6.1.0-scarlet_linux_abi_module";
420        uts.release[..release.len()].copy_from_slice(release);
421
422        // Version (build info)
423        let version = b"#1 SMP Scarlet";
424        uts.version[..version.len()].copy_from_slice(version);
425
426        // Machine (architecture)
427        let machine = b"riscv64";
428        uts.machine[..machine.len()].copy_from_slice(machine);
429
430        // Domain name
431        let domainname = b"(none)";
432        uts.domainname[..domainname.len()].copy_from_slice(domainname);
433
434        uts
435    }
436}
437
438/// Linux uname system call implementation
439///
440/// Returns system information including system name, hostname, kernel version,
441/// and hardware architecture. This provides compatibility with Linux applications
442/// that query system information.
443///
444/// # Arguments
445/// - buf: Pointer to utsname structure to fill
446///
447/// # Returns
448/// - 0 on success
449/// - usize::MAX on error (-1 in Linux)
450pub fn sys_uname(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
451    let task = mytask().unwrap();
452    let buf_ptr = trapframe.get_arg(0);
453
454    // Increment PC to avoid infinite loop
455    trapframe.increment_pc_next(task);
456
457    // Translate user space pointer
458    let buf_vaddr = match task.vm_manager.translate_vaddr(buf_ptr) {
459        Some(addr) => addr as *mut UtsName,
460        None => return usize::MAX, // Invalid address
461    };
462
463    if buf_vaddr.is_null() {
464        return usize::MAX; // NULL pointer
465    }
466
467    // Create and copy system information
468    let uts = UtsName::new();
469    unsafe {
470        *buf_vaddr = uts;
471    }
472
473    0 // Success
474}
475
476/// Linux sys_clone implementation for RISC-V64 ABI
477///
478/// RISC-V64 clone argument order (Linux ABI):
479/// long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
480///
481/// Arguments:
482/// - flags: clone flags (CLONE_VM, CLONE_FS, etc.)
483/// - stack: child stack pointer (NULL to duplicate parent stack)
484/// - parent_tid: pointer to store parent TID (for CLONE_PARENT_SETTID)
485/// - child_tid: pointer to store child TID (for CLONE_CHILD_SETTID/CLONE_CHILD_CLEARTID)
486/// - tls: TLS (Thread Local Storage) pointer
487pub fn sys_clone(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
488    let parent_task = match mytask() {
489        Some(t) => t,
490        None => return usize::MAX,
491    };
492
493    let flags = trapframe.get_arg(0);
494    let child_stack = trapframe.get_arg(1);
495    let parent_tid_ptr = trapframe.get_arg(2) as *mut i32; // a2
496    let tls = trapframe.get_arg(3); // a3 (RISC-V: TLS here)
497    let child_tid_ptr = trapframe.get_arg(4) as *mut i32; // a4
498
499    let parent_tid_opt = (!parent_tid_ptr.is_null()).then_some(parent_tid_ptr as usize);
500    let child_tid_opt = (!child_tid_ptr.is_null()).then_some(child_tid_ptr as usize);
501    {
502        let state = abi.thread_state_mut();
503        state.parent_tid_ptr = parent_tid_opt;
504        state.child_tid_ptr = child_tid_opt;
505        if (flags & CLONE_CHILD_CLEARTID) != 0 {
506            state.clear_child_tid_ptr = child_tid_opt;
507        }
508        if (flags & CLONE_SETTLS) != 0 {
509            state.tls_pointer = Some(tls);
510        }
511    }
512
513    // Linux clone flags
514    const CLONE_VM: usize = 0x00000100;
515    const CLONE_FS: usize = 0x00000200;
516    const CLONE_FILES: usize = 0x00000400;
517    // Thread-related flags (accepted but not fully implemented yet)
518    #[allow(dead_code)]
519    const CLONE_SIGHAND: usize = 0x00000800;
520    const CLONE_THREAD: usize = 0x00010000;
521    #[allow(dead_code)]
522    const CLONE_SETTLS: usize = 0x00080000;
523    /// Set child's TID at child_tid_ptr in child's memory
524    #[allow(dead_code)]
525    const CLONE_CHILD_SETTID: usize = 0x01000000;
526    #[allow(dead_code)]
527    const CLONE_PARENT_SETTID: usize = 0x00100000;
528    #[allow(dead_code)]
529    const CLONE_CHILD_CLEARTID: usize = 0x00200000;
530
531    // Accept CLONE_THREAD/CLONE_SIGHAND for minimal thread support.
532    // Note: signal handler sharing and full thread group semantics are partial.
533    // Stash CLONE_THREAD intent so on_task_cloned can initialize child's TGID.
534    {
535        let state = abi.thread_state_mut();
536        state.pending_clone_is_thread = (flags & CLONE_THREAD) != 0;
537    }
538
539    trapframe.increment_pc_next(parent_task);
540    parent_task.vcpu.lock().store(trapframe);
541
542    // Map Linux clone flags to Scarlet CloneFlags
543    let mut cflags = CloneFlags::new();
544    if (flags & CLONE_VM) != 0 {
545        cflags.set(crate::task::CloneFlagsDef::Vm);
546    }
547    if (flags & CLONE_FS) != 0 {
548        cflags.set(crate::task::CloneFlagsDef::Fs);
549    }
550    if (flags & CLONE_FILES) != 0 {
551        cflags.set(crate::task::CloneFlagsDef::Files);
552    }
553    if (flags & CLONE_THREAD) != 0 {
554        cflags.set(crate::task::CloneFlagsDef::Thread);
555    }
556
557    let ret = match parent_task.clone_task(cflags) {
558        Ok(mut child_task) => {
559            child_task.vcpu.lock().iregs.reg[10] = 0; // a0 = 0 in child
560            // If child_stack is provided, set child's user SP
561            if child_stack != 0 {
562                child_task.vcpu.lock().set_sp(child_stack);
563            }
564            // If CLONE_SETTLS requested, set tp (x4) to tls for child
565            #[allow(non_snake_case)]
566            const CLONE_SETTLS: usize = 0x00080000;
567            if (flags & CLONE_SETTLS) != 0 {
568                child_task.vcpu.lock().iregs.reg[4] = tls; // x4 = tp
569            }
570
571            let scheduler = get_scheduler();
572            let cpu_id = get_cpu().get_cpuid();
573            let parent_id = parent_task.get_id();
574
575            // Add child and get allocated ID
576            let child_id = scheduler.add_task(child_task, cpu_id);
577
578            // Establish parent-child relationship now that both have valid IDs
579            if let Some(child) = scheduler.get_task_by_id(child_id) {
580                child.set_parent_id(parent_id);
581            }
582            if let Some(parent) = scheduler.get_task_by_id(parent_id) {
583                parent.add_child(child_id);
584            }
585
586            // Do not modify user pthread list; musl manages linkage. No safety-net writes.
587            // Handle parent TID store when CLONE_PARENT_SETTID is requested
588            if (flags & CLONE_PARENT_SETTID) != 0 && !parent_tid_ptr.is_null() {
589                if let Some(paddr) = parent_task
590                    .vm_manager
591                    .translate_vaddr(parent_tid_ptr as usize)
592                {
593                    unsafe {
594                        *(paddr as *mut i32) = child_id as i32;
595                    }
596                }
597            }
598            // IMPORTANT: Only write child TID when CLONE_CHILD_SETTID is set.
599            // For CLONE_CHILD_CLEARTID, the pointer is a futex lock to clear on exit.
600            if (flags & CLONE_CHILD_SETTID) != 0 && !child_tid_ptr.is_null() {
601                if let Some(paddr) = get_scheduler()
602                    .get_task_by_id(child_id)
603                    .unwrap()
604                    .vm_manager
605                    .translate_vaddr(child_tid_ptr as usize)
606                {
607                    unsafe {
608                        *(paddr as *mut i32) = child_id as i32;
609                    }
610                }
611            }
612            child_id
613        }
614        Err(_) => usize::MAX,
615    };
616
617    // Clear pending flag in parent after clone completes
618    abi.thread_state_mut().pending_clone_is_thread = false;
619    ret
620}
621
622/// Linux sys_setgid implementation (syscall 144)
623///
624/// Set group ID. This is a stub implementation that always succeeds.
625///
626/// Arguments:
627/// - gid: group ID to set
628///
629/// Returns:
630/// - 0 on success
631pub fn sys_setgid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
632    let task = match mytask() {
633        Some(t) => t,
634        None => return usize::MAX - 1, // -EPERM
635    };
636
637    let _gid = trapframe.get_arg(0);
638
639    // Increment PC to avoid infinite loop
640    trapframe.increment_pc_next(task);
641
642    // Always succeed - group ID is ignored in this stub
643    0
644}
645
646/// Linux sys_setuid implementation (syscall 146)
647///
648/// Set user ID. This is a stub implementation that always succeeds.
649///
650/// Arguments:
651/// - uid: user ID to set
652///
653/// Returns:
654/// - 0 on success
655pub fn sys_setuid(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
656    let task = match mytask() {
657        Some(t) => t,
658        None => return usize::MAX - 1, // -EPERM
659    };
660
661    let _uid = trapframe.get_arg(0);
662
663    // Increment PC to avoid infinite loop
664    trapframe.increment_pc_next(task);
665
666    // Always succeed - user ID is ignored in this stub
667    0
668}
669
670///
671/// Wait for process to change state (wait4 system call).
672/// This is a stub implementation that returns immediately.
673///
674/// Arguments:
675/// Wait for process to change state (wait4 system call).
676///
677/// This is a Linux-compatible implementation that waits for child processes
678/// to exit and returns their process ID and exit status.
679///
680/// # Arguments
681/// - pid: process ID to wait for
682///   * -1: wait for any child process
683///   * >0: wait for specific child process
684///   * 0 or <-1: wait for process group (not implemented)
685/// - wstatus: pointer to store status information (can be null)
686/// - options: wait options (currently ignored - TODO: implement WNOHANG, WUNTRACED)
687/// - rusage: pointer to resource usage structure (can be null, currently ignored)
688///
689/// # Returns
690/// - On success: process ID of child that changed state
691/// - On error: negated error code (e.g., usize::MAX - 9 for -ECHILD)
692///
693/// # Errors
694/// - ECHILD: no child processes or specified child is not our child
695/// - EFAULT: invalid address for wstatus pointer
696/// - ENOSYS: unsupported operation (process groups)
697/// - EPERM: no current task context
698pub fn sys_wait4(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
699    use crate::task::{WaitError, get_parent_waitpid_waker};
700
701    let task = match mytask() {
702        Some(t) => t,
703        None => return usize::MAX - 1, // -EPERM
704    };
705
706    let pid = trapframe.get_arg(0) as isize;
707    let wstatus = trapframe.get_arg(1) as *mut i32;
708    let _options = trapframe.get_arg(2); // TODO: Handle WNOHANG, WUNTRACED, etc.
709    let _rusage = trapframe.get_arg(3); // TODO: Implement resource usage tracking
710
711    // Check if the task has any children
712    if task.get_children().is_empty() {
713        trapframe.increment_pc_next(task);
714        return usize::MAX - 9; // -ECHILD (no child processes)
715    }
716
717    // Minimal implementation; no verbose logging.
718
719    // Loop until a child exits or an error occurs
720    loop {
721        if pid == -1 {
722            // Wait for any child process
723            for child_pid in task.get_children().clone() {
724                match task.wait(child_pid) {
725                    Ok(status) => {
726                        // Child has exited, return the status
727                        if wstatus != core::ptr::null_mut() {
728                            match task.vm_manager.translate_vaddr(wstatus as usize) {
729                                Some(phys_addr) => {
730                                    let status_ptr = phys_addr as *mut i32;
731                                    unsafe {
732                                        *status_ptr = status;
733                                    }
734                                }
735                                None => {
736                                    // Invalid address, return EFAULT
737                                    trapframe.increment_pc_next(task);
738                                    return usize::MAX - 13; // -EFAULT
739                                }
740                            }
741                        }
742                        trapframe.increment_pc_next(task);
743                        return child_pid;
744                    }
745                    Err(error) => {
746                        match error {
747                            WaitError::NoSuchChild(_) => {
748                                // This child is not our child
749                                continue;
750                            }
751                            WaitError::ChildTaskNotFound(_) => {
752                                // Child task not found in scheduler, continue with other children
753                                continue;
754                            }
755                            WaitError::ChildNotExited(_) => {
756                                // Child not exited yet, continue with other children
757                                continue;
758                            }
759                        }
760                    }
761                }
762            }
763
764            // No child has exited yet, block until one does
765            // Use parent waker for waitpid(-1) semantics
766            let parent_waker = get_parent_waitpid_waker(task.get_id());
767            parent_waker.wait(task.get_id(), task.get_trapframe());
768            // Woken by child exit; re-check children.
769            // Continue the loop to re-check after waking up
770            continue;
771        } else if pid > 0 {
772            // Wait for specific child process
773            let child_pid = pid as usize;
774
775            // Check if this is actually our child
776            if !task.get_children().contains(&child_pid) {
777                trapframe.increment_pc_next(task);
778                return usize::MAX - 9; // -ECHILD (not our child)
779            }
780
781            match task.wait(child_pid) {
782                Ok(status) => {
783                    // Child has exited, return the status
784                    if wstatus != core::ptr::null_mut() {
785                        match task.vm_manager.translate_vaddr(wstatus as usize) {
786                            Some(phys_addr) => {
787                                let status_ptr = phys_addr as *mut i32;
788                                unsafe {
789                                    *status_ptr = status;
790                                }
791                            }
792                            None => {
793                                // Invalid address, return EFAULT
794                                trapframe.increment_pc_next(task);
795                                return usize::MAX - 13; // -EFAULT
796                            }
797                        }
798                    }
799                    trapframe.increment_pc_next(task);
800                    return child_pid;
801                }
802                Err(error) => {
803                    match error {
804                        WaitError::NoSuchChild(_) => {
805                            trapframe.increment_pc_next(task);
806                            return usize::MAX - 9; // -ECHILD
807                        }
808                        WaitError::ChildTaskNotFound(_) => {
809                            trapframe.increment_pc_next(task);
810                            return usize::MAX - 9; // -ECHILD
811                        }
812                        WaitError::ChildNotExited(_) => {
813                            // Child not exited yet, wait for it
814                            use crate::task::get_waitpid_waker;
815                            let child_waker = get_waitpid_waker(child_pid);
816                            child_waker.wait(task.get_id(), task.get_trapframe());
817                            // Woken by specific child exit; re-check.
818                            // Continue the loop to re-check after waking up
819                            continue;
820                        }
821                    }
822                }
823            }
824        } else {
825            // pid <= 0 && pid != -1: wait for process group (not implemented)
826            trapframe.increment_pc_next(task);
827            return usize::MAX - 37; // -ENOSYS (function not implemented)
828        }
829    }
830}
831
832/// Linux sys_membarrier implementation (syscall 283)
833///
834/// Memory barrier system call for ensuring memory ordering between threads.
835/// This is a stub implementation that always succeeds.
836///
837/// Arguments:
838/// - cmd: membarrier command (various MEMBARRIER_CMD_* constants)
839/// - flags: flags for the command (usually 0)
840/// - cpu_id: CPU ID for per-CPU barriers (usually unused)
841///
842/// Returns:
843/// - 0 on success
844/// - Negative error code on failure
845///
846/// Note: This is a no-op stub. On a real system with multiple cores,
847/// this would issue appropriate memory barrier instructions to ensure
848/// memory ordering visibility across CPUs. For single-core or simple
849/// multi-core systems without complex memory reordering, this stub
850/// should be sufficient for most applications.
851pub fn sys_membarrier(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
852    let task = match mytask() {
853        Some(t) => t,
854        None => return usize::MAX - 1, // -EPERM
855    };
856
857    let _cmd = trapframe.get_arg(0);
858    let _flags = trapframe.get_arg(1);
859    let _cpu_id = trapframe.get_arg(2);
860
861    // Increment PC to avoid infinite loop
862    trapframe.increment_pc_next(task);
863
864    // Issue a memory fence to ensure all memory operations are visible
865    // This is a basic implementation - real membarrier has multiple modes
866    core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
867
868    // Always succeed - stub implementation
869    0
870}
871
872/// Linux sys_memfd_create - Create an anonymous file descriptor for memory mapping
873///
874/// Creates a new anonymous file descriptor that can be used for memory mapping.
875/// This is primarily used by Wayland clients for shared memory.
876///
877/// Arguments:
878/// - abi: LinuxRiscv64Abi context
879/// - trapframe: Trapframe containing syscall arguments
880///   - arg0: uname (name for the memfd - can be NULL)
881///   - arg1: flags (MFD_CLOEXEC, MFD_ALLOW_SEALING, etc.)
882///
883/// Returns:
884/// - New file descriptor on success
885/// - usize::MAX (Linux -1) on error
886pub fn sys_memfd_create(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
887    use crate::ipc::SharedMemory;
888    use crate::object::KernelObject;
889
890    let task = match mytask() {
891        Some(t) => t,
892        None => return usize::MAX,
893    };
894
895    let _uname_ptr = trapframe.get_arg(0);
896    let flags = trapframe.get_arg(1) as u32;
897
898    // Increment PC to avoid infinite loop
899    trapframe.increment_pc_next(task);
900
901    // Parse flags (Linux memfd_create flags)
902    const MFD_CLOEXEC: u32 = 0x0001;
903    const MFD_ALLOW_SEALING: u32 = 0x0002;
904    const MFD_SEAL_SEAL: u32 = 0x0004;
905
906    let _cloexec = (flags & MFD_CLOEXEC) != 0;
907    let _allow_sealing = (flags & MFD_ALLOW_SEALING) != 0;
908    let _seal = (flags & MFD_SEAL_SEAL) != 0;
909
910    // Create shared memory object (size 0 initially, will be resized by ftruncate)
911    // Default size for Wayland SHM pools
912    const DEFAULT_SHM_SIZE: usize = crate::environment::PAGE_SIZE; // one page as starting point
913
914    let shm = match SharedMemory::new(DEFAULT_SHM_SIZE, 0x3 /* READ | WRITE */) {
915        Ok(shm) => shm,
916        Err(e) => {
917            crate::early_println!("[sys_memfd_create] Failed to create shared memory: {:?}", e);
918            return usize::MAX;
919        }
920    };
921
922    // Insert into handle table
923    let handle = match task
924        .handle_table
925        .insert(KernelObject::SharedMemory(alloc::sync::Arc::new(shm)))
926    {
927        Ok(h) => h,
928        Err(_) => {
929            crate::early_println!("[sys_memfd_create] Failed to insert handle into table");
930            return usize::MAX;
931        }
932    };
933
934    // Allocate fd for the shared memory
935    let fd = match abi.allocate_fd(handle) {
936        Ok(fd) => fd,
937        Err(_) => {
938            // Clean up on error
939            let _ = task.handle_table.remove(handle);
940            crate::early_println!("[sys_memfd_create] Failed to allocate fd");
941            return usize::MAX;
942        }
943    };
944
945    // crate::early_println!(
946    //     "[sys_memfd_create] Created memfd: fd={}, handle={}",
947    //     fd,
948    //     handle
949    // );
950
951    fd
952}