veridian_kernel/userspace/
enhanced_loader.rs1#![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
16pub struct ProgramArgs {
18 pub args: Vec<String>,
20
21 pub env: Vec<String>,
23}
24
25impl ProgramArgs {
26 pub fn new() -> Self {
28 Self {
29 args: Vec::new(),
30 env: Vec::new(),
31 }
32 }
33
34 pub fn add_arg(&mut self, arg: String) {
36 self.args.push(arg);
37 }
38
39 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#[allow(dead_code)] pub struct EnhancedElfLoader {
54 data: Vec<u8>,
56
57 header: Option<Elf64Header>,
59
60 program_headers: Vec<Elf64ProgramHeader>,
62
63 parsed_entry_point: u64,
65
66 requires_dynamic: bool,
68
69 interpreter_path: Option<String>,
71}
72
73impl EnhancedElfLoader {
74 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 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 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 if self.data[4] != 2 {
111 return Err(KernelError::InvalidArgument {
112 name: "elf_class",
113 value: "not_64bit",
114 });
115 }
116
117 if self.data[5] != 1 {
119 return Err(KernelError::InvalidArgument {
120 name: "elf_encoding",
121 value: "not_little_endian",
122 });
123 }
124
125 let header = unsafe { *(self.data.as_ptr() as *const Elf64Header) };
132
133 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 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 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 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 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 for i in 0..ph_count {
191 let offset = ph_offset + (i * ph_size);
192
193 let ph = unsafe { *(self.data[offset..].as_ptr() as *const Elf64ProgramHeader) };
198 self.program_headers.push(ph);
199
200 if ph.p_type == 3 {
202 self.requires_dynamic = true;
203
204 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]; 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 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 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 for ph in &self.program_headers {
237 if ph.p_type != 1 {
238 continue; }
240
241 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 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 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 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 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 if ph.p_memsz > ph.p_filesz {
290 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 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 let stack_top = 0x7FFF_FFFF_F000_u64; let stack_size = 0x10000_u64; 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 let mut sp = stack_top;
365
366 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 for env_str in args.env.iter().rev() {
372 let bytes = env_str.as_bytes();
373 sp -= (bytes.len() + 1) as u64; 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; }
383 env_ptrs.push(sp);
384 }
385 env_ptrs.reverse();
386
387 for arg_str in args.args.iter().rev() {
389 let bytes = arg_str.as_bytes();
390 sp -= (bytes.len() + 1) as u64;
391 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 sp &= !0xF;
405
406 sp -= 8;
408 unsafe {
411 *(sp as *mut u64) = 0;
412 }
413
414 for env_ptr in env_ptrs.iter().rev() {
416 sp -= 8;
417 unsafe {
421 *(sp as *mut u64) = *env_ptr;
422 }
423 }
424
425 sp -= 8;
427 unsafe {
430 *(sp as *mut u64) = 0;
431 }
432
433 for arg_ptr in arg_ptrs.iter().rev() {
435 sp -= 8;
436 unsafe {
440 *(sp as *mut u64) = *arg_ptr;
441 }
442 }
443
444 sp -= 8;
446 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 pub fn entry_point(&self) -> VirtualAddress {
463 VirtualAddress(self.parsed_entry_point)
464 }
465
466 pub fn requires_dynamic_linking(&self) -> bool {
468 self.requires_dynamic
469 }
470
471 pub fn interpreter(&self) -> Option<&str> {
473 self.interpreter_path.as_deref()
474 }
475
476 pub fn segments(&self) -> &[Elf64ProgramHeader] {
478 &self.program_headers
479 }
480
481 pub fn raw_data(&self) -> &[u8] {
483 &self.data
484 }
485
486 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 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
512pub fn load_and_execute(path: &str, args: ProgramArgs) -> Result<ProcessId, KernelError> {
514 println!("[ELF-LOADER] Loading program: {}", path);
515
516 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 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 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 drop(vfs);
554
555 let loader = EnhancedElfLoader::new(elf_data)?;
557
558 let name: String = path.rsplit('/').next().unwrap_or("unknown").into();
560
561 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 if let Some(process) = crate::process::get_process(pid) {
584 let _entry = loader.load(&process)?;
586
587 loader.setup_args(&process, &args)?;
589
590 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
607fn load_interpreter(process: &Process, interp_path: &str) -> Result<VirtualAddress, KernelError> {
609 println!("[ELF-LOADER] Loading interpreter from {}", interp_path);
610
611 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 let interp_loader = EnhancedElfLoader::new(interp_data)?;
641
642 let interp_base = 0x7F00_0000_0000_u64;
645
646 let mut memory_space = process.memory_space.lock();
647
648 for ph in interp_loader.segments() {
650 if ph.p_type != 1 {
651 continue; }
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 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 unsafe {
684 core::ptr::write_bytes(bss_start as *mut u8, 0, bss_len);
685 }
686 }
687
688 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 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
717pub fn execute_hello_world() -> Result<(), KernelError> {
719 println!("[ELF-LOADER] Executing hello_world program");
720
721 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 let _pid = load_and_execute("/bin/hello_world", args)?;
729
730 println!("[ELF-LOADER] hello_world execution started");
731
732 Ok(())
733}
734
735pub 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
748pub 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 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}