1use crate::{
2 abi::xv6::riscv64::fs::xv6fs::{Dirent, Stat},
3 arch::Trapframe,
4 device::manager::DeviceManager,
5 executor::TransparentExecutor,
6 fs::{
7 DeviceFileInfo,
8 DirectoryEntry, FileType,
10 SeekFrom,
11 },
12 library::std::string::{
13 cstring_to_string, parse_c_string_from_userspace, parse_string_array_from_userspace,
14 },
15 task::mytask,
16};
17use alloc::{
18 string::{String, ToString},
19 sync::Arc,
20 vec,
21 vec::Vec,
22};
23
24fn read_directory_as_xv6_dirent(buf_ptr: *mut u8, count: usize, buffer_data: &[u8]) -> usize {
26 if count < Dirent::DIRENT_SIZE {
27 return 0; }
29
30 if let Some(dir_entry) = DirectoryEntry::parse(buffer_data) {
32 let inum = (dir_entry.file_id & 0xFFFF) as u16; let name = dir_entry.name_str().unwrap_or("");
35
36 let xv6_dirent = Dirent::new(inum, name);
37
38 if count >= Dirent::DIRENT_SIZE {
40 let dirent_bytes = xv6_dirent.as_bytes();
42 unsafe {
43 core::ptr::copy_nonoverlapping(dirent_bytes.as_ptr(), buf_ptr, Dirent::DIRENT_SIZE);
44 }
45 return Dirent::DIRENT_SIZE;
46 }
47 }
48
49 0 }
51
52const MAX_PATH_LENGTH: usize = 128;
53const MAX_ARG_COUNT: usize = 64;
54
55pub fn sys_exec(
56 _abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
57 trapframe: &mut Trapframe,
58) -> usize {
59 let task = mytask().unwrap();
60
61 trapframe.increment_pc_next(task);
63
64 let path_ptr = trapframe.get_arg(0);
66 let argv_ptr = trapframe.get_arg(1);
67
68 let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
70 Ok(path) => match to_absolute_path_v2(&task, &path) {
71 Ok(abs_path) => abs_path,
72 Err(_) => return usize::MAX, },
74 Err(_) => return usize::MAX, };
76
77 let argv_strings =
79 match parse_string_array_from_userspace(task, argv_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
80 Ok(args) => args,
81 Err(_) => return usize::MAX, };
83
84 let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
86
87 match TransparentExecutor::execute_binary(&path_str, &argv_refs, &[], task, trapframe, false) {
89 Ok(_) => {
90 trapframe.get_return_value()
94 }
95 Err(_) => {
96 usize::MAX }
100 }
101}
102
103#[repr(i32)]
104enum OpenMode {
105 ReadOnly = 0x000,
106 WriteOnly = 0x001,
107 ReadWrite = 0x002,
108 Create = 0x200,
109 Truncate = 0x400,
110}
111
112pub fn sys_open(
113 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
114 trapframe: &mut Trapframe,
115) -> usize {
116 let task = mytask().unwrap();
117 let path_ptr = task
118 .vm_manager
119 .translate_vaddr(trapframe.get_arg(0))
120 .unwrap() as *const u8;
121 let mode = trapframe.get_arg(1) as i32;
122
123 trapframe.increment_pc_next(task);
125
126 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
128 Ok((path, _)) => match to_absolute_path_v2(&task, &path) {
129 Ok(abs_path) => abs_path,
130 Err(_) => return usize::MAX,
131 },
132 Err(_) => return usize::MAX, };
134
135 let vfs = task.vfs.read().clone().unwrap();
137
138 let file = vfs.open(&path_str, 0);
140
141 match file {
142 Ok(kernel_obj) => {
143 let handle = task.handle_table.insert(kernel_obj);
145 match handle {
146 Ok(handle) => {
147 match abi.allocate_fd(handle as u32) {
148 Ok(fd) => fd,
149 Err(_) => usize::MAX, }
151 }
152 Err(_) => usize::MAX, }
154 }
155 Err(_) => {
156 if mode & OpenMode::Create as i32 != 0 {
158 let res = vfs.create_file(&path_str, FileType::RegularFile);
159 if res.is_err() {
160 return usize::MAX; }
162 match vfs.open(&path_str, 0) {
163 Ok(kernel_obj) => {
164 let handle = task.handle_table.insert(kernel_obj);
166 match handle {
167 Ok(handle) => {
168 match abi.allocate_fd(handle as u32) {
169 Ok(fd) => fd,
170 Err(_) => usize::MAX, }
172 }
173 Err(_) => usize::MAX, }
175 }
176 Err(_) => usize::MAX, }
178 } else {
179 return usize::MAX; }
181 }
182 }
183}
184
185pub fn sys_dup(
186 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
187 trapframe: &mut Trapframe,
188) -> usize {
189 let task = mytask().unwrap();
190 let fd = trapframe.get_arg(0) as usize;
191 trapframe.increment_pc_next(task);
192
193 if let Some(old_handle) = abi.get_handle(fd) {
195 if let Some(kernel_obj) = task.handle_table.clone_for_dup(old_handle) {
197 let handle = task.handle_table.insert(kernel_obj);
198 match handle {
199 Ok(new_handle) => {
200 match abi.allocate_fd(new_handle as u32) {
201 Ok(fd) => fd,
202 Err(_) => usize::MAX, }
204 }
205 Err(_) => usize::MAX, }
207 } else {
208 usize::MAX }
210 } else {
211 usize::MAX }
213}
214
215pub fn sys_close(
216 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
217 trapframe: &mut Trapframe,
218) -> usize {
219 let task = mytask().unwrap();
220 let fd = trapframe.get_arg(0) as usize;
221 trapframe.increment_pc_next(task);
222
223 if let Some(handle) = abi.remove_fd(fd) {
225 if task.handle_table.remove(handle).is_some() {
226 0 } else {
228 usize::MAX }
230 } else {
231 usize::MAX }
233}
234
235pub fn sys_read(
236 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
237 trapframe: &mut Trapframe,
238) -> usize {
239 let task = mytask().unwrap();
240 let fd = trapframe.get_arg(0) as usize;
241 let buf_ptr = task
242 .vm_manager
243 .translate_vaddr(trapframe.get_arg(1))
244 .unwrap() as *mut u8;
245 let count = trapframe.get_arg(2) as usize;
246
247 let handle = match abi.get_handle(fd) {
249 Some(h) => h,
250 None => {
251 trapframe.increment_pc_next(task);
252 return usize::MAX; }
254 };
255
256 let kernel_obj = match task.handle_table.get(handle) {
257 Some(obj) => obj,
258 None => {
259 trapframe.increment_pc_next(task);
260 return usize::MAX; }
262 };
263
264 let is_directory = if let Some(file_obj) = kernel_obj.as_file() {
266 if let Ok(metadata) = file_obj.metadata() {
267 matches!(metadata.file_type, FileType::Directory)
268 } else {
269 false
270 }
271 } else {
272 false
273 };
274
275 let stream = match kernel_obj.as_stream() {
276 Some(stream) => stream,
277 None => {
278 trapframe.increment_pc_next(task);
279 return usize::MAX; }
281 };
282
283 if is_directory {
284 let directory_entry_size = core::mem::size_of::<DirectoryEntry>();
286 let mut temp_buffer = vec![0u8; directory_entry_size];
287
288 match stream.read(&mut temp_buffer) {
289 Ok(n) => {
290 trapframe.increment_pc_next(task); if n > 0 && n >= directory_entry_size {
292 let converted_bytes =
294 read_directory_as_xv6_dirent(buf_ptr, count, &temp_buffer[..n]);
295 if converted_bytes > 0 {
296 return converted_bytes; }
298 }
299 0 }
301 Err(_) => usize::MAX, }
303 } else {
304 let mut buffer = unsafe { core::slice::from_raw_parts_mut(buf_ptr, count) };
306
307 match stream.read(&mut buffer) {
308 Ok(n) => {
309 trapframe.increment_pc_next(task); n
311 } Err(_) => usize::MAX, }
314 }
315}
316
317pub fn sys_write(
318 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
319 trapframe: &mut Trapframe,
320) -> usize {
321 let task = mytask().unwrap();
322 let fd = trapframe.get_arg(0) as usize;
323 let buf_ptr = task
324 .vm_manager
325 .translate_vaddr(trapframe.get_arg(1))
326 .unwrap() as *const u8;
327 let count = trapframe.get_arg(2) as usize;
328
329 trapframe.increment_pc_next(task);
331
332 let handle = match abi.get_handle(fd) {
334 Some(h) => h,
335 None => return usize::MAX, };
337
338 let kernel_obj = match task.handle_table.get(handle) {
339 Some(obj) => obj,
340 None => return usize::MAX, };
342
343 let stream = match kernel_obj.as_stream() {
344 Some(stream) => stream,
345 None => return usize::MAX, };
347
348 let buffer = unsafe { core::slice::from_raw_parts(buf_ptr, count) };
349
350 match stream.write(buffer) {
351 Ok(n) => n,
352 Err(_) => usize::MAX, }
354}
355
356pub fn sys_lseek(
357 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
358 trapframe: &mut Trapframe,
359) -> usize {
360 let task = mytask().unwrap();
361 let fd = trapframe.get_arg(0) as usize;
362 let offset = trapframe.get_arg(1) as i64;
363 let whence = trapframe.get_arg(2) as i32;
364
365 trapframe.increment_pc_next(task);
367
368 let handle = match abi.get_handle(fd) {
370 Some(h) => h,
371 None => return usize::MAX, };
373
374 let kernel_obj = match task.handle_table.get(handle) {
375 Some(obj) => obj,
376 None => return usize::MAX, };
378
379 let file = match kernel_obj.as_file() {
380 Some(file) => file,
381 None => return usize::MAX, };
383
384 let whence = match whence {
385 0 => SeekFrom::Start(offset as u64),
386 1 => SeekFrom::Current(offset),
387 2 => SeekFrom::End(offset),
388 _ => return usize::MAX, };
390
391 match file.seek(whence) {
392 Ok(pos) => pos as usize,
393 Err(_) => usize::MAX, }
395}
396
397pub fn sys_mknod(
399 _abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
400 trapframe: &mut Trapframe,
401) -> usize {
402 let task = mytask().unwrap();
403 trapframe.increment_pc_next(task);
404 let name_ptr = task
405 .vm_manager
406 .translate_vaddr(trapframe.get_arg(0))
407 .unwrap() as *const u8;
408 let name = get_path_str_v2(name_ptr).unwrap();
409 let path = to_absolute_path_v2(&task, &name).unwrap();
410
411 let major = trapframe.get_arg(1) as u32;
412 let minor = trapframe.get_arg(2) as u32;
413
414 match (major, minor) {
415 (1, 0) => {
416 let console_dev = Some(DeviceManager::get_manager().register_device(Arc::new(
418 crate::abi::xv6::drivers::console::ConsoleDevice::new(0, "console"),
419 )));
420
421 let vfs = task.vfs.read().clone().unwrap();
422 let _res = vfs.create_file(
423 &path,
424 FileType::CharDevice(DeviceFileInfo {
425 device_id: console_dev.unwrap(),
426 device_type: crate::device::DeviceType::Char,
427 }),
428 );
429 }
431 _ => {}
432 }
433 0
434}
435
436pub fn sys_fstat(
437 abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
438 trapframe: &mut crate::arch::Trapframe,
439) -> usize {
440 let fd = trapframe.get_arg(0) as usize;
441
442 let task = mytask().expect("sys_fstat: No current task found");
443 trapframe.increment_pc_next(task); let stat_ptr = task
446 .vm_manager
447 .translate_vaddr(trapframe.get_arg(1) as usize)
448 .expect("sys_fstat: Failed to translate stat pointer") as *mut Stat;
449
450 let handle = match abi.get_handle(fd) {
452 Some(h) => h,
453 None => return usize::MAX, };
455
456 let kernel_obj = match task.handle_table.get(handle) {
457 Some(obj) => obj,
458 None => return usize::MAX, };
460
461 let file = match kernel_obj.as_file() {
462 Some(file) => file,
463 None => return usize::MAX, };
465
466 let metadata = file
467 .metadata()
468 .expect("sys_fstat: Failed to get file metadata");
469
470 if stat_ptr.is_null() {
471 return usize::MAX; }
473
474 let stat = unsafe { &mut *stat_ptr };
475
476 *stat = Stat {
477 dev: 0,
478 ino: metadata.file_id as u32,
479 file_type: match metadata.file_type {
480 FileType::Directory => 1, FileType::RegularFile => 2, FileType::CharDevice(_) => 3, FileType::BlockDevice(_) => 3, _ => 0, },
486 nlink: 1,
487 size: metadata.size as u64,
488 };
489
490 0
491}
492
493pub fn sys_mkdir(
494 _abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
495 trapframe: &mut Trapframe,
496) -> usize {
497 let task = mytask().unwrap();
498 trapframe.increment_pc_next(task);
499
500 let path_ptr = task
501 .vm_manager
502 .translate_vaddr(trapframe.get_arg(0))
503 .unwrap() as *const u8;
504 let path = match get_path_str_v2(path_ptr) {
505 Ok(p) => to_absolute_path_v2(&task, &p).unwrap(),
506 Err(_) => return usize::MAX, };
508
509 let vfs = task.vfs.read().clone().unwrap();
511 match vfs.create_dir(&path) {
512 Ok(_) => 0, Err(_) => usize::MAX, }
515}
516
517pub fn sys_unlink(
518 _abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
519 trapframe: &mut Trapframe,
520) -> usize {
521 let task = mytask().unwrap();
522 trapframe.increment_pc_next(task);
523
524 let path_ptr = task
525 .vm_manager
526 .translate_vaddr(trapframe.get_arg(0))
527 .unwrap() as *const u8;
528 let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
529 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
530 Err(_) => return usize::MAX, };
532
533 let vfs = task.vfs.read().clone().unwrap();
535 match vfs.remove(&path) {
536 Ok(_) => 0, Err(_) => usize::MAX, }
539}
540
541pub fn sys_link(
542 _abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi,
543 trapframe: &mut Trapframe,
544) -> usize {
545 let task = mytask().unwrap();
546 trapframe.increment_pc_next(task);
547
548 let src_path_ptr = task
549 .vm_manager
550 .translate_vaddr(trapframe.get_arg(0))
551 .unwrap() as *const u8;
552 let dst_path_ptr = task
553 .vm_manager
554 .translate_vaddr(trapframe.get_arg(1))
555 .unwrap() as *const u8;
556
557 let src_path = match cstring_to_string(src_path_ptr, MAX_PATH_LENGTH) {
558 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
559 Err(_) => return usize::MAX, };
561
562 let dst_path = match cstring_to_string(dst_path_ptr, MAX_PATH_LENGTH) {
563 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
564 Err(_) => return usize::MAX, };
566
567 let vfs = task.vfs.read().clone().unwrap();
568 match vfs.create_hardlink(&src_path, &dst_path) {
569 Ok(_) => 0, Err(err) => {
571 use crate::fs::FileSystemErrorKind;
572
573 match err.kind {
575 FileSystemErrorKind::NotFound => {
576 2 }
579 FileSystemErrorKind::FileExists => {
580 17 }
583 FileSystemErrorKind::CrossDevice => {
584 18 }
587 FileSystemErrorKind::InvalidOperation => {
588 1 }
591 FileSystemErrorKind::PermissionDenied => {
592 13 }
594 _ => {
595 5 }
598 }
599 }
600 }
601}
602
603fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
606 if path.starts_with('/') {
607 Ok(path.to_string())
608 } else {
609 let vfs = task.vfs.read().clone().ok_or(())?;
610 Ok(vfs.resolve_path_to_absolute(path))
611 }
612}
613
614fn get_path_str_v2(ptr: *const u8) -> Result<String, ()> {
617 const MAX_PATH_LENGTH: usize = 128;
618 cstring_to_string(ptr, MAX_PATH_LENGTH)
619 .map(|(s, _)| s)
620 .map_err(|_| ())
621}