1#[macro_use]
2mod macros;
3mod file;
4pub mod fs;
5mod pipe;
6mod proc;
7
8use alloc::{
11 boxed::Box,
12 string::{String, ToString},
13 sync::Arc,
14 vec::Vec,
15};
16use core::sync::atomic::Ordering;
17use file::{sys_dup, sys_exec, sys_mknod, sys_open, sys_write};
18use hashbrown::HashMap;
19use proc::{sys_exit, sys_fork, sys_getpid, sys_sleep, sys_wait};
20
21use crate::{
22 abi::{
23 AbiModule,
24 xv6::riscv64::{
25 file::{sys_close, sys_fstat, sys_link, sys_mkdir, sys_read, sys_unlink},
26 pipe::sys_pipe,
27 proc::{sys_chdir, sys_sbrk},
28 },
29 },
30 arch::{self, IntRegisters},
31 early_initcall,
32 fs::{
33 FileSystemError, FileSystemErrorKind, SeekFrom, VfsManager, drivers::overlayfs::OverlayFS,
34 },
35 register_abi,
36 task::elf_loader::load_elf_into_task,
37 vm::setup_user_stack,
38};
39
40const MAX_FDS: usize = 1024; #[derive(Clone)]
43pub struct Xv6Riscv64Abi {
44 namespace: Arc<crate::task::namespace::TaskNamespace>,
46 fd_to_handle: HashMap<usize, u32>,
48 free_fds: Vec<usize>,
50}
51
52impl Default for Xv6Riscv64Abi {
53 fn default() -> Self {
54 let mut free_fds: Vec<usize> = (0..MAX_FDS).collect();
57 free_fds.reverse(); let namespace = crate::task::namespace::get_root_namespace().clone();
62
63 Self {
64 namespace,
65 fd_to_handle: HashMap::new(), free_fds,
67 }
68 }
69}
70
71impl Xv6Riscv64Abi {
72 pub fn allocate_fd(&mut self, handle: u32) -> Result<usize, &'static str> {
74 let fd = if let Some(freed_fd) = self.free_fds.pop() {
75 freed_fd
77 } else {
78 return Err("Too many open files");
80 };
81
82 self.fd_to_handle.insert(fd, handle);
83 Ok(fd)
84 }
85
86 pub fn get_handle(&self, fd: usize) -> Option<u32> {
88 if fd < MAX_FDS {
89 self.fd_to_handle.get(&fd).copied()
90 } else {
91 None
92 }
93 }
94
95 pub fn remove_fd(&mut self, fd: usize) -> Option<u32> {
97 if fd < MAX_FDS {
98 if let Some(handle) = self.fd_to_handle.remove(&fd) {
99 self.free_fds.push(fd);
101 Some(handle)
102 } else {
103 None
104 }
105 } else {
106 None
107 }
108 }
109
110 pub fn find_fd_by_handle(&self, handle: u32) -> Option<usize> {
112 for (&fd, &mapped_handle) in self.fd_to_handle.iter() {
113 if mapped_handle == handle {
114 return Some(fd);
115 }
116 }
117 None
118 }
119
120 pub fn remove_handle(&mut self, handle: u32) -> Option<usize> {
122 if let Some(fd) = self.find_fd_by_handle(handle) {
123 self.fd_to_handle.remove(&fd);
124 self.free_fds.push(fd);
125 Some(fd)
126 } else {
127 None
128 }
129 }
130
131 pub fn init_std_fds(&mut self, stdin_handle: u32, stdout_handle: u32, stderr_handle: u32) {
133 self.fd_to_handle.insert(0, stdin_handle);
135 self.fd_to_handle.insert(1, stdout_handle);
136 self.fd_to_handle.insert(2, stderr_handle);
137
138 self.free_fds.retain(|&fd| fd != 0 && fd != 1 && fd != 2);
140 }
141
142 pub fn fd_count(&self) -> usize {
144 self.fd_to_handle.len()
145 }
146
147 pub fn allocated_fds(&self) -> Vec<usize> {
149 self.fd_to_handle.keys().copied().collect()
150 }
151}
152
153impl AbiModule for Xv6Riscv64Abi {
154 fn name() -> &'static str {
155 "xv6-riscv64"
156 }
157
158 fn get_name(&self) -> alloc::string::String {
159 Self::name().to_string()
160 }
161
162 fn clone_boxed(&self) -> alloc::boxed::Box<dyn AbiModule + Send + Sync> {
163 Box::new(self.clone()) }
165
166 fn handle_syscall(
167 &mut self,
168 trapframe: &mut crate::arch::Trapframe,
169 ) -> Result<usize, &'static str> {
170 syscall_handler(self, trapframe)
171 }
172
173 fn can_execute_binary(
174 &self,
175 file_object: &crate::object::KernelObject,
176 file_path: &str,
177 current_abi: Option<&(dyn AbiModule + Send + Sync)>,
178 ) -> Option<u8> {
179 let magic_score = match file_object.as_file() {
181 Some(file_obj) => {
182 let mut magic_buffer = [0u8; 4];
184 file_obj.seek(SeekFrom::Start(0)).ok(); match file_obj.read(&mut magic_buffer) {
186 Ok(bytes_read) if bytes_read >= 4 => {
187 if magic_buffer == [0x7F, b'E', b'L', b'F'] {
188 25 } else {
190 return None; }
192 }
193 _ => return None, }
195 }
196 None => return None, };
198
199 let mut confidence = magic_score;
200
201 confidence += 10;
204
205 if file_path.contains("xv6") || file_path.ends_with(".xv6") {
207 confidence += 20; } else if file_path.ends_with(".elf") {
209 confidence += 5; }
211
212 if let Some(abi) = current_abi {
214 if abi.get_name() == self.get_name() {
215 confidence += 15; }
217 }
218
219 Some(confidence.min(100)) }
221
222 fn execute_binary(
223 &self,
224 file_object: &crate::object::KernelObject,
225 argv: &[&str],
226 _envp: &[&str],
227 task: &crate::task::Task,
228 trapframe: &mut crate::arch::Trapframe,
229 ) -> Result<(), &'static str> {
230 match file_object.as_file() {
231 Some(file_obj) => {
232 task.text_size.store(0, Ordering::SeqCst);
234 task.data_size.store(0, Ordering::SeqCst);
235 task.stack_size.store(0, Ordering::SeqCst);
236 task.brk
237 .store(usize::MAX, core::sync::atomic::Ordering::SeqCst);
238
239 match load_elf_into_task(file_obj, task) {
241 Ok(entry_point) => {
242 *task.name.write() =
244 argv.get(0).map_or("xv6".to_string(), |s| s.to_string());
245 let idx =
247 arch::vm::get_root_pagetable_ptr(task.vm_manager.get_asid()).unwrap();
248 let root_page_table = arch::vm::get_pagetable(idx).unwrap();
249 root_page_table.unmap_all();
250 arch::vm::setup_trampoline_for_user(&task.vm_manager);
252 let (_, stack_top) = setup_user_stack(task);
254 let mut stack_pointer = stack_top as usize;
255
256 let mut arg_ptrs: Vec<u64> = Vec::new();
257 for arg in argv.iter() {
258 let arg_bytes = arg.as_bytes();
259 stack_pointer -= arg_bytes.len() + 1; stack_pointer -= stack_pointer % 16; unsafe {
263 let translated_stack_pointer =
264 task.vm_manager.translate_vaddr(stack_pointer).unwrap();
265 let stack_slice = core::slice::from_raw_parts_mut(
266 translated_stack_pointer as *mut u8,
267 arg_bytes.len() + 1,
268 );
269 stack_slice[..arg_bytes.len()].copy_from_slice(arg_bytes);
270 stack_slice[arg_bytes.len()] = 0; }
272
273 arg_ptrs.push(stack_pointer as u64); }
275
276 let argc = arg_ptrs.len();
277
278 stack_pointer -= argc * 8;
279 stack_pointer -= stack_pointer % 16; unsafe {
283 let translated_stack_pointer =
284 task.vm_manager.translate_vaddr(stack_pointer).unwrap() as *mut u64;
285 for (i, &arg_ptr) in arg_ptrs.iter().enumerate() {
286 *(translated_stack_pointer.add(i)) = arg_ptr;
287 }
288 }
289
290 task.set_entry_point(entry_point as usize);
292
293 task.vcpu.lock().iregs = IntRegisters::new();
295 task.vcpu.lock().set_sp(stack_pointer);
297 task.vcpu.lock().iregs.reg[11] = stack_pointer as usize; task.vcpu.lock().iregs.reg[10] = argc; task.vcpu.lock().switch(trapframe);
302 Ok(())
303 }
304 Err(_e) => Err("Failed to load XV6 ELF binary"),
305 }
306 }
307 None => Err("Invalid file object type for XV6 binary execution"),
308 }
309 }
310
311 fn get_default_cwd(&self) -> &str {
312 "/" }
314
315 fn setup_overlay_environment(
316 &self,
317 target_vfs: &Arc<VfsManager>,
318 base_vfs: &Arc<VfsManager>,
319 system_path: &str,
320 config_path: &str,
321 ) -> Result<(), &'static str> {
322 let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
325 let upper_vfs = base_vfs;
326 let fs = match OverlayFS::new_from_paths_and_vfs(
327 Some((upper_vfs, config_path)),
328 lower_vfs_list,
329 "/",
330 ) {
331 Ok(fs) => fs,
332 Err(e) => {
333 crate::println!(
334 "Failed to create overlay filesystem for XV6 ABI: {}",
335 e.message
336 );
337 return Err("Failed to create XV6 overlay environment");
338 }
339 };
340 match target_vfs.mount(fs, "/", 0) {
341 Ok(()) => Ok(()),
342 Err(e) => {
343 crate::println!(
344 "Failed to create cross-VFS overlay for XV6 ABI: {}",
345 e.message
346 );
347 Err("Failed to create XV6 overlay environment")
348 }
349 }
350 }
351
352 fn setup_shared_resources(
353 &self,
354 target_vfs: &Arc<VfsManager>,
355 base_vfs: &Arc<VfsManager>,
356 ) -> Result<(), &'static str> {
357 match create_dir_if_not_exists(target_vfs, "/home") {
360 Ok(()) => {}
361 Err(e) => {
362 return Err("Failed to create /home directory for XV6");
364 }
365 }
366
367 match target_vfs.bind_mount_from(base_vfs, "/home", "/home") {
368 Ok(()) => {}
369 Err(e) => {
370 }
372 }
373
374 match create_dir_if_not_exists(target_vfs, "/data") {
375 Ok(()) => {}
376 Err(e) => {
377 crate::println!("Failed to create /data directory for XV6: {}", e.message);
378 return Err("Failed to create /data directory for XV6");
379 }
380 }
381
382 match target_vfs.bind_mount_from(base_vfs, "/data/shared", "/data/shared") {
383 Ok(()) => {}
384 Err(e) => {
385 }
387 }
388
389 match create_dir_if_not_exists(target_vfs, "/scarlet") {
391 Ok(()) => {}
392 Err(e) => {
393 crate::println!("Failed to create /scarlet directory for XV6: {}", e.message);
394 return Err("Failed to create /scarlet directory for XV6");
395 }
396 }
397 match target_vfs.bind_mount_from(base_vfs, "/", "/scarlet") {
398 Ok(()) => Ok(()),
399 Err(e) => {
400 crate::println!(
401 "Failed to bind mount native Scarlet root to /scarlet for XV6: {}",
402 e.message
403 );
404 return Err("Failed to bind mount native Scarlet root to /scarlet for XV6");
405 }
406 }
407 }
408
409 fn initialize_from_existing_handles(
410 &mut self,
411 task: &crate::task::Task,
412 ) -> Result<(), &'static str> {
413 task.handle_table.close_all();
414 Ok(())
415 }
416
417 fn choose_load_address(
418 &self,
419 _elf_type: u16,
420 _target: crate::task::elf_loader::LoadTarget,
421 ) -> Option<u64> {
422 None
425 }
426
427 fn get_interpreter_path(&self, _requested_interpreter: &str) -> String {
428 "/dev/null".to_string() }
433
434 fn get_task_namespace(&self) -> Arc<crate::task::namespace::TaskNamespace> {
435 self.namespace.clone()
436 }
437}
438
439syscall_table! {
440 Invalid = 0 => |_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, _trapframe: &mut crate::arch::Trapframe| {
441 0
442 },
443 Fork = 1 => sys_fork,
444 Exit = 2 => sys_exit,
445 Wait = 3 => sys_wait,
446 Pipe = 4 => sys_pipe,
447 Read = 5 => sys_read,
448 Exec = 7 => sys_exec,
450 Fstat = 8 => sys_fstat,
451 Chdir = 9 => sys_chdir,
452 Dup = 10 => sys_dup,
453 Getpid = 11 => sys_getpid,
454 Sbrk = 12 => sys_sbrk,
455 Sleep = 13 => sys_sleep,
456 Open = 15 => sys_open,
458 Write = 16 => sys_write,
459 Mknod = 17 => sys_mknod,
460 Unlink = 18 => sys_unlink,
461 Link = 19 => sys_link,
462 Mkdir = 20 => sys_mkdir,
463 Close = 21 => sys_close,
464}
465
466fn create_dir_if_not_exists(vfs: &Arc<VfsManager>, path: &str) -> Result<(), FileSystemError> {
467 match vfs.create_dir(path) {
468 Ok(()) => Ok(()),
469 Err(e) => {
470 if e.kind == FileSystemErrorKind::AlreadyExists {
471 Ok(()) } else {
473 Err(e) }
475 }
476 }
477}
478
479fn register_xv6_abi() {
480 register_abi!(Xv6Riscv64Abi);
481}
482
483early_initcall!(register_xv6_abi);