kernel/task/
syscall.rs

1//! Task-related system call implementations.
2//!
3//! This module implements system calls that interact with task management,
4//! filesystem operations, and process control. Many operations leverage
5//! the VfsManager for filesystem access when tasks have isolated namespaces.
6//!
7//! # VfsManager Integration
8//!
9//! System calls automatically use the task's VfsManager when available:
10//! - Tasks with `vfs: Some(Arc<VfsManager>)` use their isolated filesystem namespace
11//! - Tasks with `vfs: None` fall back to global filesystem operations
12//! - Bind mount operations enable controlled sharing between isolated namespaces
13//! - All filesystem operations are thread-safe and handle concurrent access properly
14
15use alloc::vec::Vec;
16
17use crate::abi::MAX_ABI_LENGTH;
18use crate::device::manager::DeviceManager;
19use crate::executor::executor::TransparentExecutor;
20use crate::fs::MAX_PATH_LENGTH;
21use crate::library::std::string::{parse_c_string_from_userspace, parse_string_array_from_userspace};
22
23use crate::arch::{get_cpu, Trapframe};
24use crate::sched::scheduler::get_scheduler;
25use crate::task::{get_parent_waker, get_task_waker, CloneFlags, WaitError};
26
27const MAX_ARG_COUNT: usize = 256; // Maximum number of arguments for execve
28
29// Flags for execve system calls
30pub const EXECVE_FORCE_ABI_REBUILD: usize = 0x1; // Force ABI environment reconstruction
31
32use super::mytask;
33
34pub fn sys_brk(trapframe: &mut Trapframe) -> usize {
35    let task = mytask().unwrap();
36    let brk = trapframe.get_arg(0);
37    trapframe.increment_pc_next(task);
38    match task.set_brk(brk) {
39        Ok(_) => task.get_brk(),
40        Err(_) => usize::MAX, /* -1 */
41    }
42}
43
44pub fn sys_sbrk(trapframe: &mut Trapframe) -> usize {
45    let task = mytask().unwrap();
46    let increment = trapframe.get_arg(0);
47    let brk = task.get_brk();
48    trapframe.increment_pc_next(task);
49    match task.set_brk(unsafe { brk.unchecked_add(increment) }) {
50        Ok(_) => brk,
51        Err(_) => usize::MAX, /* -1 */
52    }
53}
54
55pub fn sys_putchar(trapframe: &mut Trapframe) -> usize {
56    let c = trapframe.get_arg(0) as u32;
57    let task = mytask().unwrap();
58    trapframe.increment_pc_next(task);
59    if let Some(ch) = char::from_u32(c) {
60        let manager = DeviceManager::get_manager();
61        if let Some(device_id) = manager.get_first_device_by_type(crate::device::DeviceType::Char) {
62            if let Some(char_device) = manager.get_device(device_id).unwrap().as_char_device() {
63                // Use CharDevice trait methods to write
64                if let Err(e) = char_device.write_byte(ch as u8) {
65                    crate::print!("Error writing character: {}", e);
66                    return usize::MAX; // -1
67                }
68                // Successfully written character
69                return 0;
70            }
71        }
72    }
73    return usize::MAX; // -1
74}
75
76pub fn sys_getchar(trapframe: &mut Trapframe) -> usize {
77    let task = mytask().unwrap();
78    trapframe.increment_pc_next(task);
79    
80    // Find TTY device for blocking input
81    let manager = DeviceManager::get_manager();
82    if let Some(borrowed_device) = manager.get_device_by_name("tty0") {
83        if let Some(char_device) = borrowed_device.as_char_device() {
84            // Check if data is available
85            if let Some(byte) = char_device.read_byte() {
86                return byte as usize;
87            }
88        }
89    }
90    
91    0 // Return 0 if no device found (should not happen)
92}
93
94pub fn sys_exit(trapframe: &mut Trapframe) -> usize {
95    let task = mytask().unwrap();
96    task.vcpu.store(trapframe);
97    let exit_code = trapframe.get_arg(0) as i32;
98    task.exit(exit_code);
99    // The scheduler will handle saving the current task state internally
100    get_scheduler().schedule(get_cpu());
101}
102
103pub fn sys_clone(trapframe: &mut Trapframe) -> usize {
104    let parent_task = mytask().unwrap();
105    trapframe.increment_pc_next(parent_task); /* Increment the program counter */
106    /* Save the trapframe to the task before cloning */
107    parent_task.vcpu.store(trapframe);
108    let clone_flags = CloneFlags::from_raw(trapframe.get_arg(0) as u64);
109
110    /* Clone the task */
111    match parent_task.clone_task(clone_flags) {
112        Ok(mut child_task) => {
113            let child_id = child_task.get_id();
114            child_task.vcpu.regs.reg[10] = 0; /* Set the return value to 0 in the child task */
115            get_scheduler().add_task(child_task, get_cpu().get_cpuid());
116            /* Return the child task ID to the parent task */
117            child_id
118        },
119        Err(_) => {
120            usize::MAX /* Return -1 on error */
121        }
122    }
123}
124
125pub fn sys_execve(trapframe: &mut Trapframe) -> usize {
126    let task = mytask().unwrap();
127    
128    // Increment PC to avoid infinite loop if execve fails
129    trapframe.increment_pc_next(task);
130    
131    // Get arguments from trapframe
132    let path_ptr = trapframe.get_arg(0);
133    let argv_ptr = trapframe.get_arg(1);
134    let envp_ptr = trapframe.get_arg(2);
135    let flags = trapframe.get_arg(3); // New flags argument
136    
137    // Parse path
138    let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
139        Ok(path) => path,
140        Err(_) => return usize::MAX, // Path parsing error
141    };
142    
143    // Parse argv and envp
144    let argv_strings = match parse_string_array_from_userspace(task, argv_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
145        Ok(args) => args,
146        Err(_) => return usize::MAX, // argv parsing error
147    };
148    
149    let envp_strings = match parse_string_array_from_userspace(task, envp_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
150        Ok(env) => env,
151        Err(_) => return usize::MAX, // envp parsing error
152    };
153    
154    // Convert Vec<String> to Vec<&str> for TransparentExecutor
155    let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
156    let envp_refs: Vec<&str> = envp_strings.iter().map(|s| s.as_str()).collect();
157    
158    // Check if force ABI rebuild is requested
159    let force_abi_rebuild = (flags & EXECVE_FORCE_ABI_REBUILD) != 0;
160    
161    // Use TransparentExecutor for cross-ABI execution
162    match TransparentExecutor::execute_binary(&path_str, &argv_refs, &envp_refs, task, trapframe, force_abi_rebuild) {
163        Ok(_) => {
164            // execve normally should not return on success - the process is replaced
165            // However, if ABI module sets trapframe return value and returns here,
166            // we should respect that value instead of hardcoding 0
167            trapframe.get_return_value()
168        },
169        Err(_) => {
170            // Execution failed - return error code
171            // The trap handler will automatically set trapframe return value from our return
172            usize::MAX // Error return value
173        }
174    }
175}
176
177pub fn sys_execve_abi(trapframe: &mut Trapframe) -> usize {
178    let task = mytask().unwrap();
179    
180    // Increment PC to avoid infinite loop if execve fails
181    trapframe.increment_pc_next(task);
182
183    // Get arguments from trapframe
184    let path_ptr = trapframe.get_arg(0);
185    let argv_ptr = trapframe.get_arg(1);
186    let envp_ptr = trapframe.get_arg(2);
187    let abi_str_ptr = trapframe.get_arg(3);
188    let flags = trapframe.get_arg(4); // New flags argument
189    
190    // Parse path
191    let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
192        Ok(path) => path,
193        Err(_) => return usize::MAX, // Path parsing error
194    };
195    
196    // Parse ABI string
197    let abi_str = match parse_c_string_from_userspace(task, abi_str_ptr, MAX_ABI_LENGTH) {
198        Ok(abi) => abi,
199        Err(_) => return usize::MAX, // ABI parsing error
200    };
201    
202    // Parse argv and envp
203    let argv_strings = match parse_string_array_from_userspace(task, argv_ptr, 256, MAX_PATH_LENGTH) {
204        Ok(args) => args,
205        Err(_) => return usize::MAX, // argv parsing error
206    };
207    
208    let envp_strings = match parse_string_array_from_userspace(task, envp_ptr, 256, MAX_PATH_LENGTH) {
209        Ok(env) => env,
210        Err(_) => return usize::MAX, // envp parsing error
211    };
212    
213    // Convert Vec<String> to Vec<&str> for TransparentExecutor
214    let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
215    let envp_refs: Vec<&str> = envp_strings.iter().map(|s| s.as_str()).collect();
216
217    // Check if force ABI rebuild is requested
218    let force_abi_rebuild = (flags & EXECVE_FORCE_ABI_REBUILD) != 0;
219
220    // Use TransparentExecutor for ABI-aware execution
221    match TransparentExecutor::execute_with_abi(
222        &path_str,
223        &argv_refs,
224        &envp_refs,
225        &abi_str,
226        task,
227        trapframe,
228        force_abi_rebuild,
229    ) {
230        Ok(()) => {
231            // execve normally should not return on success - the process is replaced
232            // However, if ABI module sets trapframe return value and returns here,
233            // we should respect that value instead of hardcoding 0
234            trapframe.get_return_value()
235        }
236        Err(_) => {
237            // Execution failed - return error code
238            // The trap handler will automatically set trapframe return value from our return
239            usize::MAX // Error return value
240        }
241    }
242}
243
244pub fn sys_waitpid(trapframe: &mut Trapframe) -> usize {
245    let task = mytask().unwrap();
246    let pid = trapframe.get_arg(0) as i32;
247    let status_ptr = trapframe.get_arg(1) as *mut i32;
248    let _options = trapframe.get_arg(2) as i32; // Not used in this implementation
249
250    if pid == -1 {
251        // Wait for any child process
252        for pid in task.get_children().clone() {
253            match task.wait(pid) {
254                Ok(status) => {
255                    // Child has exited, return the status
256                    if status_ptr != core::ptr::null_mut() {
257                        let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
258                        unsafe {
259                            *status_ptr = status;
260                        }
261                    }
262                    trapframe.increment_pc_next(task);
263                    return pid;
264                },
265                Err(error) => {
266                    match error {
267                        WaitError::ChildNotExited(_) => continue,
268                        _ => {
269                            trapframe.increment_pc_next(task);
270                            return usize::MAX;
271                        },
272                    }
273                }
274            }
275        }
276        
277        // No child has exited yet, block until one does
278        // We wait on the parent's waker since we're waiting for any child (-1)
279        // This is different from waiting for a specific child
280        let parent_waker = get_parent_waker(task.get_id());
281        parent_waker.wait(task, trapframe);
282    }
283    
284    // Wait for specific child process
285    match task.wait(pid as usize) {
286        Ok(status) => {
287            // Child has exited, return the status
288            if status_ptr != core::ptr::null_mut() {
289                let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
290                unsafe {
291                    *status_ptr = status;
292                }
293            }
294            trapframe.increment_pc_next(task);
295            return pid as usize;
296        }
297        Err(error) => {
298            match error {
299                WaitError::NoSuchChild(_) => {
300                    trapframe.increment_pc_next(task);
301                    return usize::MAX;
302                },
303                WaitError::ChildTaskNotFound(_) => {
304                    trapframe.increment_pc_next(task);
305                    crate::print!("Child task with PID {} not found", pid);
306                    return usize::MAX;
307                },
308                WaitError::ChildNotExited(_) => {
309                    // If the child task is not exited, we need to wait for it
310                    let child_waker = get_task_waker(pid as usize);
311                    child_waker.wait(task, trapframe);
312                },
313            }
314        }
315    }
316}
317
318pub fn sys_getpid(trapframe: &mut Trapframe) -> usize {
319    let task = mytask().unwrap();
320    trapframe.increment_pc_next(task);
321    task.get_id() as usize
322}
323
324pub fn sys_getppid(trapframe: &mut Trapframe) -> usize {
325    let task = mytask().unwrap();
326    trapframe.increment_pc_next(task);
327    task.get_parent_id().unwrap_or(task.get_id()) as usize
328}
329