1#[macro_use]
2mod macros;
3mod proc;
4mod file;
5pub mod fs;
6mod pipe;
7
8use alloc::{boxed::Box, string::ToString, sync::Arc, vec::Vec};
11use file::{sys_dup, sys_exec, sys_mknod, sys_open, sys_write};
12use proc::{sys_exit, sys_fork, sys_wait, sys_getpid};
13
14use crate::{
15 abi::{
16 xv6::riscv64::{
17 file::{sys_close, sys_fstat, sys_link, sys_mkdir, sys_read, sys_unlink},
18 pipe::sys_pipe,
19 proc::{sys_chdir, sys_sbrk}
20 },
21 AbiModule
22 }, arch::{self, Registers}, early_initcall, fs::{drivers::overlayfs::OverlayFS, FileSystemError, FileSystemErrorKind, SeekFrom, VfsManager}, register_abi, task::elf_loader::load_elf_into_task, vm::{setup_trampoline, setup_user_stack}
23};
24
25const MAX_FDS: usize = 1024; #[derive(Clone)]
28pub struct Xv6Riscv64Abi {
29 fd_to_handle: [Option<u32>; MAX_FDS],
32 free_fds: Vec<usize>,
34}
35
36impl Default for Xv6Riscv64Abi {
37 fn default() -> Self {
38 let mut free_fds: Vec<usize> = (0..MAX_FDS).collect();
41 free_fds.reverse(); Self {
43 fd_to_handle: [None; MAX_FDS],
44 free_fds,
45 }
46 }
47}
48
49impl Xv6Riscv64Abi {
50 pub fn allocate_fd(&mut self, handle: u32) -> Result<usize, &'static str> {
52 let fd = if let Some(freed_fd) = self.free_fds.pop() {
53 freed_fd
55 } else {
56 return Err("Too many open files");
58 };
59
60 self.fd_to_handle[fd] = Some(handle);
61 Ok(fd)
62 }
63
64 pub fn get_handle(&self, fd: usize) -> Option<u32> {
66 if fd < MAX_FDS {
67 self.fd_to_handle[fd]
68 } else {
69 None
70 }
71 }
72
73 pub fn remove_fd(&mut self, fd: usize) -> Option<u32> {
75 if fd < MAX_FDS {
76 if let Some(handle) = self.fd_to_handle[fd].take() {
77 self.free_fds.push(fd);
79 Some(handle)
80 } else {
81 None
82 }
83 } else {
84 None
85 }
86 }
87
88 pub fn find_fd_by_handle(&self, handle: u32) -> Option<usize> {
90 for (fd, &mapped_handle) in self.fd_to_handle.iter().enumerate() {
91 if let Some(h) = mapped_handle {
92 if h == handle {
93 return Some(fd);
94 }
95 }
96 }
97 None
98 }
99
100 pub fn remove_handle(&mut self, handle: u32) -> Option<usize> {
102 if let Some(fd) = self.find_fd_by_handle(handle) {
103 self.fd_to_handle[fd] = None;
104 self.free_fds.push(fd);
105 Some(fd)
106 } else {
107 None
108 }
109 }
110
111 pub fn init_std_fds(&mut self, stdin_handle: u32, stdout_handle: u32, stderr_handle: u32) {
113 self.fd_to_handle[0] = Some(stdin_handle);
115 self.fd_to_handle[1] = Some(stdout_handle);
116 self.fd_to_handle[2] = Some(stderr_handle);
117
118 self.free_fds.retain(|&fd| fd != 0 && fd != 1 && fd != 2);
120 }
121
122 pub fn fd_count(&self) -> usize {
124 self.fd_to_handle.iter().filter(|&&h| h.is_some()).count()
125 }
126
127 pub fn allocated_fds(&self) -> Vec<usize> {
129 self.fd_to_handle.iter()
130 .enumerate()
131 .filter_map(|(fd, &handle)| if handle.is_some() { Some(fd) } else { None })
132 .collect()
133 }
134}
135
136impl AbiModule for Xv6Riscv64Abi {
137 fn name() -> &'static str {
138 "xv6-riscv64"
139 }
140
141 fn get_name(&self) -> alloc::string::String {
142 Self::name().to_string()
143 }
144
145 fn clone_boxed(&self) -> alloc::boxed::Box<dyn AbiModule> {
146 Box::new(self.clone()) }
148
149 fn handle_syscall(&mut self, trapframe: &mut crate::arch::Trapframe) -> Result<usize, &'static str> {
150 syscall_handler(self, trapframe)
151 }
152
153 fn can_execute_binary(
154 &self,
155 file_object: &crate::object::KernelObject,
156 file_path: &str,
157 current_abi: Option<&dyn AbiModule>
158 ) -> Option<u8> {
159 let magic_score = match file_object.as_file() {
161 Some(file_obj) => {
162 let mut magic_buffer = [0u8; 4];
164 file_obj.seek(SeekFrom::Start(0)).ok(); match file_obj.read(&mut magic_buffer) {
166 Ok(bytes_read) if bytes_read >= 4 => {
167 if magic_buffer == [0x7F, b'E', b'L', b'F'] {
168 25 } else {
170 return None; }
172 }
173 _ => return None }
175 }
176 None => return None };
178
179 let mut confidence = magic_score;
180
181 confidence += 10;
184
185 if file_path.contains("xv6") || file_path.ends_with(".xv6") {
187 confidence += 20; } else if file_path.ends_with(".elf") {
189 confidence += 5; }
191
192 if let Some(abi) = current_abi {
194 if abi.get_name() == self.get_name() {
195 confidence += 15; }
197 }
198
199 Some(confidence.min(100)) }
201
202 fn execute_binary(
203 &self,
204 file_object: &crate::object::KernelObject,
205 argv: &[&str],
206 _envp: &[&str],
207 task: &mut crate::task::Task,
208 trapframe: &mut crate::arch::Trapframe
209 ) -> Result<(), &'static str> {
210 match file_object.as_file() {
211 Some(file_obj) => {
212 task.text_size = 0;
214 task.data_size = 0;
215 task.stack_size = 0;
216 task.brk = None;
217
218 match load_elf_into_task(file_obj, task) {
220 Ok(entry_point) => {
221 task.name = argv.get(0).map_or("xv6".to_string(), |s| s.to_string());
223 let idx = arch::vm::get_root_pagetable_ptr(task.vm_manager.get_asid()).unwrap();
225 let root_page_table = arch::vm::get_pagetable(idx).unwrap();
226 root_page_table.unmap_all();
227 setup_trampoline(&mut task.vm_manager);
229 let (_, stack_top) = setup_user_stack(task);
231 let mut stack_pointer = stack_top as usize;
232
233 let mut arg_ptrs: Vec<u64> = Vec::new();
234 for arg in argv.iter() {
235 let arg_bytes = arg.as_bytes();
236 stack_pointer -= arg_bytes.len() + 1; stack_pointer -= stack_pointer % 16; unsafe {
240 let translated_stack_pointer = task.vm_manager
241 .translate_vaddr(stack_pointer)
242 .unwrap();
243 let stack_slice = core::slice::from_raw_parts_mut(translated_stack_pointer as *mut u8, arg_bytes.len() + 1);
244 stack_slice[..arg_bytes.len()].copy_from_slice(arg_bytes);
245 stack_slice[arg_bytes.len()] = 0; }
247
248 arg_ptrs.push(stack_pointer as u64); }
250
251 let argc = arg_ptrs.len();
252
253 stack_pointer -= argc * 8;
254 stack_pointer -= stack_pointer % 16; unsafe {
258 let translated_stack_pointer = task.vm_manager
259 .translate_vaddr(stack_pointer)
260 .unwrap() as *mut u64;
261 for (i, &arg_ptr) in arg_ptrs.iter().enumerate() {
262 *(translated_stack_pointer.add(i)) = arg_ptr;
263 }
264 }
265
266 task.set_entry_point(entry_point as usize);
268
269 task.vcpu.regs = Registers::new();
271 task.vcpu.set_sp(stack_pointer);
273 task.vcpu.regs.reg[11] = stack_pointer as usize; task.vcpu.regs.reg[10] = argc; task.vcpu.switch(trapframe);
278 Ok(())
279 },
280 Err(_e) => {
281 Err("Failed to load XV6 ELF binary")
282 }
283 }
284 },
285 None => Err("Invalid file object type for XV6 binary execution"),
286 }
287 }
288
289 fn get_default_cwd(&self) -> &str {
290 "/" }
292
293 fn setup_overlay_environment(
294 &self,
295 target_vfs: &Arc<VfsManager>,
296 base_vfs: &Arc<VfsManager>,
297 system_path: &str,
298 config_path: &str,
299 ) -> Result<(), &'static str> {
300 let lower_vfs_list = alloc::vec![(base_vfs, system_path)];
303 let upper_vfs = base_vfs;
304 let fs = match OverlayFS::new_from_paths_and_vfs(Some((upper_vfs, config_path)), lower_vfs_list, "/") {
305 Ok(fs) => fs,
306 Err(e) => {
307 crate::println!("Failed to create overlay filesystem for XV6 ABI: {}", e.message);
308 return Err("Failed to create XV6 overlay environment");
309 }
310 }
311 ;
312 match target_vfs.mount(fs, "/", 0) {
313 Ok(()) => Ok(()),
314 Err(e) => {
315 crate::println!("Failed to create cross-VFS overlay for XV6 ABI: {}", e.message);
316 Err("Failed to create XV6 overlay environment")
317 }
318 }
319 }
320
321 fn setup_shared_resources(
322 &self,
323 target_vfs: &Arc<VfsManager>,
324 base_vfs: &Arc<VfsManager>,
325 ) -> Result<(), &'static str> {
326 match create_dir_if_not_exists(target_vfs, "/home") {
329 Ok(()) => {}
330 Err(e) => {
331 return Err("Failed to create /home directory for XV6");
333 }
334 }
335
336 match target_vfs.bind_mount_from(base_vfs, "/home", "/home") {
337 Ok(()) => {}
338 Err(e) => {
339 }
341 }
342
343 match create_dir_if_not_exists(target_vfs, "/data") {
344 Ok(()) => {}
345 Err(e) => {
346 crate::println!("Failed to create /data directory for XV6: {}", e.message);
347 return Err("Failed to create /data directory for XV6");
348 }
349 }
350
351 match target_vfs.bind_mount_from(base_vfs, "/data/shared", "/data/shared") {
352 Ok(()) => {}
353 Err(e) => {
354 }
356 }
357
358 match create_dir_if_not_exists(target_vfs, "/scarlet") {
360 Ok(()) => {}
361 Err(e) => {
362 crate::println!("Failed to create /scarlet directory for XV6: {}", e.message);
363 return Err("Failed to create /scarlet directory for XV6");
364 }
365 }
366 match target_vfs.bind_mount_from(base_vfs, "/", "/scarlet") {
367 Ok(()) => Ok(()),
368 Err(e) => {
369 crate::println!("Failed to bind mount native Scarlet root to /scarlet for XV6: {}", e.message);
370 return Err("Failed to bind mount native Scarlet root to /scarlet for XV6");
371 }
372 }
373 }
374
375 fn initialize_from_existing_handles(&self, task: &mut crate::task::Task) -> Result<(), &'static str> {
376 task.handle_table.close_all();
377 Ok(())
378 }
379}
380
381syscall_table! {
382 Invalid = 0 => |_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, _trapframe: &mut crate::arch::Trapframe| {
383 0
384 },
385 Fork = 1 => sys_fork,
386 Exit = 2 => sys_exit,
387 Wait = 3 => sys_wait,
388 Pipe = 4 => sys_pipe,
389 Read = 5 => sys_read,
390 Exec = 7 => sys_exec,
392 Fstat = 8 => sys_fstat,
393 Chdir = 9 => sys_chdir,
394 Dup = 10 => sys_dup,
395 Getpid = 11 => sys_getpid,
396 Sbrk = 12 => sys_sbrk,
397 Open = 15 => sys_open,
400 Write = 16 => sys_write,
401 Mknod = 17 => sys_mknod,
402 Unlink = 18 => sys_unlink,
403 Link = 19 => sys_link,
404 Mkdir = 20 => sys_mkdir,
405 Close = 21 => sys_close,
406}
407
408fn create_dir_if_not_exists(vfs: &Arc<VfsManager>, path: &str) -> Result<(), FileSystemError> {
409 match vfs.create_dir(path) {
410 Ok(()) => Ok(()),
411 Err(e) => {
412 if e.kind == FileSystemErrorKind::AlreadyExists {
413 Ok(()) } else {
415 Err(e) }
417 }
418 }
419}
420
421fn register_xv6_abi() {
422 register_abi!(Xv6Riscv64Abi);
423}
424
425early_initcall!(register_xv6_abi);