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}