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;
16use core::str;
17
18use crate::abi::{AbiRegistry, MAX_ABI_LENGTH};
19use crate::device::manager::DeviceManager;
20use crate::fs::{File, VfsManager, MAX_PATH_LENGTH};
21use crate::task::elf_loader::load_elf_into_task;
22
23use crate::arch::{get_cpu, vm, Registers, Trapframe};
24use crate::print;
25use crate::sched::scheduler::get_scheduler;
26use crate::task::WaitError;
27use crate::vm::{setup_user_stack, setup_trampoline};
28
29use super::mytask;
30
31pub fn sys_brk(trapframe: &mut Trapframe) -> usize {
32    let task = mytask().unwrap();
33    let brk = trapframe.get_arg(0);
34    trapframe.epc += 4;
35    match task.set_brk(brk) {
36        Ok(_) => task.get_brk(),
37        Err(_) => usize::MAX, /* -1 */
38    }
39}
40
41pub fn sys_sbrk(trapframe: &mut Trapframe) -> usize {
42    let task = mytask().unwrap();
43    let increment = trapframe.get_arg(0);
44    let brk = task.get_brk();
45    trapframe.epc += 4;
46    match task.set_brk(unsafe { brk.unchecked_add(increment) }) {
47        Ok(_) => brk,
48        Err(_) => usize::MAX, /* -1 */
49    }
50}
51
52pub fn sys_putchar(trapframe: &mut Trapframe) -> usize {
53    let c = trapframe.get_arg(0) as u32;
54    trapframe.epc += 4;
55    if let Some(ch) = char::from_u32(c) {
56        print!("{}", ch);
57    } else {
58        return usize::MAX; // -1
59    }
60    0
61}
62
63pub fn sys_getchar(trapframe: &mut Trapframe) -> usize {
64    let serial = DeviceManager::get_mut_manager().basic.borrow_mut_serial(0).unwrap();
65    trapframe.epc += 4;
66    
67    if let Some(byte) = serial.get() {
68        byte as usize
69    } else {
70        0 // Return 0 if no data available
71    }
72}
73
74pub fn sys_exit(trapframe: &mut Trapframe) -> usize {
75    let task = mytask().unwrap();
76    task.vcpu.store(trapframe);
77    let exit_code = trapframe.get_arg(0) as i32;
78    task.exit(exit_code);
79    get_scheduler().schedule(get_cpu());
80    trapframe.get_arg(0) as usize
81}
82
83pub fn sys_clone(trapframe: &mut Trapframe) -> usize {
84    let parent_task = mytask().unwrap();
85    
86    trapframe.epc += 4; /* Increment the program counter */
87
88    /* Save the trapframe to the task before cloning */
89    parent_task.vcpu.store(trapframe);
90    
91    /* Clone the task */
92    match parent_task.clone_task() {
93        Ok(mut child_task) => {
94            let child_id = child_task.get_id();
95            child_task.vcpu.regs.reg[10] = 0; /* Set the return value to 0 in the child task */
96            get_scheduler().add_task(child_task, get_cpu().get_cpuid());
97            /* Return the child task ID to the parent task */
98            child_id
99        },
100        Err(_) => {
101            usize::MAX /* Return -1 on error */
102        }
103    }
104}
105
106pub fn sys_execve(trapframe: &mut Trapframe) -> usize {
107    let task = mytask().unwrap();
108    // Get arguments from the trapframe
109    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
110    
111    /* 
112     * The second and third arguments are pointers to arrays of pointers to
113     * null-terminated strings (char **argv, char **envp).
114     * We will not use them in this implementation.
115     */
116    // let argv_ptr = trapframe.get_arg(1) as *const *const u8;
117    // let envp_ptr = trapframe.get_arg(2) as *const *const u8;
118    
119    // Increment PC to avoid infinite loop if execve fails
120    trapframe.epc += 4;
121    
122    // Get the current task
123    let task = mytask().unwrap();
124
125    // Backup the managed pages
126    let mut backup_pages = Vec::new();
127    backup_pages.append(&mut task.managed_pages); // Move the pages to the backup
128    // Backup the vm mapping
129    let backup_vm_mapping = task.vm_manager.remove_all_memory_maps(); // Move the memory mapping to the backup
130    // Backing up the size
131    let backup_text_size = task.text_size;
132    let backup_data_size = task.data_size;
133    
134    // Parse path as a null-terminated C string
135    let mut path_bytes = Vec::new();
136    let mut i = 0;
137    unsafe {
138        loop {
139            let byte = *path_ptr.add(i);
140            if byte == 0 {
141                break;
142            }
143            path_bytes.push(byte);
144            i += 1;
145            
146            // Safety check to prevent infinite loop
147            if i > MAX_PATH_LENGTH {
148                // Restore the managed pages, memory mapping and sizes
149                task.managed_pages = backup_pages; // Restore the pages
150                task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
151                task.text_size = backup_text_size; // Restore the text size
152                task.data_size = backup_data_size; // Restore the data size
153                return usize::MAX; // Path too long
154            }
155        }
156    }
157    
158    // Convert path bytes to string
159    let path_str = match str::from_utf8(&path_bytes) {
160        Ok(s) => match VfsManager::to_absolute_path(&task, s) {
161            Ok(path) => path,
162            Err(_) => {
163                // Restore the managed pages, memory mapping and sizes
164                task.managed_pages = backup_pages; // Restore the pages
165                task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
166                task.text_size = backup_text_size; // Restore the text size
167                task.data_size = backup_data_size; // Restore the data size
168                return usize::MAX; // Path error
169            }
170        },
171        Err(_) => {
172            // Restore the managed pages, memory mapping and sizes
173            task.managed_pages = backup_pages; // Restore the pages
174            task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
175            task.text_size = backup_text_size; // Restore the text size
176            task.data_size = backup_data_size; // Restore the data size
177            return usize::MAX // Invalid UTF-8
178        },
179    };
180    
181    // Ensure that task.vfs is initialized before proceeding.
182    if task.vfs.is_none() {
183        // Restore the managed pages, memory mapping and sizes
184        task.managed_pages = backup_pages; // Restore the pages
185        task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
186        task.text_size = backup_text_size; // Restore the text size
187        task.data_size = backup_data_size; // Restore the data size
188        return usize::MAX; // VFS not initialized
189    }
190    
191    // Try to open the executable file
192    let file = match task.vfs.as_ref() {
193        Some(vfs) => vfs.open(&path_str, 0),
194        None => {
195            // Restore the managed pages, memory mapping and sizes
196            task.managed_pages = backup_pages; // Restore the pages
197            task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
198            task.text_size = backup_text_size; // Restore the text size
199            task.data_size = backup_data_size; // Restore the data size
200            return usize::MAX; // VFS uninitialized
201        }
202    };
203    if file.is_err() {
204        // Restore the managed pages, memory mapping and sizes
205        task.managed_pages = backup_pages; // Restore the pages
206        task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
207        task.text_size = backup_text_size; // Restore the text size
208        task.data_size = backup_data_size; // Restore the data size
209        return usize::MAX; // File open error
210    }
211    let mut file = file.unwrap();
212
213    task.text_size = 0;
214    task.data_size = 0;
215    task.stack_size = 0;
216    
217    // Load the ELF file and replace the current process
218    match load_elf_into_task(&mut file, task) {
219        Ok(entry_point) => {
220            // Set the name
221            task.name = path_str;
222            // Clear page table entries
223            let idx = vm::get_root_page_table_idx(task.vm_manager.get_asid()).unwrap();
224            let root_page_table = vm::get_page_table(idx).unwrap();
225            root_page_table.unmap_all();
226            // Setup the trapframe
227            setup_trampoline(&mut task.vm_manager);
228            // Setup the stack
229            let stack_pointer = setup_user_stack(task);
230
231            // Set the new entry point for the task
232            task.set_entry_point(entry_point as usize);
233            
234            // Reset task's registers (except for those needed for arguments)
235            task.vcpu.regs = Registers::new();
236            // Set the stack pointer
237            task.vcpu.set_sp(stack_pointer);
238
239            // Switch to the new task
240            task.vcpu.switch(trapframe);
241            
242            // Return 0 on success (though this should never actually return)
243            0
244        },
245        Err(_) => {
246            // Restore the managed pages, memory mapping and sizes
247            task.managed_pages = backup_pages; // Restore the pages
248            task.vm_manager.restore_memory_maps(backup_vm_mapping).unwrap(); // Restore the memory mapping
249            task.text_size = backup_text_size; // Restore the text size
250            task.data_size = backup_data_size; // Restore the data size
251
252            // Return error code
253            usize::MAX
254        }
255    }
256}
257
258pub fn sys_execve_abi(trapframe: &mut Trapframe) -> usize {
259    let task = mytask().unwrap();
260    trapframe.epc += 4;
261
262    let abi_str_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(3)).unwrap() as *const u8;
263    let mut abi_bytes = Vec::new();
264    let mut i = 0;
265    unsafe {
266        loop {
267            let byte = *abi_str_ptr.add(i);
268            if byte == 0 {
269                break;
270            }
271            abi_bytes.push(byte);
272            i += 1;
273            
274            // Safety check to prevent infinite loop
275            if i > MAX_ABI_LENGTH {
276                trapframe.epc += 4;
277                return usize::MAX; // Path too long
278            }
279        }
280    }
281    // Convert abi bytes to string
282    let abi_str = match str::from_utf8(&abi_bytes) {
283        Ok(s) => s,
284        Err(_) => return usize::MAX, // Invalid UTF-8
285    };
286    let abi = AbiRegistry::instantiate(abi_str);
287    if abi.is_none() {
288        trapframe.epc += 4;
289        return usize::MAX; // ABI not found
290    }
291    let backup_abi = task.abi.take();
292    task.abi = abi;
293    
294    let res = sys_execve(trapframe);
295    if res == usize::MAX {
296        // Restore the ABI
297        task.abi = backup_abi;
298    }
299    res
300}
301
302pub fn sys_waitpid(trapframe: &mut Trapframe) -> usize {
303    let task = mytask().unwrap();
304    let pid = trapframe.get_arg(0) as i32;
305    let status_ptr = trapframe.get_arg(1) as *mut i32;
306    let _options = trapframe.get_arg(2) as i32; // Not used in this implementation
307
308    if pid == -1 {
309        for pid in task.get_children().clone() {
310            match task.wait(pid) {
311                Ok(status) => {
312                    // If the child task is exited, we can return the status
313                    if status_ptr != core::ptr::null_mut() {
314                        let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
315                        unsafe {
316                            *status_ptr = status;
317                        }
318                    }
319                    trapframe.epc += 4;
320                    return pid;
321                },
322                Err(error) => {
323                    match error {
324                        WaitError::ChildNotExited(_) => continue,
325                        _ => {
326                            trapframe.epc += 4;
327                            return usize::MAX;
328                        },
329                    }
330                }
331            }
332        }
333        // Any child process has exited
334        trapframe.epc += 4;
335        return usize::MAX;
336    }
337    
338    match task.wait(pid as usize) {
339        Ok(status) => {
340            // If the child task is exited, we can return the status
341            if status_ptr != core::ptr::null_mut() {
342                let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
343                unsafe {
344                    *status_ptr = status;
345                }
346            }
347            trapframe.epc += 4;
348            pid as usize
349        }
350        Err(error) => {
351            match error {
352                WaitError::NoSuchChild(_) => {
353                    trapframe.epc += 4;
354                    usize::MAX
355                },
356                WaitError::ChildTaskNotFound(_) => {
357                    trapframe.epc += 4;
358                    usize::MAX
359                },
360                WaitError::ChildNotExited(_) => {
361                    // If the child task is not exited, we need to wait for it
362                    get_scheduler().schedule(trapframe);
363                    trapframe.get_return_value()
364                },
365            }
366        }
367    }
368}
369
370pub fn sys_getpid(trapframe: &mut Trapframe) -> usize {
371    let task = mytask().unwrap();
372    trapframe.epc += 4;
373    task.get_id() as usize
374}
375
376pub fn sys_getppid(trapframe: &mut Trapframe) -> usize {
377    let task = mytask().unwrap();
378    trapframe.epc += 4;
379    task.get_parent_id().unwrap_or(task.get_id()) as usize
380}