kernel/abi/xv6/riscv64/
proc.rs

1use alloc::string::{String, ToString};
2use crate::{
3    arch::{get_cpu, Trapframe}, 
4    fs::FileType, 
5    library::std::string::cstring_to_string,
6    sched::scheduler::get_scheduler, 
7    task::{get_parent_waker, mytask, CloneFlags, WaitError}
8};
9
10/// VFS v2 helper function for path absolutization
11/// TODO: Move this to a shared helper module when VFS v2 provides public API
12fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
13    if path.starts_with('/') {
14        Ok(path.to_string())
15    } else {
16        let cwd = task.cwd.clone().ok_or(())?;
17        let mut absolute_path = cwd;
18        if !absolute_path.ends_with('/') {
19            absolute_path.push('/');
20        }
21        absolute_path.push_str(path);
22        // Simple normalization (removes "//", ".", etc.)
23        let mut components = alloc::vec::Vec::new();
24        for comp in absolute_path.split('/') {
25            match comp {
26                "" | "." => {},
27                ".." => { components.pop(); },
28                _ => components.push(comp),
29            }
30        }
31        Ok("/".to_string() + &components.join("/"))
32    }
33}
34
35/// Helper function to replace the missing get_path_str function
36/// TODO: This should be moved to a shared helper when VFS v2 provides public API
37fn get_path_str_v2(ptr: *const u8) -> Result<String, ()> {
38    const MAX_PATH_LENGTH: usize = 128;
39    cstring_to_string(ptr, MAX_PATH_LENGTH).map(|(s, _)| s).map_err(|_| ())
40}
41
42pub fn sys_fork(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
43    let parent_task = mytask().unwrap();
44    
45    trapframe.increment_pc_next(parent_task); /* Increment the program counter */
46
47    /* Save the trapframe to the task before cloning */
48    parent_task.vcpu.store(trapframe);
49    
50    /* Clone the task */
51    match parent_task.clone_task(CloneFlags::default()) {
52        Ok(mut child_task) => {
53            let child_id = child_task.get_id();
54            child_task.vcpu.regs.reg[10] = 0; /* Set the return value (a0) to 0 in the child proc */
55            get_scheduler().add_task(child_task, get_cpu().get_cpuid());
56            /* Return the child task ID as pid to the parent proc */
57            child_id
58        },
59        Err(_) => {
60            usize::MAX /* Return -1 on error */
61        }
62    }
63}
64
65pub fn sys_exit(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
66    let task = mytask().unwrap();
67    task.vcpu.store(trapframe);
68    let exit_code = trapframe.get_arg(0) as i32;
69    task.exit(exit_code);
70    get_scheduler().schedule(get_cpu());
71}
72
73pub fn sys_wait(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
74    let task = mytask().unwrap();
75    let status_ptr = trapframe.get_arg(0) as *mut i32;
76
77    for pid in task.get_children().clone() {
78        match task.wait(pid) {
79            Ok(status) => {
80                // If the child proc is exited, we can return the status
81                if status_ptr != core::ptr::null_mut() {
82                    let status_ptr = task.vm_manager.translate_vaddr(status_ptr as usize).unwrap() as *mut i32;
83                    unsafe {
84                        *status_ptr = status;
85                    }
86                }
87                trapframe.increment_pc_next(task);
88                return pid;
89            },
90            Err(error) => {
91                match error {
92                    WaitError::ChildNotExited(_) => continue,
93                    _ => {
94                        return trapframe.get_return_value();
95                    },
96                }
97            }
98        }
99    }
100    
101    // No child has exited yet, block until one does
102    // xv6's wait() is equivalent to waitpid(-1), so we use the parent waker
103    let parent_waker = get_parent_waker(task.get_id());
104    parent_waker.wait(task, trapframe);
105}
106
107pub fn sys_kill(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, _trapframe: &mut Trapframe) -> usize {
108    // Implement the kill syscall
109    // This syscall is not yet implemented. Returning ENOSYS error code (-1).
110    usize::MAX
111}
112
113pub fn sys_sbrk(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
114    let task = mytask().unwrap();
115    let increment = trapframe.get_arg(0);
116    let brk = task.get_brk();
117    trapframe.increment_pc_next(task);
118    match task.set_brk(unsafe { brk.unchecked_add(increment) }) {
119        Ok(_) => brk,
120        Err(_) => usize::MAX, /* -1 */
121    }
122}
123
124pub fn sys_chdir(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
125    let task = mytask().unwrap();
126    trapframe.increment_pc_next(task);
127    
128    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0) as usize).unwrap() as *const u8;
129    let path = match get_path_str_v2(path_ptr) {
130        Ok(p) => match to_absolute_path_v2(&task, &p) {
131            Ok(abs_path) => abs_path,
132            Err(_) => return usize::MAX,
133        },
134        Err(_) => return usize::MAX, /* -1 */
135    };
136
137    // Try to open the file
138    let file = match task.vfs.as_ref() {
139        Some(vfs) => vfs.open(&path, 0),
140        None => return usize::MAX, // VFS not initialized
141    };
142    if file.is_err() {
143        return usize::MAX; // -1
144    }
145    let kernel_obj = file.unwrap();
146    let file_handle = kernel_obj.as_file().unwrap();
147    // Check if the file is a directory
148    if file_handle.metadata().unwrap().file_type != FileType::Directory {
149        return usize::MAX; // -1
150    }
151
152    task.cwd = Some(path); // Update the current working directory
153
154    0
155}
156
157pub fn sys_getpid(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
158    let task = mytask().unwrap();
159    trapframe.increment_pc_next(task);
160    task.get_id()
161}