kernel/abi/
mod.rs

1//! ABI module.
2//!
3//! This module provides the interface for ABI (Application Binary Interface) modules
4//! in the Scarlet kernel. ABI modules are responsible for handling system calls
5//! and providing the necessary functionality for different application binary
6//! interfaces.
7//!
8
9use crate::{
10    arch::Trapframe,
11    fs::VfsManager,
12    task::{CloneFlags, mytask},
13};
14use alloc::{
15    boxed::Box,
16    string::{String, ToString},
17    sync::Arc,
18    vec::Vec,
19};
20use hashbrown::HashMap;
21use spin::Mutex;
22
23pub mod linux;
24pub mod scarlet;
25pub mod xv6;
26
27pub const MAX_ABI_LENGTH: usize = 64;
28
29/// Runtime configuration for delegating binary execution to userland
30///
31/// This structure defines how a binary format should be executed via
32/// a userland runtime instead of being loaded directly by the kernel.
33///
34/// # Examples
35/// - MS-DOS binaries executed via DOSBox (Linux ABI)
36/// - Wasm binaries executed via a Scarlet-native Wasm runtime
37/// - Java bytecode executed via a JVM
38#[derive(Debug, Clone)]
39pub struct RuntimeConfig {
40    /// Path to the runtime executable in the VFS
41    pub runtime_path: String,
42
43    /// ABI that the runtime itself uses
44    /// If None, runtime's ABI will be auto-detected
45    pub runtime_abi: Option<String>,
46
47    /// Additional arguments to pass to the runtime before the target binary
48    /// Example: ["--emulate", "dos"] for DOSBox
49    pub runtime_args: Vec<String>,
50}
51
52/// ABI module trait.
53///
54/// This trait defines the interface for ABI modules in the Scarlet kernel.
55/// ABI modules are responsible for handling system calls and providing
56/// the necessary functionality for different application binary interfaces.
57///
58/// Each ABI module must implement Clone to support task cloning with
59/// independent ABI state per task.
60///
61pub trait AbiModule: Send + Sync + 'static {
62    fn name() -> &'static str
63    where
64        Self: Sized;
65
66    fn get_name(&self) -> String;
67
68    /// Clone this ABI module into a boxed trait object
69    ///
70    /// This method enables cloning ABI modules as trait objects,
71    /// allowing each task to have its own independent ABI instance.
72    fn clone_boxed(&self) -> Box<dyn AbiModule + Send + Sync>;
73
74    fn handle_syscall(&mut self, trapframe: &mut Trapframe) -> Result<usize, &'static str>;
75
76    /// Hook invoked after Task::clone_task creates the child
77    fn on_task_cloned(
78        &mut self,
79        _parent_task: &crate::task::Task,
80        _child_task: &crate::task::Task,
81        _flags: CloneFlags,
82    ) -> Result<(), &'static str> {
83        Ok(())
84    }
85
86    /// Hook invoked as part of Task::exit cleanup for the current task
87    ///
88    /// ABI modules can perform per-ABI teardown such as waking futex waiters,
89    /// clearing TLS/robust-list pointers, or delivering exit-related signals.
90    fn on_task_exit(&mut self, _task: &crate::task::Task) {}
91
92    /// Get the task namespace for this ABI.
93    ///
94    /// This allows each ABI to have its own namespace for task IDs.
95    /// By default, returns the root namespace.
96    ///
97    /// # Returns
98    /// The task namespace for this ABI
99    fn get_task_namespace(&self) -> Arc<crate::task::namespace::TaskNamespace> {
100        crate::task::namespace::get_root_namespace().clone()
101    }
102
103    /// Determine if a binary can be executed by this ABI and return confidence
104    ///
105    /// This method reads binary content directly from the file object and
106    /// executes ABI-specific detection logic (magic bytes, header structure,
107    /// entry point validation, etc.).
108    ///
109    /// # Arguments
110    /// * `file_object` - Binary file to check (in KernelObject format)
111    /// * `file_path` - File path (for auxiliary detection like file extensions)
112    /// * `current_abi` - Current task's ABI reference for inheritance/compatibility decisions
113    ///
114    /// # Returns
115    /// * `Some(confidence)` - Confidence level (0-100) if executable by this ABI
116    /// * `None` - Not executable by this ABI
117    ///
118    /// # Implementation Guidelines
119    /// - Use file_object.as_file() to access FileObject
120    /// - Use StreamOps::read() to directly read file content
121    /// - Check ABI-specific magic bytes and header structures
122    /// - Validate entry point and architecture compatibility
123    /// - Consider current_abi for inheritance/compatibility bonus (same ABI = higher confidence)
124    /// - Return confidence based on how well the binary matches this ABI
125    /// - No need for artificial score limitations - let each ABI decide its own confidence
126    ///
127    /// # Recommended Scoring Guidelines
128    /// - 0-30: Basic compatibility (correct magic bytes, architecture)
129    /// - 31-60: Good match (+ file extension, path hints, valid entry point)
130    /// - 61-80: Strong match (+ ABI-specific headers, symbols, sections)
131    /// - 81-100: Perfect match (+ same ABI inheritance, full validation)
132    ///
133    /// # Example Scoring Strategy
134    /// ```rust
135    /// let mut confidence = 0;
136    ///
137    /// // Basic format check
138    /// if self.is_valid_format(file_object) { confidence += 30; }
139    ///
140    /// // Entry point validation
141    /// if self.is_valid_entry_point(file_object) { confidence += 15; }
142    ///
143    /// // File path hints
144    /// if file_path.contains(self.get_name()) { confidence += 15; }
145    ///
146    /// // ABI inheritance bonus
147    /// if let Some(abi) = current_abi {
148    ///     if abi.get_name() == self.get_name() { confidence += 40; }
149    /// }
150    ///
151    /// Some(confidence.min(100))
152    /// ```
153    fn can_execute_binary(
154        &self,
155        _file_object: &crate::object::KernelObject,
156        _file_path: &str,
157        _current_abi: Option<&(dyn AbiModule + Send + Sync)>,
158    ) -> Option<u8> {
159        // Default implementation: cannot determine
160        None
161    }
162
163    /// Handle conversion when switching ABIs
164    fn initialize_from_existing_handles(
165        &mut self,
166        _task: &crate::task::Task,
167    ) -> Result<(), &'static str> {
168        Ok(()) // Default: no conversion needed
169    }
170
171    /// Convert environment variables from this ABI to Scarlet canonical format (in-place)
172    ///
173    /// This method is called when switching from this ABI to another ABI.
174    /// It should convert ABI-specific environment variables to a canonical
175    /// Scarlet format that can then be converted to the target ABI.
176    ///
177    /// Uses in-place modification to avoid expensive allocations.
178    ///
179    /// # Arguments
180    /// * `envp` - Mutable reference to environment variables in "KEY=VALUE" format,
181    ///            will be modified to contain Scarlet canonical format
182    ///
183    /// # Implementation Guidelines
184    /// - Convert paths to absolute Scarlet namespace paths
185    /// - Normalize variable names to Scarlet conventions
186    /// - Remove ABI-specific variables that don't translate
187    /// - Ensure all paths are absolute and start with /
188    /// - Modify the vector in-place for efficiency
189    fn normalize_env_to_scarlet(&self, _envp: &mut Vec<String>) {
190        // Default: no conversion needed (assuming already in Scarlet format)
191    }
192
193    /// Convert environment variables from Scarlet canonical format to this ABI's format (in-place)
194    ///
195    /// This method is called when switching to this ABI from another ABI.
196    /// It should convert canonical Scarlet environment variables to this ABI's
197    /// specific format and namespace.
198    ///
199    /// Uses in-place modification to avoid expensive allocations.
200    ///
201    /// # Arguments
202    /// * `envp` - Mutable reference to environment variables in Scarlet canonical format,
203    ///            will be modified to contain this ABI's format
204    fn denormalize_env_from_scarlet(&self, _envp: &mut Vec<String>) {
205        // Default: no conversion needed (assuming target is Scarlet format)
206    }
207
208    /// Binary execution (each ABI supports its own binary format)
209    ///
210    /// This method actually executes a binary that has already been verified
211    /// by can_execute_binary. Use file_object.as_file() to access FileObject,
212    /// and call ABI-specific loaders (ELF, PE, etc.) to load and execute the binary.
213    ///
214    /// Environment variables are passed directly as envp array, not stored in task.
215    ///
216    /// # Arguments
217    /// * `file_object` - Binary file to execute (already opened, in KernelObject format)
218    /// * `argv` - Command line arguments
219    /// * `envp` - Environment variables in "KEY=VALUE" format
220    /// * `task` - Target task (modified by this method)
221    /// * `trapframe` - Execution context (modified by this method)
222    ///
223    /// # Implementation Notes
224    /// - Use file_object.as_file() to get FileObject
225    /// - Use ABI-specific loaders (e.g., task::elf_loader)
226    /// - Environment variables are passed directly as envp parameter
227    /// - Set task's memory space, registers, and entry point
228    /// - Update trapframe registers (PC, SP) for the new process
229    /// - Recommended to restore original state on execution failure
230    ///
231    /// # Return Value Handling in Syscall Context
232    /// The Scarlet syscall mechanism works as follows:
233    /// 1. sys_execve() calls this method
234    /// 2. sys_execve() returns usize to syscall_handler()
235    /// 3. syscall_handler() returns Ok(usize) to syscall_dispatcher()
236    /// 4. syscall_dispatcher() returns Ok(usize) to trap handler
237    /// 5. Trap handler calls trapframe.set_return_value(usize) automatically
238    fn execute_binary(
239        &self,
240        file_object: &crate::object::KernelObject,
241        argv: &[&str],
242        envp: &[&str],
243        task: &crate::task::Task,
244        trapframe: &mut Trapframe,
245    ) -> Result<(), &'static str>;
246
247    /// Choose base address for ELF loading (ABI-specific strategy)
248    ///
249    /// This method allows each ABI to define its own memory layout preferences
250    /// for different types of ELF objects. The ELF loader will use these
251    /// addresses when loading binaries for this ABI.
252    ///
253    /// # Arguments
254    /// * `elf_type` - ELF file type (ET_EXEC, ET_DYN, etc.)
255    /// * `target` - Target component being loaded
256    ///
257    /// # Returns
258    /// Base address where the component should be loaded, or None to use
259    /// kernel default strategy
260    fn choose_load_address(
261        &self,
262        _elf_type: u16,
263        _target: crate::task::elf_loader::LoadTarget,
264    ) -> Option<u64> {
265        None // Default: use kernel default strategy
266    }
267
268    /// Override interpreter path (for ABI compatibility)
269    ///
270    /// This method allows each ABI to specify which dynamic linker should
271    /// be used when a binary requires dynamic linking (has PT_INTERP).
272    ///
273    /// # Arguments
274    /// * `requested_interpreter` - Interpreter path from PT_INTERP segment
275    ///
276    /// # Returns
277    /// The interpreter path to actually use (may be different from requested)
278    fn get_interpreter_path(&self, requested_interpreter: &str) -> String {
279        requested_interpreter.to_string() // Default: use requested interpreter as-is
280    }
281
282    /// Get userland runtime configuration for executing binaries
283    ///
284    /// This method allows ABI modules to delegate binary execution to userland runtimes.
285    /// When a runtime is configured, the binary will be executed via the runtime instead
286    /// of being loaded directly by the kernel.
287    ///
288    /// # Arguments
289    /// * `file_object` - Binary file to check
290    /// * `file_path` - File path for format detection
291    ///
292    /// # Returns
293    /// * `Some(RuntimeConfig)` - Runtime configuration if delegation is needed
294    /// * `None` - No runtime delegation, execute directly
295    ///
296    /// # Example Use Cases
297    /// - MS-DOS binaries via DOSBox (Linux ABI runtime)
298    /// - Wasm binaries via Scarlet-native Wasm runtime
299    /// - Java bytecode via JVM
300    /// - Cross-architecture binaries via QEMU user-mode
301    fn get_runtime_config(
302        &self,
303        _file_object: &crate::object::KernelObject,
304        _file_path: &str,
305    ) -> Option<RuntimeConfig> {
306        None // Default: no runtime delegation
307    }
308
309    /// Get default working directory for this ABI
310    fn get_default_cwd(&self) -> &str {
311        "/" // Default: root directory
312    }
313
314    /// Setup overlay environment for this ABI (read-only base + writable layer)
315    ///
316    /// Creates overlay filesystem with provided base VFS and paths.
317    /// The TransparentExecutor is responsible for providing base_vfs, paths,
318    /// and verifying that directories exist. This method assumes that required
319    /// directories (/system/{abi}, /data/config/{abi}) have been prepared
320    /// by the user/administrator as part of system setup.
321    ///
322    /// # Arguments
323    /// * `target_vfs` - VfsManager to configure with overlay filesystem
324    /// * `base_vfs` - Base VFS containing system and config directories
325    /// * `system_path` - Path to read-only base layer (e.g., "/system/scarlet")
326    /// * `config_path` - Path to writable persistence layer (e.g., "/data/config/scarlet")
327    fn setup_overlay_environment(
328        &self,
329        _target_vfs: &Arc<VfsManager>,
330        _base_vfs: &Arc<VfsManager>,
331        _system_path: &str,
332        _config_path: &str,
333    ) -> Result<(), &'static str> {
334        // cross-vfs overlay_mount_from is not supported in v2, commented out for now
335        // let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
336        // target_vfs.overlay_mount_from(
337        //     Some(base_vfs),             // upper_vfs (base VFS)
338        //     config_path,                // upperdir (read-write persistent layer)
339        //     lower_vfs_list,             // lowerdir (read-only base system)
340        //     "/"                         // target mount point in task VFS
341        // ).map_err(|e| {
342        //     crate::println!("Failed to create cross-VFS overlay for ABI: {}", e.message);
343        //     "Failed to create overlay environment"
344        // })
345        Err("overlay_mount_from (cross-vfs) is not supported in v2")
346    }
347
348    /// Setup shared resources accessible across all ABIs
349    ///
350    /// Bind mounts common directories that should be shared from base VFS.
351    /// The TransparentExecutor is responsible for providing base_vfs.
352    ///
353    /// # Arguments
354    /// * `target_vfs` - VfsManager to configure
355    /// * `base_vfs` - Base VFS containing shared directories
356    fn setup_shared_resources(
357        &self,
358        _target_vfs: &Arc<VfsManager>,
359        _base_vfs: &Arc<VfsManager>,
360    ) -> Result<(), &'static str> {
361        // TODO: VFS v2 migration - update bind_mount_from API usage
362        // Current limitation: function signature uses VFS v1 types
363        // Bind mount shared directories from base VFS
364        // target_vfs.bind_mount_from(&base_vfs, "/home", "/home")
365        //     .map_err(|_| "Failed to bind mount /home")?;
366        // target_vfs.bind_mount_from(&base_vfs, "/data/shared", "/data/shared")
367        //     .map_err(|_| "Failed to bind mount /data/shared")?;
368        // target_vfs.bind_mount_from(&base_vfs, "/", "/scarlet") // Read-only is not supported
369        //     .map_err(|_| "Failed to bind mount native Scarlet root to /scarlet")
370        Ok(())
371    }
372
373    /// Handle incoming event from EventManager
374    ///
375    /// This method is called when an event is delivered to a task using this ABI.
376    /// Each ABI can implement its own event handling strategy:
377    /// - Scarlet ABI: Handle-based queuing with EventSubscription objects
378    /// - xv6 ABI: POSIX-like signals and pipe notifications
379    /// - Other ABIs: Custom event processing mechanisms
380    ///
381    /// # Arguments
382    /// * `event` - The event to be delivered
383    /// * `target_task_id` - ID of the task that should receive the event
384    ///
385    /// # Returns
386    /// * `Ok(())` if the event was successfully handled
387    /// * `Err(message)` if event delivery failed
388    fn handle_event(
389        &self,
390        _event: crate::ipc::Event,
391        _target_task_id: u32,
392    ) -> Result<(), &'static str> {
393        // Default implementation: ignore events
394        Ok(())
395    }
396
397    /// Set the TLS (Thread Local Storage) pointer for this task
398    ///
399    /// Default implementation does nothing - ABIs that support TLS
400    /// should override this method.
401    fn set_tls_pointer(&mut self, _ptr: usize) {
402        // Default: do nothing
403    }
404
405    /// Get the TLS (Thread Local Storage) pointer for this task
406    ///
407    /// Default implementation returns None - ABIs that support TLS
408    /// should override this method.
409    fn get_tls_pointer(&self) -> Option<usize> {
410        None
411    }
412
413    /// Set the clear_child_tid pointer for thread exit notification
414    ///
415    /// Default implementation does nothing - ABIs that support TLS
416    /// should override this method.
417    fn set_clear_child_tid(&mut self, _ptr: usize) {
418        // Default: do nothing
419    }
420}
421
422/// ABI registry.
423///
424/// This struct is responsible for managing the registration and instantiation
425/// of ABI modules in the Scarlet kernel.
426///
427pub struct AbiRegistry {
428    factories: HashMap<String, fn() -> Box<dyn AbiModule + Send + Sync>>,
429}
430
431impl AbiRegistry {
432    fn new() -> Self {
433        Self {
434            factories: HashMap::new(),
435        }
436    }
437
438    pub fn global() -> &'static Mutex<AbiRegistry> {
439        // Thread-safe lazy initialization using spin::Once
440        static INSTANCE: spin::Once<Mutex<AbiRegistry>> = spin::Once::new();
441
442        INSTANCE.call_once(|| Mutex::new(AbiRegistry::new()))
443    }
444
445    pub fn register<T>()
446    where
447        T: AbiModule + Default + 'static,
448    {
449        crate::early_println!("Registering ABI module: {}", T::name());
450        let mut registry = Self::global().lock();
451        registry
452            .factories
453            .insert(T::name().to_string(), || Box::new(T::default()));
454    }
455
456    pub fn instantiate(name: &str) -> Option<Box<dyn AbiModule + Send + Sync>> {
457        let registry = Self::global().lock();
458        if let Some(factory) = registry.factories.get(name) {
459            let abi = factory();
460            return Some(abi);
461        }
462        None
463    }
464
465    /// Detect the best ABI for a binary from all registered ABI modules
466    ///
467    /// This method tries all registered ABIs and selects the one with the highest
468    /// confidence score. Each ABI internally handles inheritance bonuses and
469    /// compatibility logic based on the current task's ABI.
470    ///
471    /// # Arguments
472    /// * `file_object` - Binary file to check
473    /// * `file_path` - File path
474    ///
475    /// # Returns
476    /// * `Some((abi_name, confidence))` - Best ABI name and confidence level
477    /// * `None` - No executable ABI found
478    pub fn detect_best_abi(
479        file_object: &crate::object::KernelObject,
480        file_path: &str,
481    ) -> Option<(String, u8)> {
482        let registry = Self::global().lock();
483
484        // Get current task's ABI reference for inheritance consideration
485        let _task = mytask();
486
487        // Try all ABI modules and find the one with highest confidence
488        // Each ABI decides its own confidence based on:
489        // - Binary format compatibility
490        // - Architecture compatibility
491        // - Entry point validity
492        // - Inheritance bonus from current ABI
493        if let Some(ref task) = _task {
494            task.with_default_abi(|current_abi| {
495                registry
496                    .factories
497                    .iter()
498                    .filter_map(|(name, factory)| {
499                        let abi = factory();
500                        abi.can_execute_binary(file_object, file_path, Some(current_abi))
501                            .map(|confidence| (name.clone(), confidence))
502                    })
503                    .max_by_key(|(_, confidence)| *confidence)
504            })
505        } else {
506            registry
507                .factories
508                .iter()
509                .filter_map(|(name, factory)| {
510                    let abi = factory();
511                    abi.can_execute_binary(file_object, file_path, None)
512                        .map(|confidence| (name.clone(), confidence))
513                })
514                .max_by_key(|(_, confidence)| *confidence)
515        }
516    }
517}
518
519#[macro_export]
520macro_rules! register_abi {
521    ($ty:ty) => {
522        $crate::abi::AbiRegistry::register::<$ty>();
523    };
524}
525
526pub fn syscall_dispatcher(trapframe: &mut Trapframe) -> Result<usize, &'static str> {
527    // 1. Get the program counter (sepc) from trapframe
528    let pc = trapframe.get_current_pc() as usize;
529
530    // 2. Get mutable reference to current task
531    let task = mytask().unwrap();
532
533    // 3. Resolve the appropriate ABI based on PC address and handle the syscall
534    task.with_resolve_abi_mut(pc, |abi_module| {
535        // 4. Handle the system call with the resolved ABI
536        abi_module.handle_syscall(trapframe)
537    })
538}