kernel/abi/scarlet/
riscv64.rs

1//! Scarlet Native ABI Module (RISC-V)
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
7use alloc::{
8    boxed::Box,
9    collections::btree_map::BTreeMap,
10    format,
11    string::{String, ToString},
12    sync::Arc,
13    vec::Vec,
14};
15use core::sync::atomic::Ordering;
16
17use crate::{
18    arch::{Trapframe, vm},
19    early_initcall,
20    fs::{
21        FileSystemError, FileSystemErrorKind, SeekFrom, VfsManager, drivers::overlayfs::OverlayFS,
22    },
23    register_abi,
24    syscall::syscall_handler,
25    task::elf_loader::{
26        ExecutionMode, LoadStrategy, LoadTarget, analyze_and_load_elf_with_strategy,
27        build_auxiliary_vector, setup_auxiliary_vector_on_stack,
28    },
29    vm::setup_user_stack,
30};
31
32use crate::abi::AbiModule;
33
34#[derive(Clone, Copy)]
35pub struct ScarletAbi {
36    /// TLS (Thread Local Storage) pointer for this task
37    pub tls_pointer: Option<usize>,
38    /// clear_child_tid pointer for thread exit notification (Linux-compatible)
39    pub clear_child_tid_ptr: Option<usize>,
40}
41
42impl Default for ScarletAbi {
43    fn default() -> Self {
44        Self {
45            tls_pointer: None,
46            clear_child_tid_ptr: None,
47        }
48    }
49}
50
51impl ScarletAbi {
52    /// Get the TLS pointer for this task
53    pub fn tls_pointer(&self) -> Option<usize> {
54        self.tls_pointer
55    }
56
57    /// Set the TLS pointer for this task
58    pub fn set_tls_pointer(&mut self, ptr: usize) {
59        self.tls_pointer = Some(ptr);
60    }
61
62    /// Clear the TLS pointer for this task
63    pub fn clear_tls_pointer(&mut self) {
64        self.tls_pointer = None;
65    }
66
67    /// Set the clear_child_tid pointer for thread exit notification
68    pub fn set_clear_child_tid(&mut self, ptr: usize) {
69        self.clear_child_tid_ptr = Some(ptr);
70    }
71
72    /// Handle task exit with TLS cleanup (Linux-compatible)
73    pub fn on_task_exit(&mut self, task: &crate::task::Task) {
74        // Linux-compatible behavior: write 0 to clear_child_tid and futex wake
75        if let Some(ptr) = self.clear_child_tid_ptr {
76            if let Some(paddr) = task.vm_manager.translate_vaddr(ptr) {
77                unsafe {
78                    *(paddr as *mut i32) = 0;
79                }
80            }
81            // Note: Futex wake for clear_child_tid is handled by the Linux ABI's
82            // on_task_exit implementation. For Scarlet Native, we just clear the value.
83        }
84    }
85}
86
87impl AbiModule for ScarletAbi {
88    fn name() -> &'static str {
89        "scarlet"
90    }
91
92    fn get_name(&self) -> alloc::string::String {
93        Self::name().to_string()
94    }
95
96    fn clone_boxed(&self) -> Box<dyn AbiModule + Send + Sync> {
97        Box::new(*self) // ScarletAbi is Copy, so we can dereference and copy
98    }
99
100    fn handle_syscall(&mut self, trapframe: &mut Trapframe) -> Result<usize, &'static str> {
101        syscall_handler(trapframe)
102    }
103
104    fn can_execute_binary(
105        &self,
106        file_object: &crate::object::KernelObject,
107        file_path: &str,
108        current_abi: Option<&(dyn crate::abi::AbiModule + Send + Sync)>,
109    ) -> Option<u8> {
110        // Stage 1: Basic format validation
111        let magic_score = match file_object.as_file() {
112            Some(file_obj) => {
113                // Check ELF magic bytes (0x7F, 'E', 'L', 'F')
114                let mut magic_buffer = [0u8; 4];
115                file_obj.seek(SeekFrom::Start(0)).ok(); // Reset to start
116                match file_obj.read(&mut magic_buffer) {
117                    Ok(bytes_read) if bytes_read >= 4 => {
118                        if magic_buffer == [0x7F, b'E', b'L', b'F'] {
119                            30 // Basic ELF format compatibility
120                        } else {
121                            return None; // Not an ELF file, cannot execute
122                        }
123                    }
124                    _ => return None, // Read failed, cannot determine
125                }
126            }
127            None => return None, // Not a file object
128        };
129
130        let mut confidence = magic_score;
131
132        // Stage 2: ELF header checks
133        if let Some(file_obj) = file_object.as_file() {
134            // Check ELF header for Scarlet-specific OSABI (83)
135            let mut osabi_buffer = [0u8; 1];
136            file_obj.seek(SeekFrom::Start(7)).ok(); // OSABI is at
137            match file_obj.read(&mut osabi_buffer) {
138                Ok(bytes_read) if bytes_read == 1 => {
139                    if osabi_buffer[0] == 83 {
140                        // Scarlet OSABI
141                        confidence += 70; // Strong indicator for Scarlet ABI
142                    }
143                }
144                _ => return None, // Read failed, cannot determine
145            }
146        } else {
147            return None; // Not a file object
148        }
149
150        // Stage 3: File path hints
151        if file_path.ends_with(".elf") || file_path.contains("scarlet") {
152            confidence += 15; // Scarlet-specific path indicators
153        }
154
155        // Stage 4: ABI inheritance bonus - high priority for same ABI
156        if let Some(abi) = current_abi {
157            if abi.get_name() == self.get_name() {
158                confidence += 40; // Strong inheritance bonus for Scarlet Native
159            }
160        }
161
162        Some(confidence.min(100))
163    }
164
165    fn get_runtime_config(
166        &self,
167        file_object: &crate::object::KernelObject,
168        file_path: &str,
169    ) -> Option<crate::abi::RuntimeConfig> {
170        // Example: Delegate WebAssembly binaries to a Scarlet-native Wasm runtime
171        // This demonstrates how to configure runtime delegation
172
173        // Check for Wasm magic bytes (0x00 0x61 0x73 0x6D) or .wasm extension
174        let is_wasm = if let Some(file_obj) = file_object.as_file() {
175            let mut magic_buffer = [0u8; 4];
176            // Save current position to restore later
177            let original_pos = file_obj.seek(SeekFrom::Current(0)).ok();
178
179            // Check magic bytes
180            let has_wasm_magic = if file_obj.seek(SeekFrom::Start(0)).is_ok() {
181                match file_obj.read(&mut magic_buffer) {
182                    Ok(bytes_read) if bytes_read >= 4 => {
183                        magic_buffer == [0x00, 0x61, 0x73, 0x6D] // Wasm magic "\0asm"
184                    }
185                    _ => false,
186                }
187            } else {
188                false
189            };
190
191            // Restore original file position
192            if let Some(pos) = original_pos {
193                let _ = file_obj.seek(SeekFrom::Start(pos));
194            }
195
196            has_wasm_magic
197        } else {
198            false
199        } || file_path.ends_with(".wasm");
200
201        if is_wasm {
202            // Delegate to Scarlet-native Wasm runtime
203            Some(crate::abi::RuntimeConfig {
204                runtime_path: "/system/scarlet/bin/wasm-runtime".to_string(),
205                runtime_abi: None, // Auto-detect (will be Scarlet native)
206                runtime_args: alloc::vec!["--wasm".to_string()],
207            })
208        } else {
209            // Not a Wasm binary, execute directly (or return None for unknown formats)
210            None
211        }
212    }
213
214    fn execute_binary(
215        &self,
216        file_object: &crate::object::KernelObject,
217        argv: &[&str],
218        envp: &[&str],
219        task: &crate::task::Task,
220        trapframe: &mut Trapframe,
221    ) -> Result<(), &'static str> {
222        // Get file object from KernelObject::File
223        match file_object.as_file() {
224            Some(file_obj) => {
225                task.text_size.store(0, Ordering::SeqCst);
226                task.data_size.store(0, Ordering::SeqCst);
227                task.stack_size.store(0, Ordering::SeqCst);
228                task.brk
229                    .store(usize::MAX, core::sync::atomic::Ordering::SeqCst);
230
231                // Create Scarlet-specific loading strategy
232                let strategy = LoadStrategy {
233                    choose_base_address: |target, needs_relocation| match (target, needs_relocation)
234                    {
235                        (LoadTarget::MainProgram, false) => 0, // ET_EXEC: absolute
236                        (LoadTarget::MainProgram, true) => 0x10000, // ET_DYN: PIE
237                        (LoadTarget::Interpreter, _) => 0x40000000, // Dynamic linker
238                        (LoadTarget::SharedLib, _) => 0x50000000, // Shared libraries
239                    },
240                    resolve_interpreter: |requested| {
241                        // Scarlet ABI: use interpreter as specified in ELF
242                        requested.map(|s| s.to_string())
243                    },
244                };
245
246                // Load and analyze the ELF file with Scarlet strategy
247                match analyze_and_load_elf_with_strategy(file_obj, task, &strategy) {
248                    Ok(elf_result) => {
249                        // Set the name from argv[0] or use default
250                        *task.name.write() = argv
251                            .get(0)
252                            .map_or("Unnamed Task".to_string(), |s| s.to_string());
253
254                        // Clear old page table entries
255                        let root_page_table =
256                            vm::get_root_pagetable(task.vm_manager.get_asid()).unwrap();
257                        root_page_table.unmap_all();
258
259                        // Setup the new memory environment
260                        vm::setup_trampoline_for_user(&task.vm_manager);
261                        let stack_pointer = setup_user_stack(task).1;
262
263                        // Handle different execution modes
264                        match elf_result.mode {
265                            ExecutionMode::Static => {
266                                // Static linking - direct execution
267                                task.set_entry_point(elf_result.entry_point as usize);
268                            }
269                            ExecutionMode::Dynamic {
270                                ref interpreter_path,
271                            } => {
272                                // Dynamic linking - setup auxiliary vector and jump to interpreter
273                                crate::println!(
274                                    "Scarlet ABI: Using dynamic linker at {}",
275                                    interpreter_path
276                                );
277
278                                // Build auxiliary vector for dynamic linking
279                                let auxv = build_auxiliary_vector(&elf_result);
280
281                                // Setup auxiliary vector on stack
282                                match setup_auxiliary_vector_on_stack(task, &auxv) {
283                                    Ok(_auxv_addr) => {
284                                        crate::println!(
285                                            "Scarlet ABI: Auxiliary vector setup complete"
286                                        );
287                                    }
288                                    Err(e) => {
289                                        crate::println!(
290                                            "Scarlet ABI: Failed to setup auxiliary vector: {}",
291                                            e.message
292                                        );
293                                        return Err("Failed to setup auxiliary vector");
294                                    }
295                                }
296
297                                task.set_entry_point(elf_result.entry_point as usize);
298                            }
299                        }
300
301                        // Reset task's registers for clean start
302                        task.vcpu.lock().reset_iregs();
303                        task.vcpu.lock().set_sp(stack_pointer);
304
305                        // Setup argv/envp on stack following Unix and RISC-V conventions
306                        let (adjusted_sp, argv_ptr) =
307                            self.setup_arguments_on_stack(task, argv, envp, stack_pointer)?;
308                        task.vcpu.lock().set_sp(adjusted_sp);
309
310                        // Set RISC-V calling convention registers
311                        // a0 (reg[10]) = argc
312                        // a1 (reg[11]) = argv pointer
313                        task.vcpu.lock().iregs.reg[10] = argv.len(); // argc
314                        task.vcpu.lock().iregs.reg[11] = argv_ptr; // argv array pointer
315
316                        // Switch to the new task
317                        task.vcpu.lock().switch(trapframe);
318                        Ok(())
319                    }
320                    Err(e) => {
321                        // Log error details
322                        crate::println!("ELF loading failed: {}", e.message);
323                        Err("Failed to load ELF binary")
324                    }
325                }
326            }
327            None => Err("Invalid file object type for binary execution"),
328        }
329    }
330
331    fn choose_load_address(
332        &self,
333        elf_type: u16,
334        target: crate::task::elf_loader::LoadTarget,
335    ) -> Option<u64> {
336        use crate::task::elf_loader::{ET_DYN, LoadTarget};
337
338        // Scarlet Native ABI uses standard Linux-style memory layout
339        if elf_type == ET_DYN {
340            match target {
341                LoadTarget::MainProgram => {
342                    // PIE main program: low memory area, avoiding null pointer region
343                    Some(0x10000) // 64KB base
344                }
345                LoadTarget::Interpreter => {
346                    // Dynamic linker: high memory area to avoid conflicts with main program
347                    Some(0x40000000) // 1GB base
348                }
349                LoadTarget::SharedLib => {
350                    // Shared libraries: medium memory area
351                    Some(0x50000000) // 1.25GB base
352                }
353            }
354        } else {
355            None // Use kernel default for ET_EXEC and other types
356        }
357    }
358
359    fn normalize_env_to_scarlet(&self, envp: &mut Vec<String>) {
360        // Scarlet ABI is already in canonical format, but ensure all paths are absolute
361        // Modify in-place to avoid allocations
362
363        for env_var in envp.iter_mut() {
364            if let Some(eq_pos) = env_var.find('=') {
365                let key = &env_var[..eq_pos];
366                let value = &env_var[eq_pos + 1..];
367
368                let normalized_value = match key {
369                    "PATH" | "LD_LIBRARY_PATH" => {
370                        // Ensure all paths are in absolute Scarlet namespace format
371                        self.normalize_path_to_absolute_scarlet(value)
372                    }
373                    "HOME" => {
374                        // Ensure home directory is absolute
375                        if value.starts_with('/') {
376                            value.to_string()
377                        } else {
378                            format!("/home/{}", value)
379                        }
380                    }
381                    _ => value.to_string(), // Most variables pass through unchanged
382                };
383
384                // Update in-place if value changed
385                let new_env_var = format!("{}={}", key, normalized_value);
386                if new_env_var != *env_var {
387                    *env_var = new_env_var;
388                }
389            }
390        }
391    }
392
393    fn denormalize_env_from_scarlet(&self, envp: &mut Vec<String>) {
394        // For Scarlet ABI, canonical format is the native format
395        // But ensure proper Scarlet-specific defaults exist
396
397        // Convert to temporary map for easier processing
398        let mut env_map = BTreeMap::new();
399        for env_var in envp.iter() {
400            if let Some(eq_pos) = env_var.find('=') {
401                let key = env_var[..eq_pos].to_string();
402                let value = env_var[eq_pos + 1..].to_string();
403                env_map.insert(key, value);
404            }
405        }
406
407        // Add defaults if they don't exist
408        if !env_map.contains_key("PATH") {
409            env_map.insert(
410                "PATH".to_string(),
411                "/system/scarlet/bin:/bin:/usr/bin".to_string(),
412            );
413        }
414
415        if !env_map.contains_key("SHELL") {
416            env_map.insert("SHELL".to_string(), "/system/scarlet/bin/sh".to_string());
417        }
418
419        // Convert back to Vec<String> format
420        envp.clear();
421        for (key, value) in env_map.iter() {
422            envp.push(format!("{}={}", key, value));
423        }
424    }
425
426    fn setup_overlay_environment(
427        &self,
428        target_vfs: &Arc<VfsManager>,
429        base_vfs: &Arc<VfsManager>,
430        system_path: &str,
431        config_path: &str,
432    ) -> Result<(), &'static str> {
433        // Scarlet ABI uses overlay mount with system Scarlet tools and config persistence
434        let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
435        let upper_vfs = base_vfs;
436        let fs = match OverlayFS::new_from_paths_and_vfs(
437            Some((upper_vfs, config_path)),
438            lower_vfs_list,
439            "/",
440        ) {
441            Ok(fs) => fs,
442            Err(e) => {
443                crate::println!(
444                    "Failed to create overlay filesystem for Scarlet ABI: {}",
445                    e.message
446                );
447                return Err("Failed to create Scarlet overlay environment");
448            }
449        };
450
451        match target_vfs.mount(fs, "/", 0) {
452            Ok(()) => Ok(()),
453            Err(e) => {
454                crate::println!(
455                    "Failed to create cross-VFS overlay for Scarlet ABI: {}",
456                    e.message
457                );
458                Err("Failed to create Scarlet overlay environment")
459            }
460        }
461    }
462
463    fn setup_shared_resources(
464        &self,
465        target_vfs: &Arc<VfsManager>,
466        base_vfs: &Arc<VfsManager>,
467    ) -> Result<(), &'static str> {
468        // Scarlet shared resource setup: bind mount common directories and Scarlet gateway
469        match create_dir_if_not_exists(target_vfs, "/home") {
470            Ok(()) => {}
471            Err(e) => {
472                crate::println!(
473                    "Failed to create /home directory for Scarlet: {}",
474                    e.message
475                );
476                return Err("Failed to create /home directory for Scarlet");
477            }
478        }
479
480        match target_vfs.bind_mount_from(base_vfs, "/home", "/home") {
481            Ok(()) => {}
482            Err(_e) => {}
483        }
484
485        match create_dir_if_not_exists(target_vfs, "/data") {
486            Ok(()) => {}
487            Err(e) => {
488                crate::println!(
489                    "Failed to create /data directory for Scarlet: {}",
490                    e.message
491                );
492                return Err("Failed to create /data directory for Scarlet");
493            }
494        }
495
496        match target_vfs.bind_mount_from(base_vfs, "/data/shared", "/data/shared") {
497            Ok(()) => {}
498            Err(_e) => {}
499        }
500
501        // Bind mount /dev for device access
502        match create_dir_if_not_exists(target_vfs, "/dev") {
503            Ok(()) => {}
504            Err(e) => {
505                crate::println!("Failed to create /dev directory for Scarlet: {}", e.message);
506                return Err("Failed to create /dev directory for Scarlet");
507            }
508        }
509        match target_vfs.bind_mount_from(base_vfs, "/dev", "/dev") {
510            Ok(()) => {}
511            Err(e) => {
512                crate::println!("Failed to bind mount /dev for Scarlet: {}", e.message);
513                return Err("Failed to bind mount /dev for Scarlet");
514            }
515        }
516
517        // Bind moutt /tmp for temporary files
518        match create_dir_if_not_exists(target_vfs, "/tmp") {
519            Ok(()) => {}
520            Err(e) => {
521                crate::println!("Failed to create /tmp directory for Scarlet: {}", e.message);
522                return Err("Failed to create /tmp directory for Scarlet");
523            }
524        }
525        match target_vfs.bind_mount_from(base_vfs, "/tmp", "/tmp") {
526            Ok(()) => {}
527            Err(e) => {
528                crate::println!("Failed to bind mount /tmp for Scarlet: {}", e.message);
529                return Err("Failed to bind mount /tmp for Scarlet");
530            }
531        }
532
533        // Setup gateway to native Scarlet environment (read-only for security)
534        match create_dir_if_not_exists(target_vfs, "/scarlet") {
535            Ok(()) => {}
536            Err(e) => {
537                crate::println!(
538                    "Failed to create /scarlet directory for Scarlet: {}",
539                    e.message
540                );
541                return Err("Failed to create /scarlet directory for Scarlet");
542            }
543        }
544        match target_vfs.bind_mount_from(base_vfs, "/", "/scarlet") {
545            Ok(()) => Ok(()),
546            Err(e) => {
547                crate::println!(
548                    "Failed to bind mount native Scarlet root to /scarlet for Scarlet: {}",
549                    e.message
550                );
551                return Err("Failed to bind mount native Scarlet root to /scarlet for Scarlet");
552            }
553        }
554    }
555
556    fn on_task_exit(&mut self, task: &crate::task::Task) {
557        // Delegate to the implementation method
558        self.on_task_exit(task);
559    }
560
561    fn set_tls_pointer(&mut self, ptr: usize) {
562        self.tls_pointer = Some(ptr);
563    }
564
565    fn get_tls_pointer(&self) -> Option<usize> {
566        self.tls_pointer
567    }
568
569    fn set_clear_child_tid(&mut self, ptr: usize) {
570        self.clear_child_tid_ptr = Some(ptr);
571    }
572}
573
574impl ScarletAbi {
575    /// Setup argc, argv, and envp on the user stack following Unix conventions
576    ///
577    /// Standard Unix stack layout (from high to low addresses):
578    /// ```
579    /// [high addresses]
580    /// envp strings (null-terminated)
581    /// argv strings (null-terminated)
582    /// envp[] array (null-terminated pointer array)
583    /// argv[] array (null-terminated pointer array)
584    /// argc (integer)
585    /// [low addresses - returned stack pointer]
586    /// ```
587    ///
588    /// # Arguments
589    /// * `task` - The task to set up arguments for
590    /// * `argv` - Command line arguments
591    /// * `envp` - Environment variables
592    /// * `initial_sp` - Initial stack pointer from setup_user_stack
593    ///
594    /// # Returns
595    /// Tuple of (new stack pointer, argv array pointer)
596    fn setup_arguments_on_stack(
597        &self,
598        task: &crate::task::Task,
599        argv: &[&str],
600        envp: &[&str],
601        initial_sp: usize,
602    ) -> Result<(usize, usize), &'static str> {
603        // Calculate total size needed
604        let argc = argv.len();
605        let envc = envp.len();
606
607        // Calculate string sizes (including null terminators)
608        let argv_strings_size: usize = argv.iter().map(|s| s.len() + 1).sum();
609        let envp_strings_size: usize = envp.iter().map(|s| s.len() + 1).sum();
610
611        // Calculate pointer array sizes (including null terminators)
612        let argv_array_size = (argc + 1) * core::mem::size_of::<usize>(); // +1 for NULL terminator
613        let envp_array_size = (envc + 1) * core::mem::size_of::<usize>(); // +1 for NULL terminator
614        let argc_size = core::mem::size_of::<usize>();
615
616        // Total space needed
617        let total_size =
618            argc_size + argv_array_size + envp_array_size + argv_strings_size + envp_strings_size;
619
620        // Align to 16-byte boundary for ABI compliance
621        let aligned_total_size = (total_size + 15) & !15;
622
623        // Calculate new stack pointer
624        let new_sp = initial_sp - aligned_total_size;
625
626        // Layout from new_sp (low) to initial_sp (high):
627        // argc | argv[] | envp[] | argv_strings | envp_strings
628
629        let mut current_addr = new_sp;
630
631        // 1. Write argc
632        self.write_to_stack_memory(task, current_addr, &argc.to_le_bytes())?;
633        current_addr += argc_size;
634
635        // 2. Save argv array pointer for return value
636        let argv_ptr = current_addr;
637
638        // 3. Calculate string positions first
639        let argv_strings_start = current_addr + argv_array_size + envp_array_size;
640        let envp_strings_start = argv_strings_start + argv_strings_size;
641
642        // 4. Write argv[] array
643        let mut string_addr = argv_strings_start;
644        for i in 0..argc {
645            self.write_to_stack_memory(task, current_addr, &string_addr.to_le_bytes())?;
646            current_addr += core::mem::size_of::<usize>();
647            string_addr += argv[i].len() + 1; // Move to next string position
648        }
649        // NULL terminate argv[]
650        let null_ptr: usize = 0;
651        self.write_to_stack_memory(task, current_addr, &null_ptr.to_le_bytes())?;
652        current_addr += core::mem::size_of::<usize>();
653
654        // 5. Write envp[] array
655        string_addr = envp_strings_start;
656        for i in 0..envc {
657            self.write_to_stack_memory(task, current_addr, &string_addr.to_le_bytes())?;
658            current_addr += core::mem::size_of::<usize>();
659            string_addr += envp[i].len() + 1; // Move to next string position
660        }
661        // NULL terminate envp[]
662        self.write_to_stack_memory(task, current_addr, &null_ptr.to_le_bytes())?;
663        current_addr += core::mem::size_of::<usize>();
664
665        // 6. Write argv strings
666        for arg in argv {
667            self.write_string_to_stack(task, current_addr, arg)?;
668            current_addr += arg.len() + 1; // +1 for null terminator
669        }
670
671        // 7. Write envp strings
672        for env in envp {
673            self.write_string_to_stack(task, current_addr, env)?;
674            current_addr += env.len() + 1; // +1 for null terminator
675        }
676
677        Ok((new_sp, argv_ptr))
678    }
679
680    /// Write bytes to stack memory using virtual memory translation
681    fn write_to_stack_memory(
682        &self,
683        task: &crate::task::Task,
684        vaddr: usize,
685        data: &[u8],
686    ) -> Result<(), &'static str> {
687        match task.vm_manager.translate_vaddr(vaddr) {
688            Some(paddr) => {
689                unsafe {
690                    core::ptr::copy_nonoverlapping(data.as_ptr(), paddr as *mut u8, data.len());
691                }
692                Ok(())
693            }
694            None => Err("Failed to translate virtual address for stack write"),
695        }
696    }
697
698    /// Write a null-terminated string to stack memory
699    fn write_string_to_stack(
700        &self,
701        task: &crate::task::Task,
702        vaddr: usize,
703        string: &str,
704    ) -> Result<(), &'static str> {
705        // Write the string content
706        self.write_to_stack_memory(task, vaddr, string.as_bytes())?;
707        // Write null terminator
708        self.write_to_stack_memory(task, vaddr + string.len(), &[0u8])?;
709        Ok(())
710    }
711
712    /// Normalize path string to absolute Scarlet namespace format
713    ///
714    /// This ensures all paths in PATH-like variables are absolute and
715    /// in the proper Scarlet namespace format.
716    fn normalize_path_to_absolute_scarlet(&self, path_value: &str) -> String {
717        let paths: Vec<&str> = path_value.split(':').collect();
718        let mut normalized_paths = Vec::new();
719
720        for path in paths {
721            if path.starts_with('/') {
722                // Already absolute - ensure it's in proper Scarlet namespace
723                if path.starts_with("/system/scarlet/") || path.starts_with("/scarlet/") {
724                    normalized_paths.push(path.to_string());
725                } else {
726                    // Map standard paths to Scarlet namespace
727                    let mapped_path = match path {
728                        "/bin" => "/system/scarlet/bin",
729                        "/usr/bin" => "/system/scarlet/usr/bin",
730                        "/usr/local/bin" => "/system/scarlet/usr/local/bin",
731                        "/sbin" => "/system/scarlet/sbin",
732                        "/usr/sbin" => "/system/scarlet/usr/sbin",
733                        "/lib" => "/system/scarlet/lib",
734                        "/usr/lib" => "/system/scarlet/usr/lib",
735                        "/usr/local/lib" => "/system/scarlet/usr/local/lib",
736                        _ => path, // Keep other absolute paths as-is
737                    };
738                    normalized_paths.push(mapped_path.to_string());
739                }
740            } else if !path.is_empty() {
741                // Relative paths - prefix with current working directory or make absolute
742                normalized_paths.push(format!("/{}", path));
743            }
744            // Skip empty paths
745        }
746
747        normalized_paths.join(":")
748    }
749}
750
751fn create_dir_if_not_exists(vfs: &Arc<VfsManager>, path: &str) -> Result<(), FileSystemError> {
752    match vfs.create_dir(path) {
753        Ok(()) => Ok(()),
754        Err(e) => {
755            if e.kind == FileSystemErrorKind::AlreadyExists {
756                Ok(()) // Directory already exists, nothing to do
757            } else {
758                Err(e) // Some other error occurred
759            }
760        }
761    }
762}
763
764fn register_scarlet_abi() {
765    register_abi!(ScarletAbi);
766}
767
768early_initcall!(register_scarlet_abi);