⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/userspace/
enhanced_loader.rs

1//! Enhanced ELF Loader for User Space Programs
2//!
3//! Loads ELF binaries from filesystem and executes them in user space.
4
5#![allow(clippy::needless_borrow, clippy::op_ref)]
6
7use alloc::{string::String, vec, vec::Vec};
8
9use crate::{
10    elf::{Elf64Header, Elf64ProgramHeader},
11    error::KernelError,
12    mm::{PageFlags, VirtualAddress},
13    process::{Process, ProcessId},
14};
15
16/// Program arguments
17pub struct ProgramArgs {
18    /// Argument strings
19    pub args: Vec<String>,
20
21    /// Environment variables
22    pub env: Vec<String>,
23}
24
25impl ProgramArgs {
26    /// Create new program arguments
27    pub fn new() -> Self {
28        Self {
29            args: Vec::new(),
30            env: Vec::new(),
31        }
32    }
33
34    /// Add argument
35    pub fn add_arg(&mut self, arg: String) {
36        self.args.push(arg);
37    }
38
39    /// Add environment variable
40    pub fn add_env(&mut self, env: String) {
41        self.env.push(env);
42    }
43}
44
45impl Default for ProgramArgs {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51/// ELF loader for user space programs
52#[allow(dead_code)] // Alternative ELF loader -- fields used in load methods below
53pub struct EnhancedElfLoader {
54    /// ELF file data
55    data: Vec<u8>,
56
57    /// Parsed ELF header
58    header: Option<Elf64Header>,
59
60    /// Program headers
61    program_headers: Vec<Elf64ProgramHeader>,
62
63    /// Parsed entry point
64    parsed_entry_point: u64,
65
66    /// Requires dynamic linking
67    requires_dynamic: bool,
68
69    /// Interpreter path if dynamic
70    interpreter_path: Option<String>,
71}
72
73impl EnhancedElfLoader {
74    /// Create a new ELF loader from file data
75    pub fn new(data: Vec<u8>) -> Result<Self, KernelError> {
76        let mut loader = Self {
77            data,
78            header: None,
79            program_headers: Vec::new(),
80            parsed_entry_point: 0,
81            requires_dynamic: false,
82            interpreter_path: None,
83        };
84
85        loader.parse_header()?;
86        loader.parse_program_headers()?;
87
88        Ok(loader)
89    }
90
91    /// Parse ELF header
92    fn parse_header(&mut self) -> Result<(), KernelError> {
93        if self.data.len() < core::mem::size_of::<Elf64Header>() {
94            return Err(KernelError::InvalidArgument {
95                name: "elf_size",
96                value: "too_small",
97            });
98        }
99
100        // Check magic number (ELF magic: 0x7f, 'E', 'L', 'F')
101        const ELF_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F'];
102        if &self.data[0..4] != &ELF_MAGIC {
103            return Err(KernelError::InvalidArgument {
104                name: "elf_magic",
105                value: "invalid",
106            });
107        }
108
109        // Check class (must be 64-bit)
110        if self.data[4] != 2 {
111            return Err(KernelError::InvalidArgument {
112                name: "elf_class",
113                value: "not_64bit",
114            });
115        }
116
117        // Check data encoding (must be little endian)
118        if self.data[5] != 1 {
119            return Err(KernelError::InvalidArgument {
120                name: "elf_encoding",
121                value: "not_little_endian",
122            });
123        }
124
125        // Parse header using unsafe pointer cast
126        // SAFETY: We verified self.data.len() >= size_of::<Elf64Header>()
127        // above, and checked the ELF magic, class, and encoding fields.
128        // Elf64Header is #[repr(C)] with Copy, so reading via pointer
129        // cast is valid. Alignment is not an issue because we copy
130        // immediately via dereference.
131        let header = unsafe { *(self.data.as_ptr() as *const Elf64Header) };
132
133        // Validate type (must be executable or shared object)
134        if header.elf_type != 2 && header.elf_type != 3 {
135            return Err(KernelError::InvalidArgument {
136                name: "elf_type",
137                value: "not_executable",
138            });
139        }
140
141        // Validate machine type for current architecture
142        let valid_machine = match () {
143            #[cfg(target_arch = "x86_64")]
144            () => header.machine == 62,
145            #[cfg(target_arch = "aarch64")]
146            () => header.machine == 183,
147            #[cfg(target_arch = "riscv64")]
148            () => header.machine == 243,
149        };
150
151        if !valid_machine {
152            return Err(KernelError::InvalidArgument {
153                name: "elf_machine",
154                value: "unsupported_architecture",
155            });
156        }
157
158        // Store the entry point
159        self.parsed_entry_point = header.entry;
160        self.header = Some(header);
161
162        println!(
163            "[ELF-LOADER] ELF header parsed, entry: 0x{:x}",
164            header.entry
165        );
166
167        Ok(())
168    }
169
170    /// Parse program headers
171    fn parse_program_headers(&mut self) -> Result<(), KernelError> {
172        let header = self.header.ok_or(KernelError::InvalidArgument {
173            name: "elf_header",
174            value: "not_parsed",
175        })?;
176
177        let ph_offset = header.phoff as usize;
178        let ph_size = header.phentsize as usize;
179        let ph_count = header.phnum as usize;
180
181        // Validate program header table bounds
182        if ph_offset + (ph_size * ph_count) > self.data.len() {
183            return Err(KernelError::InvalidArgument {
184                name: "program_headers",
185                value: "out_of_bounds",
186            });
187        }
188
189        // Parse each program header
190        for i in 0..ph_count {
191            let offset = ph_offset + (i * ph_size);
192
193            // SAFETY: We verified ph_offset + (ph_size * ph_count) <=
194            // self.data.len() above, so `offset` is within bounds.
195            // Elf64ProgramHeader is #[repr(C)] with Copy. The pointer
196            // is derived from a valid slice.
197            let ph = unsafe { *(self.data[offset..].as_ptr() as *const Elf64ProgramHeader) };
198            self.program_headers.push(ph);
199
200            // Check for dynamic linking requirement (PT_INTERP = 3)
201            if ph.p_type == 3 {
202                self.requires_dynamic = true;
203
204                // Extract interpreter path
205                let interp_offset = ph.p_offset as usize;
206                let interp_size = ph.p_filesz as usize;
207                if interp_offset + interp_size <= self.data.len() {
208                    let interp_data = &self.data[interp_offset..interp_offset + interp_size - 1]; // -1 for null terminator
209                    if let Ok(interp_str) = core::str::from_utf8(interp_data) {
210                        self.interpreter_path = Some(String::from(interp_str));
211                    }
212                }
213            }
214
215            // Check for dynamic section (PT_DYNAMIC = 2)
216            if ph.p_type == 2 {
217                self.requires_dynamic = true;
218            }
219        }
220
221        println!(
222            "[ELF-LOADER] Parsed {} program headers, dynamic: {}",
223            ph_count, self.requires_dynamic
224        );
225
226        Ok(())
227    }
228
229    /// Load program into memory
230    pub fn load(&self, process: &Process) -> Result<VirtualAddress, KernelError> {
231        println!("[ELF-LOADER] Loading ELF program into process");
232
233        let mut memory_space = process.memory_space.lock();
234
235        // Process each LOAD segment (PT_LOAD = 1)
236        for ph in &self.program_headers {
237            if ph.p_type != 1 {
238                continue; // Skip non-LOAD segments
239            }
240
241            // Calculate page-aligned addresses
242            let page_mask = 0xFFF_u64;
243            let page_start = ph.p_vaddr & !page_mask;
244            let page_end = (ph.p_vaddr + ph.p_memsz + page_mask) & !page_mask;
245            let num_pages = ((page_end - page_start) / 0x1000) as usize;
246
247            // Determine page flags based on segment flags
248            // PF_X = 0x1, PF_W = 0x2, PF_R = 0x4
249            let mut flags = PageFlags::USER | PageFlags::PRESENT;
250            if (ph.p_flags & 0x2) != 0 {
251                flags |= PageFlags::WRITABLE;
252            }
253            if (ph.p_flags & 0x1) == 0 {
254                flags |= PageFlags::NO_EXECUTE;
255            }
256
257            // Map pages for this segment
258            for i in 0..num_pages {
259                let addr = page_start + (i as u64 * 0x1000);
260                memory_space.map_page(addr as usize, flags).map_err(|_| {
261                    KernelError::OutOfMemory {
262                        requested: 0x1000,
263                        available: 0,
264                    }
265                })?;
266            }
267
268            // Copy segment data from file
269            if ph.p_filesz > 0 {
270                let src_offset = ph.p_offset as usize;
271                let copy_size = ph.p_filesz as usize;
272
273                if src_offset + copy_size <= self.data.len() {
274                    // SAFETY: src_offset + copy_size is within self.data
275                    // bounds (checked above). dest (p_vaddr) was just mapped
276                    // into the process address space by map_page above. The
277                    // source (ELF file data) and destination (process memory)
278                    // do not overlap since they are in different address
279                    // ranges.
280                    unsafe {
281                        let dest = ph.p_vaddr as *mut u8;
282                        let src = self.data.as_ptr().add(src_offset);
283                        core::ptr::copy_nonoverlapping(src, dest, copy_size);
284                    }
285                }
286            }
287
288            // Zero BSS portion (memory size > file size)
289            if ph.p_memsz > ph.p_filesz {
290                // SAFETY: The BSS region starts at p_vaddr + p_filesz and
291                // extends to p_vaddr + p_memsz. This entire range was
292                // mapped by map_page above (num_pages covers p_memsz).
293                // write_bytes zeroes the uninitialized data section.
294                unsafe {
295                    let bss_start = (ph.p_vaddr + ph.p_filesz) as *mut u8;
296                    let bss_size = (ph.p_memsz - ph.p_filesz) as usize;
297                    core::ptr::write_bytes(bss_start, 0, bss_size);
298                }
299            }
300
301            println!(
302                "[ELF-LOADER] Loaded segment at 0x{:x}, size: {} bytes",
303                ph.p_vaddr, ph.p_memsz
304            );
305        }
306
307        let entry_point = VirtualAddress(self.parsed_entry_point);
308
309        println!(
310            "[ELF-LOADER] Program loaded, entry point: 0x{:x}",
311            entry_point.as_u64()
312        );
313
314        Ok(entry_point)
315    }
316
317    /// Set up program arguments on stack
318    /// Format on stack (growing downward):
319    /// [padding for alignment]
320    /// [env string N]
321    /// ...
322    /// [env string 0]
323    /// [arg string argc-1]
324    /// ...
325    /// [arg string 0]
326    /// [NULL] (envp terminator)
327    /// [envp[N]]
328    /// ...
329    /// [envp[0]]
330    /// [NULL] (argv terminator)
331    /// [argv[argc-1]]
332    /// ...
333    /// [argv[0]]
334    /// [argc]
335    pub fn setup_args(&self, process: &Process, args: &ProgramArgs) -> Result<(), KernelError> {
336        println!(
337            "[ELF-LOADER] Setting up {} arguments and {} env vars",
338            args.args.len(),
339            args.env.len()
340        );
341
342        let mut memory_space = process.memory_space.lock();
343
344        // User stack typically starts at a high address and grows down
345        // Use the process's configured stack pointer
346        let stack_top = 0x7FFF_FFFF_F000_u64; // Top of user stack (below kernel)
347        let stack_size = 0x10000_u64; // 64KB stack
348
349        // Map stack pages
350        let flags =
351            PageFlags::USER | PageFlags::WRITABLE | PageFlags::NO_EXECUTE | PageFlags::PRESENT;
352        let num_stack_pages = (stack_size / 0x1000) as usize;
353        for i in 0..num_stack_pages {
354            let addr = stack_top - stack_size + (i as u64 * 0x1000);
355            memory_space
356                .map_page(addr as usize, flags)
357                .map_err(|_| KernelError::OutOfMemory {
358                    requested: 0x1000,
359                    available: 0,
360                })?;
361        }
362
363        // Start from top of stack and work down
364        let mut sp = stack_top;
365
366        // First, push all the string data (env vars then args)
367        let mut env_ptrs: Vec<u64> = Vec::with_capacity(args.env.len());
368        let mut arg_ptrs: Vec<u64> = Vec::with_capacity(args.args.len());
369
370        // Push environment strings
371        for env_str in args.env.iter().rev() {
372            let bytes = env_str.as_bytes();
373            sp -= (bytes.len() + 1) as u64; // +1 for null terminator
374                                            // SAFETY: sp points into the user stack region that was mapped
375                                            // above. We write bytes.len() + 1 bytes (string + null terminator).
376                                            // sp was decremented by that exact amount, staying within the
377                                            // mapped stack region (stack_top - stack_size to stack_top).
378            unsafe {
379                let ptr = sp as *mut u8;
380                core::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
381                *ptr.add(bytes.len()) = 0; // Null terminator
382            }
383            env_ptrs.push(sp);
384        }
385        env_ptrs.reverse();
386
387        // Push argument strings
388        for arg_str in args.args.iter().rev() {
389            let bytes = arg_str.as_bytes();
390            sp -= (bytes.len() + 1) as u64;
391            // SAFETY: Same as environment string push - sp is within
392            // the mapped stack region and decremented by the exact
393            // number of bytes written.
394            unsafe {
395                let ptr = sp as *mut u8;
396                core::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
397                *ptr.add(bytes.len()) = 0;
398            }
399            arg_ptrs.push(sp);
400        }
401        arg_ptrs.reverse();
402
403        // Align stack to 16 bytes
404        sp &= !0xF;
405
406        // Push NULL terminator for envp
407        sp -= 8;
408        // SAFETY: sp is 16-byte aligned (aligned above) and within the
409        // mapped stack. Writing a u64 zero as the envp NULL terminator.
410        unsafe {
411            *(sp as *mut u64) = 0;
412        }
413
414        // Push envp pointers
415        for env_ptr in env_ptrs.iter().rev() {
416            sp -= 8;
417            // SAFETY: sp is within the mapped stack and 8-byte aligned
418            // (all writes are 8-byte u64). env_ptr contains a valid
419            // address pointing to a string previously written to the stack.
420            unsafe {
421                *(sp as *mut u64) = *env_ptr;
422            }
423        }
424
425        // Push NULL terminator for argv
426        sp -= 8;
427        // SAFETY: sp is within the mapped stack and 8-byte aligned.
428        // Writing a u64 zero as the argv NULL terminator.
429        unsafe {
430            *(sp as *mut u64) = 0;
431        }
432
433        // Push argv pointers
434        for arg_ptr in arg_ptrs.iter().rev() {
435            sp -= 8;
436            // SAFETY: sp is within the mapped stack and 8-byte aligned.
437            // arg_ptr contains a valid address pointing to an argument
438            // string previously written to the stack.
439            unsafe {
440                *(sp as *mut u64) = *arg_ptr;
441            }
442        }
443
444        // Push argc
445        sp -= 8;
446        // SAFETY: sp is within the mapped stack and 8-byte aligned.
447        // Writing argc as the topmost stack entry for the C ABI.
448        unsafe {
449            *(sp as *mut u64) = args.args.len() as u64;
450        }
451
452        println!(
453            "[ELF-LOADER] Stack setup complete, sp: 0x{:x}, argc: {}",
454            sp,
455            args.args.len()
456        );
457
458        Ok(())
459    }
460
461    /// Get entry point address
462    pub fn entry_point(&self) -> VirtualAddress {
463        VirtualAddress(self.parsed_entry_point)
464    }
465
466    /// Check if binary requires dynamic linking
467    pub fn requires_dynamic_linking(&self) -> bool {
468        self.requires_dynamic
469    }
470
471    /// Get interpreter path if dynamic
472    pub fn interpreter(&self) -> Option<&str> {
473        self.interpreter_path.as_deref()
474    }
475
476    /// Get segment information for a given type
477    pub fn segments(&self) -> &[Elf64ProgramHeader] {
478        &self.program_headers
479    }
480
481    /// Get the raw ELF file data for segment copying.
482    pub fn raw_data(&self) -> &[u8] {
483        &self.data
484    }
485
486    /// Get total memory size needed
487    pub fn memory_size(&self) -> usize {
488        let mut min_addr = u64::MAX;
489        let mut max_addr = 0u64;
490
491        for ph in &self.program_headers {
492            if ph.p_type == 1 {
493                // PT_LOAD
494                if ph.p_vaddr < min_addr {
495                    min_addr = ph.p_vaddr;
496                }
497                let end = ph.p_vaddr + ph.p_memsz;
498                if end > max_addr {
499                    max_addr = end;
500                }
501            }
502        }
503
504        if min_addr == u64::MAX {
505            0
506        } else {
507            (max_addr - min_addr) as usize
508        }
509    }
510}
511
512/// Load and execute an ELF program
513pub fn load_and_execute(path: &str, args: ProgramArgs) -> Result<ProcessId, KernelError> {
514    println!("[ELF-LOADER] Loading program: {}", path);
515
516    // Read file from filesystem
517    let vfs = crate::fs::get_vfs().read();
518    let file_node = vfs
519        .open(path, crate::fs::file::OpenFlags::read_only())
520        .map_err(|_| KernelError::NotFound {
521            resource: "file",
522            id: 0,
523        })?;
524
525    // Get file size
526    let metadata = file_node
527        .metadata()
528        .map_err(|_| KernelError::InvalidArgument {
529            name: "metadata",
530            value: "failed",
531        })?;
532    let file_size = metadata.size;
533
534    // Read the entire file
535    let mut elf_data = vec![0u8; file_size];
536
537    let bytes_read =
538        file_node
539            .read(0, &mut elf_data)
540            .map_err(|_| KernelError::InvalidArgument {
541                name: "read",
542                value: "failed",
543            })?;
544
545    if bytes_read != file_size {
546        return Err(KernelError::InvalidArgument {
547            name: "read",
548            value: "incomplete",
549        });
550    }
551
552    // Release the VFS lock before creating process
553    drop(vfs);
554
555    // Create ELF loader and parse
556    let loader = EnhancedElfLoader::new(elf_data)?;
557
558    // Extract program name from path
559    let name: String = path.rsplit('/').next().unwrap_or("unknown").into();
560
561    // Create new process
562    println!("[ELF-LOADER] Creating new process for execution: {}", name);
563
564    let create_options = crate::process::lifecycle::ProcessCreateOptions {
565        name: name.clone(),
566        parent: None,
567        priority: crate::process::ProcessPriority::Normal,
568        entry_point: loader.entry_point().as_usize(),
569        argv: args.args.clone(),
570        envp: args.env.clone(),
571        user_stack_size: crate::process::lifecycle::DEFAULT_USER_STACK_SIZE,
572        kernel_stack_size: crate::process::lifecycle::DEFAULT_KERNEL_STACK_SIZE,
573    };
574
575    let pid =
576        crate::process::lifecycle::create_process_with_options(create_options).map_err(|_| {
577            KernelError::ResourceExhausted {
578                resource: "process",
579            }
580        })?;
581
582    // Get the process and load program
583    if let Some(process) = crate::process::get_process(pid) {
584        // Load program segments into process memory
585        let _entry = loader.load(&process)?;
586
587        // Setup arguments on stack
588        loader.setup_args(&process, &args)?;
589
590        // Handle dynamic linking if needed
591        if loader.requires_dynamic_linking() {
592            if let Some(interp_path) = loader.interpreter() {
593                println!("[ELF-LOADER] Loading interpreter: {}", interp_path);
594                load_interpreter(&process, interp_path)?;
595            }
596        }
597
598        println!(
599            "[ELF-LOADER] Program loaded and ready to execute (PID {}, entry 0x{:x})",
600            pid.0, _entry.0
601        );
602    }
603
604    Ok(pid)
605}
606
607/// Load the dynamic linker/interpreter
608fn load_interpreter(process: &Process, interp_path: &str) -> Result<VirtualAddress, KernelError> {
609    println!("[ELF-LOADER] Loading interpreter from {}", interp_path);
610
611    // Read interpreter from filesystem
612    let vfs = crate::fs::get_vfs().read();
613    let file_node = vfs
614        .open(interp_path, crate::fs::file::OpenFlags::read_only())
615        .map_err(|_| KernelError::NotFound {
616            resource: "interpreter",
617            id: 0,
618        })?;
619
620    let metadata = file_node
621        .metadata()
622        .map_err(|_| KernelError::InvalidArgument {
623            name: "metadata",
624            value: "failed",
625        })?;
626    let file_size = metadata.size;
627
628    let mut interp_data = vec![0u8; file_size];
629
630    file_node
631        .read(0, &mut interp_data)
632        .map_err(|_| KernelError::InvalidArgument {
633            name: "read",
634            value: "failed",
635        })?;
636
637    drop(vfs);
638
639    // Parse interpreter ELF
640    let interp_loader = EnhancedElfLoader::new(interp_data)?;
641
642    // Load interpreter at a different base address to avoid collision
643    // Typically interpreters are position-independent, so we load at a high address
644    let interp_base = 0x7F00_0000_0000_u64;
645
646    let mut memory_space = process.memory_space.lock();
647
648    // Load each segment with offset
649    for ph in interp_loader.segments() {
650        if ph.p_type != 1 {
651            continue; // Skip non-LOAD
652        }
653
654        let page_mask = 0xFFF_u64;
655        let seg_vaddr = interp_base + ph.p_vaddr;
656        let page_start = seg_vaddr & !page_mask;
657        let page_end = (seg_vaddr + ph.p_memsz + page_mask) & !page_mask;
658        let num_pages = ((page_end - page_start) / 0x1000) as usize;
659
660        let mut flags = PageFlags::USER | PageFlags::PRESENT;
661        if (ph.p_flags & 0x2) != 0 {
662            flags |= PageFlags::WRITABLE;
663        }
664        if (ph.p_flags & 0x1) == 0 {
665            flags |= PageFlags::NO_EXECUTE;
666        }
667
668        for i in 0..num_pages {
669            let addr = page_start + (i as u64 * 0x1000);
670            memory_space
671                .map_page(addr as usize, flags)
672                .map_err(|_| KernelError::OutOfMemory {
673                    requested: 0x1000,
674                    available: 0,
675                })?;
676        }
677
678        // Zero BSS portion (p_memsz > p_filesz)
679        if ph.p_memsz > ph.p_filesz {
680            let bss_start = seg_vaddr + ph.p_filesz;
681            let bss_len = (ph.p_memsz - ph.p_filesz) as usize;
682            // SAFETY: bss_start is within the mapped region (seg_vaddr..seg_vaddr+p_memsz).
683            unsafe {
684                core::ptr::write_bytes(bss_start as *mut u8, 0, bss_len);
685            }
686        }
687
688        // Copy real segment data from the interpreter ELF image.
689        if ph.p_filesz > 0 {
690            let src_offset = ph.p_offset as usize;
691            let copy_len = ph.p_filesz as usize;
692            let elf_data = interp_loader.raw_data();
693            if src_offset + copy_len <= elf_data.len() {
694                // SAFETY: seg_vaddr was mapped above. src is within the
695                // loader's parsed ELF buffer. copy_len is bounded by p_filesz.
696                unsafe {
697                    core::ptr::copy_nonoverlapping(
698                        elf_data.as_ptr().add(src_offset),
699                        seg_vaddr as *mut u8,
700                        copy_len,
701                    );
702                }
703            }
704        }
705    }
706
707    let interp_entry = VirtualAddress(interp_base + interp_loader.parsed_entry_point);
708    println!(
709        "[ELF-LOADER] Interpreter loaded at base 0x{:x}, entry 0x{:x}",
710        interp_base,
711        interp_entry.as_u64()
712    );
713
714    Ok(interp_entry)
715}
716
717/// Execute a built-in test program
718pub fn execute_hello_world() -> Result<(), KernelError> {
719    println!("[ELF-LOADER] Executing hello_world program");
720
721    // Create arguments
722    let mut args = ProgramArgs::new();
723    args.add_arg(String::from("hello_world"));
724    args.add_env(String::from("PATH=/bin:/usr/bin"));
725    args.add_env(String::from("HOME=/"));
726
727    // Load and execute
728    let _pid = load_and_execute("/bin/hello_world", args)?;
729
730    println!("[ELF-LOADER] hello_world execution started");
731
732    Ok(())
733}
734
735/// Execute a program by path with default environment
736pub fn execute_program(path: &str) -> Result<ProcessId, KernelError> {
737    let mut args = ProgramArgs::new();
738    args.add_arg(String::from(path));
739    args.add_env(String::from("PATH=/bin:/usr/bin:/sbin:/usr/sbin"));
740    args.add_env(String::from("HOME=/root"));
741    args.add_env(String::from("TERM=vt100"));
742    args.add_env(String::from("USER=root"));
743    args.add_env(String::from("SHELL=/bin/vsh"));
744
745    load_and_execute(path, args)
746}
747
748/// Initialize the enhanced ELF loader
749pub fn init() -> Result<(), KernelError> {
750    println!("[ELF-LOADER] Enhanced ELF loader initialized");
751    Ok(())
752}
753
754#[cfg(test)]
755mod tests {
756    use super::*;
757
758    #[test]
759    fn test_program_args() {
760        let mut args = ProgramArgs::new();
761        args.add_arg(String::from("test"));
762        args.add_env(String::from("PATH=/bin"));
763
764        assert_eq!(args.args.len(), 1);
765        assert_eq!(args.env.len(), 1);
766    }
767
768    #[test]
769    fn test_elf_magic_check() {
770        // Valid ELF magic
771        let data = vec![0x7f, b'E', b'L', b'F'];
772        assert_eq!(&data[0..4], &[0x7f, b'E', b'L', b'F']);
773    }
774
775    #[test]
776    fn test_program_args_default() {
777        let args = ProgramArgs::default();
778        assert_eq!(args.args.len(), 0);
779        assert_eq!(args.env.len(), 0);
780    }
781}