1use 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 pub tls_pointer: Option<usize>,
38 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 pub fn tls_pointer(&self) -> Option<usize> {
54 self.tls_pointer
55 }
56
57 pub fn set_tls_pointer(&mut self, ptr: usize) {
59 self.tls_pointer = Some(ptr);
60 }
61
62 pub fn clear_tls_pointer(&mut self) {
64 self.tls_pointer = None;
65 }
66
67 pub fn set_clear_child_tid(&mut self, ptr: usize) {
69 self.clear_child_tid_ptr = Some(ptr);
70 }
71
72 pub fn on_task_exit(&mut self, task: &crate::task::Task) {
74 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 }
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) }
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 let magic_score = match file_object.as_file() {
112 Some(file_obj) => {
113 let mut magic_buffer = [0u8; 4];
115 file_obj.seek(SeekFrom::Start(0)).ok(); 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 } else {
121 return None; }
123 }
124 _ => return None, }
126 }
127 None => return None, };
129
130 let mut confidence = magic_score;
131
132 if let Some(file_obj) = file_object.as_file() {
134 let mut osabi_buffer = [0u8; 1];
136 file_obj.seek(SeekFrom::Start(7)).ok(); match file_obj.read(&mut osabi_buffer) {
138 Ok(bytes_read) if bytes_read == 1 => {
139 if osabi_buffer[0] == 83 {
140 confidence += 70; }
143 }
144 _ => return None, }
146 } else {
147 return None; }
149
150 if file_path.ends_with(".elf") || file_path.contains("scarlet") {
152 confidence += 15; }
154
155 if let Some(abi) = current_abi {
157 if abi.get_name() == self.get_name() {
158 confidence += 40; }
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 let is_wasm = if let Some(file_obj) = file_object.as_file() {
175 let mut magic_buffer = [0u8; 4];
176 let original_pos = file_obj.seek(SeekFrom::Current(0)).ok();
178
179 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] }
185 _ => false,
186 }
187 } else {
188 false
189 };
190
191 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 Some(crate::abi::RuntimeConfig {
204 runtime_path: "/system/scarlet/bin/wasm-runtime".to_string(),
205 runtime_abi: None, runtime_args: alloc::vec!["--wasm".to_string()],
207 })
208 } else {
209 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 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 let strategy = LoadStrategy {
233 choose_base_address: |target, needs_relocation| match (target, needs_relocation)
234 {
235 (LoadTarget::MainProgram, false) => 0, (LoadTarget::MainProgram, true) => 0x10000, (LoadTarget::Interpreter, _) => 0x40000000, (LoadTarget::SharedLib, _) => 0x50000000, },
240 resolve_interpreter: |requested| {
241 requested.map(|s| s.to_string())
243 },
244 };
245
246 match analyze_and_load_elf_with_strategy(file_obj, task, &strategy) {
248 Ok(elf_result) => {
249 *task.name.write() = argv
251 .get(0)
252 .map_or("Unnamed Task".to_string(), |s| s.to_string());
253
254 let root_page_table =
256 vm::get_root_pagetable(task.vm_manager.get_asid()).unwrap();
257 root_page_table.unmap_all();
258
259 vm::setup_trampoline_for_user(&task.vm_manager);
261 let stack_pointer = setup_user_stack(task).1;
262
263 match elf_result.mode {
265 ExecutionMode::Static => {
266 task.set_entry_point(elf_result.entry_point as usize);
268 }
269 ExecutionMode::Dynamic {
270 ref interpreter_path,
271 } => {
272 crate::println!(
274 "Scarlet ABI: Using dynamic linker at {}",
275 interpreter_path
276 );
277
278 let auxv = build_auxiliary_vector(&elf_result);
280
281 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 task.vcpu.lock().reset_iregs();
303 task.vcpu.lock().set_sp(stack_pointer);
304
305 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 task.vcpu.lock().iregs.reg[10] = argv.len(); task.vcpu.lock().iregs.reg[11] = argv_ptr; task.vcpu.lock().switch(trapframe);
318 Ok(())
319 }
320 Err(e) => {
321 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 if elf_type == ET_DYN {
340 match target {
341 LoadTarget::MainProgram => {
342 Some(0x10000) }
345 LoadTarget::Interpreter => {
346 Some(0x40000000) }
349 LoadTarget::SharedLib => {
350 Some(0x50000000) }
353 }
354 } else {
355 None }
357 }
358
359 fn normalize_env_to_scarlet(&self, envp: &mut Vec<String>) {
360 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 self.normalize_path_to_absolute_scarlet(value)
372 }
373 "HOME" => {
374 if value.starts_with('/') {
376 value.to_string()
377 } else {
378 format!("/home/{}", value)
379 }
380 }
381 _ => value.to_string(), };
383
384 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 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 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 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 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 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 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 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 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 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 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 let argc = argv.len();
605 let envc = envp.len();
606
607 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 let argv_array_size = (argc + 1) * core::mem::size_of::<usize>(); let envp_array_size = (envc + 1) * core::mem::size_of::<usize>(); let argc_size = core::mem::size_of::<usize>();
615
616 let total_size =
618 argc_size + argv_array_size + envp_array_size + argv_strings_size + envp_strings_size;
619
620 let aligned_total_size = (total_size + 15) & !15;
622
623 let new_sp = initial_sp - aligned_total_size;
625
626 let mut current_addr = new_sp;
630
631 self.write_to_stack_memory(task, current_addr, &argc.to_le_bytes())?;
633 current_addr += argc_size;
634
635 let argv_ptr = current_addr;
637
638 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 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; }
649 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 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; }
661 self.write_to_stack_memory(task, current_addr, &null_ptr.to_le_bytes())?;
663 current_addr += core::mem::size_of::<usize>();
664
665 for arg in argv {
667 self.write_string_to_stack(task, current_addr, arg)?;
668 current_addr += arg.len() + 1; }
670
671 for env in envp {
673 self.write_string_to_stack(task, current_addr, env)?;
674 current_addr += env.len() + 1; }
676
677 Ok((new_sp, argv_ptr))
678 }
679
680 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 fn write_string_to_stack(
700 &self,
701 task: &crate::task::Task,
702 vaddr: usize,
703 string: &str,
704 ) -> Result<(), &'static str> {
705 self.write_to_stack_memory(task, vaddr, string.as_bytes())?;
707 self.write_to_stack_memory(task, vaddr + string.len(), &[0u8])?;
709 Ok(())
710 }
711
712 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 if path.starts_with("/system/scarlet/") || path.starts_with("/scarlet/") {
724 normalized_paths.push(path.to_string());
725 } else {
726 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, };
738 normalized_paths.push(mapped_path.to_string());
739 }
740 } else if !path.is_empty() {
741 normalized_paths.push(format!("/{}", path));
743 }
744 }
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(()) } else {
758 Err(e) }
760 }
761 }
762}
763
764fn register_scarlet_abi() {
765 register_abi!(ScarletAbi);
766}
767
768early_initcall!(register_scarlet_abi);