kernel/abi/
scarlet.rs

1//! Scarlet Native ABI Module
2//! 
3//! This module implements the Scarlet ABI for the Scarlet kernel.
4//! It provides the necessary functionality for handling system calls
5//! and interacting with the Scarlet kernel.
6//! 
7
8use alloc::{boxed::Box, collections::btree_map::BTreeMap, format, string::{String, ToString}, sync::Arc, vec::Vec};
9
10use crate::{arch::{vm, Registers, Trapframe}, early_initcall, fs::{drivers::overlayfs::OverlayFS, FileSystemError, FileSystemErrorKind, SeekFrom, VfsManager}, register_abi, syscall::syscall_handler, task::elf_loader::load_elf_into_task, vm::{setup_trampoline, setup_user_stack}};
11
12use super::AbiModule;
13
14#[derive(Default, Copy, Clone)]
15pub struct ScarletAbi;
16
17impl AbiModule for ScarletAbi {
18    fn name() -> &'static str {
19        "scarlet"
20    }
21
22    fn get_name(&self) -> alloc::string::String {
23        Self::name().to_string()
24    }
25
26    fn clone_boxed(&self) -> Box<dyn AbiModule> {
27        Box::new(*self) // ScarletAbi is Copy, so we can dereference and copy
28    }
29
30    fn handle_syscall(&mut self, trapframe: &mut Trapframe) -> Result<usize, &'static str> {
31        syscall_handler(trapframe)
32    }
33
34    fn can_execute_binary(&self, file_object: &crate::object::KernelObject, file_path: &str, current_abi: Option<&dyn crate::abi::AbiModule>) -> Option<u8> {
35        // Stage 1: Basic format validation
36        let magic_score = match file_object.as_file() {
37            Some(file_obj) => {
38                // Check ELF magic bytes (0x7F, 'E', 'L', 'F')
39                let mut magic_buffer = [0u8; 4];
40                file_obj.seek(SeekFrom::Start(0)).ok(); // Reset to start
41                match file_obj.read(&mut magic_buffer) {
42                    Ok(bytes_read) if bytes_read >= 4 => {
43                        if magic_buffer == [0x7F, b'E', b'L', b'F'] {
44                            30 // Basic ELF format compatibility
45                        } else {
46                            return None; // Not an ELF file, cannot execute
47                        }
48                    }
49                    _ => return None // Read failed, cannot determine
50                }
51            }
52            None => return None // Not a file object
53        };
54        
55        let mut confidence = magic_score;
56        
57        // Stage 2: ELF header checks
58        if let Some(file_obj) = file_object.as_file() {
59            // Check ELF header for Scarlet-specific OSABI (83)
60            let mut osabi_buffer = [0u8; 1];
61            file_obj.seek(SeekFrom::Start(7)).ok(); // OSABI is at
62            match file_obj.read(&mut osabi_buffer) {
63                Ok(bytes_read) if bytes_read == 1 => {
64                    if osabi_buffer[0] == 83 { // Scarlet OSABI
65                        confidence += 70; // Strong indicator for Scarlet ABI
66                    }
67                }
68                _ => return None // Read failed, cannot determine
69            }
70        } else {
71            return None; // Not a file object
72        }
73        
74        // Stage 3: File path hints
75        if file_path.ends_with(".elf") || file_path.contains("scarlet") {
76            confidence += 15; // Scarlet-specific path indicators
77        }
78        
79        // Stage 4: ABI inheritance bonus - high priority for same ABI
80        if let Some(abi) = current_abi {
81            if abi.get_name() == self.get_name() {
82                confidence += 40; // Strong inheritance bonus for Scarlet Native
83            }
84        }
85        
86        Some(confidence.min(100))
87    }
88
89    fn execute_binary(
90        &self,
91        file_object: &crate::object::KernelObject,
92        argv: &[&str],
93        envp: &[&str],
94        task: &mut crate::task::Task,
95        trapframe: &mut Trapframe
96    ) -> Result<(), &'static str> {
97        // Get file object from KernelObject::File
98        match file_object.as_file() {
99            Some(file_obj) => {
100                task.text_size = 0;
101                task.data_size = 0;
102                task.stack_size = 0;
103                task.brk = None;
104
105                // Load the ELF file and replace the current process
106                match load_elf_into_task(file_obj, task) {
107                    Ok(entry_point) => {
108                        // Set the name from argv[0] or use default
109                        task.name = argv.get(0).map_or("Unnamed Task".to_string(), |s| s.to_string());
110                        
111                        // Clear old page table entries
112                        let root_page_table = vm::get_root_pagetable(task.vm_manager.get_asid()).unwrap();
113                        root_page_table.unmap_all();
114                        
115                        // Setup the new memory environment
116                        setup_trampoline(&mut task.vm_manager);
117                        let stack_pointer = setup_user_stack(task).1;
118
119                        // Set the new entry point
120                        task.set_entry_point(entry_point as usize);
121                        
122                        // Reset task's registers for clean start
123                        task.vcpu.regs = Registers::new();
124                        task.vcpu.set_sp(stack_pointer);
125
126                        // Setup argv/envp on stack following Unix and RISC-V conventions
127                        let (adjusted_sp, argv_ptr) = self.setup_arguments_on_stack(task, argv, envp, stack_pointer)?;
128                        task.vcpu.set_sp(adjusted_sp);
129                        
130                        // Set RISC-V calling convention registers
131                        // a0 (reg[10]) = argc
132                        // a1 (reg[11]) = argv pointer
133                        task.vcpu.regs.reg[10] = argv.len(); // argc
134                        task.vcpu.regs.reg[11] = argv_ptr; // argv array pointer
135
136                        // crate::println!("Executing binary: {} with entry point: {:#x}", task.name, entry_point);
137                        // crate::println!("Arguments: {:?}", argv);
138                        // crate::println!("Environment: {:?}", envp);
139                        // crate::println!("argv pointer set to: {:#x}", argv_ptr);
140                        // crate::println!("Environment pointer set to: {:#x}", env_ptr);
141
142                        // Switch to the new task
143                        task.vcpu.switch(trapframe);
144                        Ok(())
145                    },
146                    Err(e) => {
147                        // Log error details
148                        crate::println!("ELF loading failed: {}", e.message);
149                        Err("Failed to load ELF binary")
150                    }
151                }
152            },
153            None => Err("Invalid file object type for binary execution"),
154        }
155    }
156
157    fn normalize_env_to_scarlet(&self, envp: &mut Vec<String>) {
158        // Scarlet ABI is already in canonical format, but ensure all paths are absolute
159        // Modify in-place to avoid allocations
160        
161        for env_var in envp.iter_mut() {
162            if let Some(eq_pos) = env_var.find('=') {
163                let key = &env_var[..eq_pos];
164                let value = &env_var[eq_pos + 1..];
165                
166                let normalized_value = match key {
167                    "PATH" | "LD_LIBRARY_PATH" => {
168                        // Ensure all paths are in absolute Scarlet namespace format
169                        self.normalize_path_to_absolute_scarlet(value)
170                    }
171                    "HOME" => {
172                        // Ensure home directory is absolute
173                        if value.starts_with('/') {
174                            value.to_string()
175                        } else {
176                            format!("/home/{}", value)
177                        }
178                    }
179                    _ => value.to_string(), // Most variables pass through unchanged
180                };
181                
182                // Update in-place if value changed
183                let new_env_var = format!("{}={}", key, normalized_value);
184                if new_env_var != *env_var {
185                    *env_var = new_env_var;
186                }
187            }
188        }
189    }
190    
191    fn denormalize_env_from_scarlet(&self, envp: &mut Vec<String>) {
192        // For Scarlet ABI, canonical format is the native format
193        // But ensure proper Scarlet-specific defaults exist
194        
195        // Convert to temporary map for easier processing
196        let mut env_map = BTreeMap::new();
197        for env_var in envp.iter() {
198            if let Some(eq_pos) = env_var.find('=') {
199                let key = env_var[..eq_pos].to_string();
200                let value = env_var[eq_pos + 1..].to_string();
201                env_map.insert(key, value);
202            }
203        }
204        
205        // Add defaults if they don't exist
206        if !env_map.contains_key("PATH") {
207            env_map.insert("PATH".to_string(), "/system/scarlet/bin:/bin:/usr/bin".to_string());
208        }
209        
210        if !env_map.contains_key("SHELL") {
211            env_map.insert("SHELL".to_string(), "/system/scarlet/bin/sh".to_string());
212        }
213        
214        // Convert back to Vec<String> format
215        envp.clear();
216        for (key, value) in env_map.iter() {
217            envp.push(format!("{}={}", key, value));
218        }
219    }
220
221    fn setup_overlay_environment(
222        &self,
223        target_vfs: &Arc<VfsManager>,
224        base_vfs: &Arc<VfsManager>,
225        system_path: &str,
226        config_path: &str,
227    ) -> Result<(), &'static str> {
228        // crate::println!("Setting up Scarlet overlay environment with system path: {} and config path: {}", system_path, config_path);
229        // Scarlet ABI uses overlay mount with system Scarlet tools and config persistence
230        let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
231        let upper_vfs = base_vfs;
232        let fs = match OverlayFS::new_from_paths_and_vfs(Some((upper_vfs, config_path)), lower_vfs_list, "/") {
233            Ok(fs) => fs,
234            Err(e) => {
235                crate::println!("Failed to create overlay filesystem for Scarlet ABI: {}", e.message);
236                return Err("Failed to create Scarlet overlay environment");
237            }
238        };
239
240        match target_vfs.mount(fs, "/", 0) {
241            Ok(()) => Ok(()),
242            Err(e) => {
243                crate::println!("Failed to create cross-VFS overlay for Scarlet ABI: {}", e.message);
244                Err("Failed to create Scarlet overlay environment")
245            }
246        }
247    }
248    
249    fn setup_shared_resources(
250        &self,
251        target_vfs: &Arc<VfsManager>,
252        base_vfs: &Arc<VfsManager>,
253    ) -> Result<(), &'static str> {
254        // crate::println!("Setting up Scarlet shared resources with base VFS");
255        // Scarlet shared resource setup: bind mount common directories and Scarlet gateway
256        match create_dir_if_not_exists(target_vfs, "/home") {
257            Ok(()) => {}
258            Err(e) => {
259                crate::println!("Failed to create /home directory for Scarlet: {}", e.message);
260                return Err("Failed to create /home directory for Scarlet");
261            }
262        }
263
264        match target_vfs.bind_mount_from(base_vfs, "/home", "/home") {
265            Ok(()) => {}
266            Err(_e) => {
267                // crate::println!("Failed to bind mount /home for Scarlet: {}", e.message);
268            }
269        }
270
271        match create_dir_if_not_exists(target_vfs, "/data") {
272            Ok(()) => {}
273            Err(e) => {
274                crate::println!("Failed to create /data directory for Scarlet: {}", e.message);
275                return Err("Failed to create /data directory for Scarlet");
276            }
277        }
278
279        match target_vfs.bind_mount_from(base_vfs, "/data/shared", "/data/shared") {
280            Ok(()) => {}
281            Err(_e) => {
282                // crate::println!("Failed to bind mount /data/shared for Scarlet: {}", e.message);
283            }
284        }
285
286        // Bind mount /dev for device access
287        match create_dir_if_not_exists(target_vfs, "/dev") {
288            Ok(()) => {}
289            Err(e) => {
290                crate::println!("Failed to create /dev directory for Scarlet: {}", e.message);
291                return Err("Failed to create /dev directory for Scarlet");
292            }
293        }
294        match target_vfs.bind_mount_from(base_vfs, "/dev", "/dev") {
295            Ok(()) => {}
296            Err(e) => {
297                crate::println!("Failed to bind mount /dev for Scarlet: {}", e.message);
298                return Err("Failed to bind mount /dev for Scarlet");
299            }
300        }
301
302        // Setup gateway to native Scarlet environment (read-only for security)
303        match create_dir_if_not_exists(target_vfs, "/scarlet") {
304            Ok(()) => {}
305            Err(e) => {
306                crate::println!("Failed to create /scarlet directory for Scarlet: {}", e.message);
307                return Err("Failed to create /scarlet directory for Scarlet");
308            }
309        }
310        match target_vfs.bind_mount_from(base_vfs, "/", "/scarlet") {
311            Ok(()) => Ok(()),
312            Err(e) => {
313                crate::println!("Failed to bind mount native Scarlet root to /scarlet for Scarlet: {}", e.message);
314                return Err("Failed to bind mount native Scarlet root to /scarlet for Scarlet");
315            }
316        }
317    }
318}
319
320impl ScarletAbi {
321    /// Setup argc, argv, and envp on the user stack following Unix conventions
322    /// 
323    /// Standard Unix stack layout (from high to low addresses):
324    /// ```
325    /// [high addresses]
326    /// envp strings (null-terminated)
327    /// argv strings (null-terminated)  
328    /// envp[] array (null-terminated pointer array)
329    /// argv[] array (null-terminated pointer array)
330    /// argc (integer)
331    /// [low addresses - returned stack pointer]
332    /// ```
333    /// 
334    /// # Arguments
335    /// * `task` - The task to set up arguments for
336    /// * `argv` - Command line arguments
337    /// * `envp` - Environment variables
338    /// * `initial_sp` - Initial stack pointer from setup_user_stack
339    /// 
340    /// # Returns
341    /// Tuple of (new stack pointer, argv array pointer)
342    fn setup_arguments_on_stack(
343        &self,
344        task: &mut crate::task::Task,
345        argv: &[&str],
346        envp: &[&str],
347        initial_sp: usize
348    ) -> Result<(usize, usize), &'static str> {
349        // Calculate total size needed
350        let argc = argv.len();
351        let envc = envp.len();
352        
353        // Calculate string sizes (including null terminators)
354        let argv_strings_size: usize = argv.iter().map(|s| s.len() + 1).sum();
355        let envp_strings_size: usize = envp.iter().map(|s| s.len() + 1).sum();
356        
357        // Calculate pointer array sizes (including null terminators)
358        let argv_array_size = (argc + 1) * core::mem::size_of::<usize>(); // +1 for NULL terminator
359        let envp_array_size = (envc + 1) * core::mem::size_of::<usize>(); // +1 for NULL terminator
360        let argc_size = core::mem::size_of::<usize>();
361        
362        // Total space needed
363        let total_size = argc_size + argv_array_size + envp_array_size + argv_strings_size + envp_strings_size;
364        
365        // Align to 16-byte boundary for RISC-V ABI compliance
366        let aligned_total_size = (total_size + 15) & !15;
367        
368        // Calculate new stack pointer
369        let new_sp = initial_sp - aligned_total_size;
370        
371        // Layout from new_sp (low) to initial_sp (high):
372        // argc | argv[] | envp[] | argv_strings | envp_strings
373        
374        let mut current_addr = new_sp;
375        
376        // 1. Write argc
377        self.write_to_stack_memory(task, current_addr, &argc.to_le_bytes())?;
378        current_addr += argc_size;
379        
380        // 2. Save argv array pointer for return value
381        let argv_ptr = current_addr;
382        
383        // 3. Calculate string positions first
384        let argv_strings_start = current_addr + argv_array_size + envp_array_size;
385        let envp_strings_start = argv_strings_start + argv_strings_size;
386        
387        // 4. Write argv[] array
388        let mut string_addr = argv_strings_start;
389        for i in 0..argc {
390            self.write_to_stack_memory(task, current_addr, &string_addr.to_le_bytes())?;
391            current_addr += core::mem::size_of::<usize>();
392            string_addr += argv[i].len() + 1; // Move to next string position
393        }
394        // NULL terminate argv[]
395        let null_ptr: usize = 0;
396        self.write_to_stack_memory(task, current_addr, &null_ptr.to_le_bytes())?;
397        current_addr += core::mem::size_of::<usize>();
398        
399        // 5. Write envp[] array
400        string_addr = envp_strings_start;
401        for i in 0..envc {
402            self.write_to_stack_memory(task, current_addr, &string_addr.to_le_bytes())?;
403            current_addr += core::mem::size_of::<usize>();
404            string_addr += envp[i].len() + 1; // Move to next string position
405        }
406        // NULL terminate envp[]
407        self.write_to_stack_memory(task, current_addr, &null_ptr.to_le_bytes())?;
408        current_addr += core::mem::size_of::<usize>();
409        
410        // 6. Write argv strings
411        for arg in argv {
412            self.write_string_to_stack(task, current_addr, arg)?;
413            current_addr += arg.len() + 1; // +1 for null terminator
414        }
415        
416        // 7. Write envp strings
417        for env in envp {
418            self.write_string_to_stack(task, current_addr, env)?;
419            current_addr += env.len() + 1; // +1 for null terminator
420        }
421        
422        Ok((new_sp, argv_ptr))
423    }
424    
425    /// Write bytes to stack memory using virtual memory translation
426    fn write_to_stack_memory(
427        &self,
428        task: &mut crate::task::Task,
429        vaddr: usize,
430        data: &[u8]
431    ) -> Result<(), &'static str> {
432        match task.vm_manager.translate_vaddr(vaddr) {
433            Some(paddr) => {
434                unsafe {
435                    core::ptr::copy_nonoverlapping(
436                        data.as_ptr(),
437                        paddr as *mut u8,
438                        data.len()
439                    );
440                }
441                Ok(())
442            }
443            None => Err("Failed to translate virtual address for stack write")
444        }
445    }
446    
447    /// Write a null-terminated string to stack memory
448    fn write_string_to_stack(
449        &self,
450        task: &mut crate::task::Task,
451        vaddr: usize,
452        string: &str
453    ) -> Result<(), &'static str> {
454        // Write the string content
455        self.write_to_stack_memory(task, vaddr, string.as_bytes())?;
456        // Write null terminator
457        self.write_to_stack_memory(task, vaddr + string.len(), &[0u8])?;
458        Ok(())
459    }
460
461    /// Normalize path string to absolute Scarlet namespace format
462    /// 
463    /// This ensures all paths in PATH-like variables are absolute and
464    /// in the proper Scarlet namespace format.
465    fn normalize_path_to_absolute_scarlet(&self, path_value: &str) -> String {
466        let paths: Vec<&str> = path_value.split(':').collect();
467        let mut normalized_paths = Vec::new();
468        
469        for path in paths {
470            if path.starts_with('/') {
471                // Already absolute - ensure it's in proper Scarlet namespace
472                if path.starts_with("/system/scarlet/") || path.starts_with("/scarlet/") {
473                    normalized_paths.push(path.to_string());
474                } else {
475                    // Map standard paths to Scarlet namespace
476                    let mapped_path = match path {
477                        "/bin" => "/system/scarlet/bin",
478                        "/usr/bin" => "/system/scarlet/usr/bin",
479                        "/usr/local/bin" => "/system/scarlet/usr/local/bin",
480                        "/sbin" => "/system/scarlet/sbin",
481                        "/usr/sbin" => "/system/scarlet/usr/sbin",
482                        "/lib" => "/system/scarlet/lib",
483                        "/usr/lib" => "/system/scarlet/usr/lib",
484                        "/usr/local/lib" => "/system/scarlet/usr/local/lib",
485                        _ => path, // Keep other absolute paths as-is
486                    };
487                    normalized_paths.push(mapped_path.to_string());
488                }
489            } else if !path.is_empty() {
490                // Relative paths - prefix with current working directory or make absolute
491                normalized_paths.push(format!("/{}", path));
492            }
493            // Skip empty paths
494        }
495        
496        normalized_paths.join(":")
497    }
498}
499
500fn create_dir_if_not_exists(vfs: &Arc<VfsManager>, path: &str) -> Result<(), FileSystemError> {
501    match vfs.create_dir(path) {
502        Ok(()) => Ok(()),
503        Err(e) => {
504            if e.kind == FileSystemErrorKind::AlreadyExists {
505                Ok(()) // Directory already exists, nothing to do
506            } else {
507                Err(e) // Some other error occurred
508            }
509        }
510    }
511}
512
513fn register_scarlet_abi() {
514    register_abi!(ScarletAbi);
515}
516
517early_initcall!(register_scarlet_abi);