kernel/abi/xv6/riscv64/
mod.rs

1#[macro_use]
2mod macros;
3mod proc;
4mod file;
5pub mod fs;
6mod pipe;
7
8// pub mod drivers;
9
10use alloc::{boxed::Box, string::ToString, sync::Arc, vec::Vec};
11use file::{sys_dup, sys_exec, sys_mknod, sys_open, sys_write};
12use proc::{sys_exit, sys_fork, sys_wait, sys_getpid};
13
14use crate::{
15    abi::{
16        xv6::riscv64::{
17            file::{sys_close, sys_fstat, sys_link, sys_mkdir, sys_read, sys_unlink}, 
18            pipe::sys_pipe, 
19            proc::{sys_chdir, sys_sbrk}
20        }, 
21        AbiModule
22    }, arch::{self, Registers}, early_initcall, fs::{drivers::overlayfs::OverlayFS, FileSystemError, FileSystemErrorKind, SeekFrom, VfsManager}, register_abi, task::elf_loader::load_elf_into_task, vm::{setup_trampoline, setup_user_stack}
23};
24
25const MAX_FDS: usize = 1024; // Maximum number of file descriptors
26
27#[derive(Clone)]
28pub struct Xv6Riscv64Abi {
29    /// File descriptor to handle mapping table (fd -> handle)
30    /// None means the fd is not allocated
31    fd_to_handle: [Option<u32>; MAX_FDS],
32    /// Free file descriptor list for O(1) allocation/deallocation
33    free_fds: Vec<usize>,
34}
35
36impl Default for Xv6Riscv64Abi {
37    fn default() -> Self {
38        // Initialize free_fds with all available file descriptors (0 to MAX_FDS-1)
39        // Pop from the end so fd 0, 1, 2 are allocated first
40        let mut free_fds: Vec<usize> = (0..MAX_FDS).collect();
41        free_fds.reverse(); // Reverse so fd 0 is at the end and allocated first
42        Self {
43            fd_to_handle: [None; MAX_FDS],
44            free_fds,
45        }
46    }
47}
48
49impl Xv6Riscv64Abi {
50    /// Allocate a new file descriptor and map it to a handle
51    pub fn allocate_fd(&mut self, handle: u32) -> Result<usize, &'static str> {
52        let fd = if let Some(freed_fd) = self.free_fds.pop() {
53            // Reuse a previously freed file descriptor (O(1))
54            freed_fd
55        } else {
56            // No more file descriptors available
57            return Err("Too many open files");
58        };
59        
60        self.fd_to_handle[fd] = Some(handle);
61        Ok(fd)
62    }
63    
64    /// Get handle from file descriptor
65    pub fn get_handle(&self, fd: usize) -> Option<u32> {
66        if fd < MAX_FDS {
67            self.fd_to_handle[fd]
68        } else {
69            None
70        }
71    }
72    
73    /// Remove file descriptor mapping
74    pub fn remove_fd(&mut self, fd: usize) -> Option<u32> {
75        if fd < MAX_FDS {
76            if let Some(handle) = self.fd_to_handle[fd].take() {
77                // Add the freed fd back to the free list for reuse (O(1))
78                self.free_fds.push(fd);
79                Some(handle)
80            } else {
81                None
82            }
83        } else {
84            None
85        }
86    }
87    
88    /// Find file descriptor by handle (linear search)
89    pub fn find_fd_by_handle(&self, handle: u32) -> Option<usize> {
90        for (fd, &mapped_handle) in self.fd_to_handle.iter().enumerate() {
91            if let Some(h) = mapped_handle {
92                if h == handle {
93                    return Some(fd);
94                }
95            }
96        }
97        None
98    }
99    
100    /// Remove handle mapping (requires linear search)
101    pub fn remove_handle(&mut self, handle: u32) -> Option<usize> {
102        if let Some(fd) = self.find_fd_by_handle(handle) {
103            self.fd_to_handle[fd] = None;
104            self.free_fds.push(fd);
105            Some(fd)
106        } else {
107            None
108        }
109    }
110
111    /// Initialize standard file descriptors (stdin, stdout, stderr)
112    pub fn init_std_fds(&mut self, stdin_handle: u32, stdout_handle: u32, stderr_handle: u32) {
113        // XV6 convention: fd 0 = stdin, fd 1 = stdout, fd 2 = stderr
114        self.fd_to_handle[0] = Some(stdin_handle);
115        self.fd_to_handle[1] = Some(stdout_handle);
116        self.fd_to_handle[2] = Some(stderr_handle);
117        
118        // Remove std fds from free list
119        self.free_fds.retain(|&fd| fd != 0 && fd != 1 && fd != 2);
120    }
121    
122    /// Get total number of allocated file descriptors
123    pub fn fd_count(&self) -> usize {
124        self.fd_to_handle.iter().filter(|&&h| h.is_some()).count()
125    }
126    
127    /// Get the list of allocated file descriptors (for debugging)
128    pub fn allocated_fds(&self) -> Vec<usize> {
129        self.fd_to_handle.iter()
130            .enumerate()
131            .filter_map(|(fd, &handle)| if handle.is_some() { Some(fd) } else { None })
132            .collect()
133    }
134}
135
136impl AbiModule for Xv6Riscv64Abi {
137    fn name() -> &'static str {
138        "xv6-riscv64"
139    }
140    
141    fn get_name(&self) -> alloc::string::String {
142        Self::name().to_string()
143    }
144
145    fn clone_boxed(&self) -> alloc::boxed::Box<dyn AbiModule> {
146        Box::new(self.clone()) // Xv6Riscv64Abi is Copy, so we can dereference and copy
147    }
148    
149    fn handle_syscall(&mut self, trapframe: &mut crate::arch::Trapframe) -> Result<usize, &'static str> {
150        syscall_handler(self, trapframe)
151    }
152
153    fn can_execute_binary(
154        &self, 
155        file_object: &crate::object::KernelObject, 
156        file_path: &str,
157        current_abi: Option<&dyn AbiModule>
158    ) -> Option<u8> {
159        // Stage 1: Basic format validation (following implementation guidelines)
160        let magic_score = match file_object.as_file() {
161            Some(file_obj) => {
162                // Check ELF magic bytes (XV6 uses ELF format)
163                let mut magic_buffer = [0u8; 4];
164                file_obj.seek(SeekFrom::Start(0)).ok(); // Reset to start
165                match file_obj.read(&mut magic_buffer) {
166                    Ok(bytes_read) if bytes_read >= 4 => {
167                        if magic_buffer == [0x7F, b'E', b'L', b'F'] {
168                            25 // Basic ELF format compatibility (slightly lower than Scarlet)
169                        } else {
170                            return None; // Not an ELF file, cannot execute
171                        }
172                    }
173                    _ => return None // Read failed, cannot determine
174                }
175            }
176            None => return None // Not a file object
177        };
178        
179        let mut confidence = magic_score;
180        
181        // Stage 2: Entry point validation (placeholder - could check ELF header)
182        // TODO: Add ELF header parsing to validate entry point for XV6 compatibility
183        confidence += 10;
184        
185        // Stage 3: File path hints - XV6 specific patterns
186        if file_path.contains("xv6") || file_path.ends_with(".xv6") {
187            confidence += 20; // Strong XV6 indicator
188        } else if file_path.ends_with(".elf") {
189            confidence += 5; // General ELF compatibility
190        }
191        
192        // Stage 4: ABI inheritance bonus - moderate priority for same ABI
193        if let Some(abi) = current_abi {
194            if abi.get_name() == self.get_name() {
195                confidence += 15; // Moderate inheritance bonus for XV6
196            }
197        }
198        
199        Some(confidence.min(100)) // Standard 0-100 confidence range
200    }
201
202    fn execute_binary(
203        &self,
204        file_object: &crate::object::KernelObject,
205        argv: &[&str], 
206        _envp: &[&str],
207        task: &mut crate::task::Task,
208        trapframe: &mut crate::arch::Trapframe
209    ) -> Result<(), &'static str> {
210        match file_object.as_file() {
211            Some(file_obj) => {
212                // Reset task state for XV6 execution
213                task.text_size = 0;
214                task.data_size = 0;
215                task.stack_size = 0;
216                task.brk = None;
217                
218                // Load ELF using XV6-compatible method
219                match load_elf_into_task(file_obj, task) {
220                    Ok(entry_point) => {
221                        // Set the name
222                        task.name = argv.get(0).map_or("xv6".to_string(), |s| s.to_string());
223                        // Clear page table entries
224                        let idx = arch::vm::get_root_pagetable_ptr(task.vm_manager.get_asid()).unwrap();
225                        let root_page_table = arch::vm::get_pagetable(idx).unwrap();
226                        root_page_table.unmap_all();
227                        // Setup the trapframe
228                        setup_trampoline(&mut task.vm_manager);
229                        // Setup the stack
230                        let (_, stack_top) = setup_user_stack(task);
231                        let mut stack_pointer = stack_top as usize;
232
233                        let mut arg_ptrs: Vec<u64> = Vec::new();
234                        for arg in argv.iter() {
235                            let arg_bytes = arg.as_bytes();
236                            stack_pointer -= arg_bytes.len() + 1; // +1 for null terminator
237                            stack_pointer -= stack_pointer % 16; // Align to 16 bytes
238
239                            unsafe {
240                                let translated_stack_pointer = task.vm_manager
241                                    .translate_vaddr(stack_pointer)
242                                    .unwrap();
243                                let stack_slice = core::slice::from_raw_parts_mut(translated_stack_pointer as *mut u8, arg_bytes.len() + 1);
244                                stack_slice[..arg_bytes.len()].copy_from_slice(arg_bytes);
245                                stack_slice[arg_bytes.len()] = 0; // Null terminator
246                            }
247
248                            arg_ptrs.push(stack_pointer as u64); // Store the address of the argument
249                        }
250
251                        let argc = arg_ptrs.len();
252
253                        stack_pointer -= argc * 8;
254                        stack_pointer -= stack_pointer % 16; // Align to 16 bytes
255
256                        // Push the addresses of the arguments onto the stack
257                        unsafe {
258                            let translated_stack_pointer = task.vm_manager
259                                .translate_vaddr(stack_pointer)
260                                .unwrap() as *mut u64;
261                            for (i, &arg_ptr) in arg_ptrs.iter().enumerate() {
262                                *(translated_stack_pointer.add(i)) = arg_ptr;
263                            }
264                        }
265
266                        // Set the new entry point for the task
267                        task.set_entry_point(entry_point as usize);
268                        
269                        // Reset task's registers (except for those needed for arguments)
270                        task.vcpu.regs = Registers::new();
271                        // Set the stack pointer
272                        task.vcpu.set_sp(stack_pointer);
273                        task.vcpu.regs.reg[11] = stack_pointer as usize; // Set the return value (a0) to 0 in the new proc
274                        task.vcpu.regs.reg[10] = argc; // Set argc in a0
275
276                        // Switch to the new task
277                        task.vcpu.switch(trapframe);
278                        Ok(())
279                    },
280                    Err(_e) => {
281                        Err("Failed to load XV6 ELF binary")
282                    }
283                }
284            },
285            None => Err("Invalid file object type for XV6 binary execution"),
286        }
287    }
288
289    fn get_default_cwd(&self) -> &str {
290        "/" // XV6 uses root as default working directory
291    }
292    
293    fn setup_overlay_environment(
294        &self,
295        target_vfs: &Arc<VfsManager>,
296        base_vfs: &Arc<VfsManager>,
297        system_path: &str,
298        config_path: &str,
299    ) -> Result<(), &'static str> {
300        // crate::println!("Setting up XV6 overlay environment with system path: {} and config path: {}", system_path, config_path);
301        // XV6 ABI uses overlay mount with system XV6 tools and config persistence
302        let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
303        let upper_vfs = base_vfs;
304        let fs = match OverlayFS::new_from_paths_and_vfs(Some((upper_vfs, config_path)), lower_vfs_list, "/") {
305            Ok(fs) => fs,
306            Err(e) => {
307                crate::println!("Failed to create overlay filesystem for XV6 ABI: {}", e.message);
308                return Err("Failed to create XV6 overlay environment");
309            }
310        }
311        ;
312        match target_vfs.mount(fs, "/", 0) {
313            Ok(()) => Ok(()),
314            Err(e) => {
315                crate::println!("Failed to create cross-VFS overlay for XV6 ABI: {}", e.message);
316                Err("Failed to create XV6 overlay environment")
317            }
318        }
319    }
320    
321    fn setup_shared_resources(
322        &self,
323        target_vfs: &Arc<VfsManager>,
324        base_vfs: &Arc<VfsManager>,
325    ) -> Result<(), &'static str> {
326        // crate::println!("Setting up XV6 shared resources with base VFS");
327        // XV6 shared resource setup: bind mount common directories and Scarlet gateway
328        match create_dir_if_not_exists(target_vfs, "/home") {
329            Ok(()) => {}
330            Err(e) => {
331                // crate::println!("Failed to create /home directory for XV6: {}", e.message);
332                return Err("Failed to create /home directory for XV6");
333            }
334        }
335
336        match target_vfs.bind_mount_from(base_vfs, "/home", "/home") {
337            Ok(()) => {}
338            Err(e) => {
339                // crate::println!("Failed to bind mount /home for XV6: {}", e.message);
340            }
341        }
342
343        match create_dir_if_not_exists(target_vfs, "/data") {
344            Ok(()) => {}
345            Err(e) => {
346                crate::println!("Failed to create /data directory for XV6: {}", e.message);
347                return Err("Failed to create /data directory for XV6");
348            }
349        }
350
351        match target_vfs.bind_mount_from(base_vfs, "/data/shared", "/data/shared") {
352            Ok(()) => {}
353            Err(e) => {
354                // crate::println!("Failed to bind mount /data/shared for XV6: {}", e.message);
355            }
356        }
357
358        // Setup gateway to native Scarlet environment (read-only for security)
359        match create_dir_if_not_exists(target_vfs, "/scarlet") {
360            Ok(()) => {}
361            Err(e) => {
362                crate::println!("Failed to create /scarlet directory for XV6: {}", e.message);
363                return Err("Failed to create /scarlet directory for XV6");
364            }
365        }
366        match target_vfs.bind_mount_from(base_vfs, "/", "/scarlet") {
367            Ok(()) => Ok(()),
368            Err(e) => {
369                crate::println!("Failed to bind mount native Scarlet root to /scarlet for XV6: {}", e.message);
370                return Err("Failed to bind mount native Scarlet root to /scarlet for XV6");
371            }
372        }
373    }
374
375    fn initialize_from_existing_handles(&self, task: &mut crate::task::Task) -> Result<(), &'static str> {
376        task.handle_table.close_all();
377        Ok(())
378    }
379}
380
381syscall_table! {
382    Invalid = 0 => |_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, _trapframe: &mut crate::arch::Trapframe| {
383        0
384    },
385    Fork = 1 => sys_fork,
386    Exit = 2 => sys_exit,
387    Wait = 3 => sys_wait,
388    Pipe = 4 => sys_pipe,
389    Read = 5 => sys_read,
390    // Kill = 6 => sys_kill,
391    Exec = 7 => sys_exec,
392    Fstat = 8 => sys_fstat,
393    Chdir = 9 => sys_chdir,
394    Dup = 10 => sys_dup,
395    Getpid = 11 => sys_getpid,
396    Sbrk = 12 => sys_sbrk,
397    // Sleep = 13 => sys_sleep,
398    // Uptime = 14 => sys_uptime,
399    Open = 15 => sys_open,
400    Write = 16 => sys_write,
401    Mknod = 17 => sys_mknod,
402    Unlink = 18 => sys_unlink,
403    Link = 19 => sys_link,
404    Mkdir = 20 => sys_mkdir,
405    Close = 21 => sys_close,
406}
407
408fn create_dir_if_not_exists(vfs: &Arc<VfsManager>, path: &str) -> Result<(), FileSystemError> {
409    match vfs.create_dir(path) {
410        Ok(()) => Ok(()),
411        Err(e) => {
412            if e.kind == FileSystemErrorKind::AlreadyExists {
413                Ok(()) // Directory already exists, nothing to do
414            } else {
415                Err(e) // Some other error occurred
416            }
417        }
418    }
419}
420
421fn register_xv6_abi() {
422    register_abi!(Xv6Riscv64Abi);
423}
424
425early_initcall!(register_xv6_abi);