1use core::{ffi::CStr, mem};
2
3use alloc::{borrow::Cow, string::String, vec::Vec};
4use kernel_user_link::{
5 clock::ClockType,
6 file::{BlockingMode, DirEntry, FileMeta, OpenOptions, SeekFrom, SeekWhence},
7 graphics::{BlitCommand, FrameBufferInfo, GraphicsCommand},
8 process::{PriorityLevel, SpawnFileMapping},
9 sys_arg,
10 syscalls::{
11 syscall_arg_to_u64, syscall_handler_wrapper, SyscallArgError, SyscallError, SyscallResult,
12 NUM_SYSCALLS,
13 },
14 to_arg_err, verify_args, FD_STDERR,
15};
16
17use crate::{
18 cpu::{self, idt::InterruptAllSavedState},
19 devices::{self, clock},
20 executable::elf::Elf,
21 fs::{self, path::Path, FileSystemError},
22 graphics,
23 memory_management::memory_layout::{is_aligned, PAGE_4K},
24 process::{scheduler, Process},
25};
26
27use super::scheduler::{
28 exit_current_process, sleep_current_process, with_current_process, with_process,
29};
30
31type Syscall = fn(&mut InterruptAllSavedState) -> SyscallResult;
32
33const SYSCALLS: [Syscall; NUM_SYSCALLS] = [
34 sys_open, sys_write, sys_read, sys_close, sys_blocking_mode, sys_exit, sys_spawn, sys_inc_heap, sys_create_pipe, sys_wait_pid, sys_stat, sys_open_dir, sys_read_dir, sys_get_cwd, sys_chdir, sys_set_file_meta, sys_get_file_meta, sys_sleep, sys_get_time, sys_graphics, sys_seek, sys_priority, ];
57
58impl From<FileSystemError> for SyscallError {
59 fn from(e: FileSystemError) -> Self {
60 match e {
61 FileSystemError::InvalidPath => SyscallError::CouldNotOpenFile,
62 FileSystemError::FileNotFound => SyscallError::FileNotFound,
63 FileSystemError::ReadNotSupported => SyscallError::CouldNotReadFromFile,
64 FileSystemError::WriteNotSupported | FileSystemError::CouldNotSetFileLength => SyscallError::CouldNotWriteToFile,
65 FileSystemError::EndOfFile => SyscallError::EndOfFile,
66 FileSystemError::IsNotDirectory => SyscallError::IsNotDirectory,
67 FileSystemError::IsDirectory => SyscallError::IsDirectory,
68 FileSystemError::AlreadyExists => SyscallError::AlreadyExists,
69 FileSystemError::BufferNotLargeEnough(_) => SyscallError::BufferTooSmall,
70 FileSystemError::OperationNotSupported => SyscallError::OperationNotSupported,
71 FileSystemError::DiskReadError { .. }
72 | FileSystemError::FatError(_)
73 | FileSystemError::MappingError(_)
74 | FileSystemError::DeviceNotFound
75 | FileSystemError::MustBeAbsolute | FileSystemError::PartitionTableNotFound => panic!("should not happen?"),
77 }
78 }
79}
80
81impl From<clock::ClockTime> for kernel_user_link::clock::ClockTime {
82 fn from(time: clock::ClockTime) -> Self {
83 assert!(time.nanoseconds < clock::NANOS_PER_SEC);
84 Self {
85 seconds: time.seconds,
86 nanoseconds: time.nanoseconds as u32,
87 }
88 }
89}
90
91#[inline]
92fn check_ptr(arg: *const u8, len: usize) -> Result<(), SyscallArgError> {
93 if arg.is_null() {
94 return Err(SyscallArgError::InvalidUserPointer);
95 }
96 if !with_current_process(|process| {
97 process.is_user_address_mapped(arg as _)
98 && process.is_user_address_mapped(arg as usize + len - 1 )
101 }) {
102 return Err(SyscallArgError::InvalidUserPointer);
103 }
104 Ok(())
105}
106
107#[inline]
108fn ptr_as_mut<T>(ptr: *mut u8) -> Result<*mut T, SyscallArgError> {
109 check_ptr(ptr as *const u8, mem::size_of::<T>())?;
110 Ok(ptr as *mut T)
111}
112
113#[inline]
114fn ptr_as_ref<T>(ptr: *const u8) -> Result<*const T, SyscallArgError> {
115 check_ptr(ptr, mem::size_of::<T>())?;
116 Ok(ptr as *const T)
117}
118
119fn sys_arg_to_str<'a>(arg: *const u8) -> Result<&'a str, SyscallArgError> {
121 check_ptr(arg, 1)?;
122
123 let slice = unsafe { CStr::from_ptr(arg as _) };
124 let string = CStr::to_str(slice).map_err(|_| SyscallArgError::NotValidUtf8)?;
125 Ok(string)
126}
127
128fn sys_arg_to_path<'a>(arg: *const u8) -> Result<&'a Path, SyscallArgError> {
129 sys_arg_to_str(arg).map(Path::new)
130}
131
132fn sys_arg_to_slice<'a, T: Sized>(buf: *const u8, len: usize) -> Result<&'a [T], SyscallArgError> {
133 if len == 0 {
134 return Ok(&[]);
135 }
136
137 check_ptr(buf, len * mem::size_of::<T>())?;
138
139 let slice = unsafe { core::slice::from_raw_parts(buf as _, len) };
140 Ok(slice)
141}
142
143fn sys_arg_to_mut_slice<'a, T: Sized>(
144 buf: *mut u8,
145 len: usize,
146) -> Result<&'a mut [T], SyscallArgError> {
147 if len == 0 {
148 return Ok(&mut []);
149 }
150
151 check_ptr(buf, len * mem::size_of::<T>())?;
152
153 let slice = unsafe { core::slice::from_raw_parts_mut(buf as _, len) };
154 Ok(slice)
155}
156
157fn sys_arg_to_str_array(array_ptr: *const u8) -> Result<Vec<String>, SyscallArgError> {
159 let array_ptr = ptr_as_ref::<*const u8>(array_ptr)?;
160
161 let mut array = Vec::new();
162 let mut i = 0;
163 loop {
164 let ptr = unsafe { *array_ptr.offset(i) };
165 if ptr.is_null() {
166 break;
167 }
168 let str = sys_arg_to_str(ptr)?;
169 if str.is_empty() {
170 break;
171 }
172 array.push(String::from(str));
173 i += 1;
174 }
175
176 Ok(array)
177}
178
179fn sys_arg_to_file_mappings_array<'a>(
181 array_ptr: *const u8,
182 array_size: usize,
183) -> Result<&'a [SpawnFileMapping], SyscallArgError> {
184 let mappings_array = sys_arg_to_slice::<SpawnFileMapping>(array_ptr, array_size)?;
185
186 for i in 0..array_size {
187 let mapping = mappings_array[i];
188
189 for other_mapping in mappings_array.iter().take(i) {
191 if mapping.src_fd == other_mapping.src_fd || mapping.dst_fd == other_mapping.dst_fd {
192 return Err(SyscallArgError::DuplicateFileMappings);
193 }
194 }
195 }
196
197 Ok(mappings_array)
198}
199
200fn path_to_proc_absolute_path(path: &Path) -> Cow<'_, Path> {
203 let absolute_path = if path.is_absolute() {
204 Cow::Borrowed(path)
205 } else {
206 let current_dir =
207 with_current_process(|process| process.get_current_dir().path().to_path_buf());
208 Cow::Owned(current_dir.join(path))
209 };
210 assert!(absolute_path.is_absolute());
211
212 absolute_path
213}
214
215fn sys_open(all_state: &mut InterruptAllSavedState) -> SyscallResult {
216 let (path, open_options, flags, ..) = verify_args! {
217 sys_arg!(0, all_state.rest => sys_arg_to_path(*const u8)),
218 sys_arg!(1, all_state.rest => u64),
219 sys_arg!(2, all_state.rest => u64),
220 };
221
222 let open_options = OpenOptions::from_u64(open_options)
223 .ok_or(to_arg_err!(1, SyscallArgError::GeneralInvalid))?;
224
225 let blocking_mode = kernel_user_link::file::parse_flags(flags)
226 .ok_or(to_arg_err!(2, SyscallArgError::GeneralInvalid))?;
227
228 let absolute_path = path_to_proc_absolute_path(path);
229 let file = fs::File::open_blocking(absolute_path, blocking_mode, open_options)?;
230 let file_index = with_current_process(|process| process.push_fs_node(file));
231
232 SyscallResult::Ok(file_index as u64)
233}
234
235fn sys_write(all_state: &mut InterruptAllSavedState) -> SyscallResult {
236 let (file_index, buf, size, ..) = verify_args! {
237 sys_arg!(0, all_state.rest => usize),
238 sys_arg!(1, all_state.rest => *const u8),
239 sys_arg!(2, all_state.rest => usize),
240 };
241 let buf = sys_arg_to_slice(buf, size).map_err(|err| to_arg_err!(0, err))?;
242 let bytes_written = with_current_process(|process| -> Result<u64, SyscallError> {
243 let file = process
244 .get_fs_node(file_index)
245 .ok_or(SyscallError::InvalidFileIndex)?;
246
247 file.as_file_mut()?.write(buf).map_err(|e| e.into())
248 })?;
249 SyscallResult::Ok(bytes_written)
250}
251
252fn sys_read(all_state: &mut InterruptAllSavedState) -> SyscallResult {
253 let (file_index, buf, size, ..) = verify_args! {
254 sys_arg!(0, all_state.rest => usize),
255 sys_arg!(1, all_state.rest => *mut u8),
256 sys_arg!(2, all_state.rest => usize),
257 };
258 let buf = sys_arg_to_mut_slice(buf, size).map_err(|err| to_arg_err!(0, err))?;
259
260 let (bytes_read, file) = with_current_process(|process| {
274 let file = process
275 .get_fs_node(file_index)
276 .ok_or(SyscallError::InvalidFileIndex)?
277 .as_file_mut()?;
278 if file.is_blocking() {
279 let file = process
281 .take_fs_node(file_index)
282 .ok_or(SyscallError::InvalidFileIndex)?;
283 Ok((0, Some(file)))
284 } else {
285 let bytes_read = file.read(buf)?;
286 Ok::<_, SyscallError>((bytes_read, None))
287 }
288 })?;
289
290 let bytes_read = if let Some(mut file) = file {
291 let bytes_read = file.as_file_mut()?.read(buf)?;
292 with_current_process(|process| process.put_fs_node(file_index, file));
294 bytes_read
295 } else {
296 bytes_read
297 };
298 SyscallResult::Ok(bytes_read)
299}
300
301fn sys_close(all_state: &mut InterruptAllSavedState) -> SyscallResult {
302 let (file_index, ..) = verify_args! {
303 sys_arg!(0, all_state.rest => usize),
304 };
305
306 with_current_process(|process| {
307 process
308 .take_fs_node(file_index)
309 .ok_or(SyscallError::InvalidFileIndex)?;
310 Ok::<_, SyscallError>(())
311 })?;
312
313 SyscallResult::Ok(0)
314}
315
316fn sys_blocking_mode(all_state: &mut InterruptAllSavedState) -> SyscallResult {
317 let (file_index, blocking_mode, ..) = verify_args! {
318 sys_arg!(0, all_state.rest => usize),
319 sys_arg!(1, all_state.rest => u64),
320 };
321
322 let blocking_mode = BlockingMode::try_from(blocking_mode)
323 .map_err(|_| to_arg_err!(1, SyscallArgError::GeneralInvalid))?;
324
325 with_current_process(|process| {
326 let file = process
327 .get_fs_node(file_index)
328 .ok_or(SyscallError::InvalidFileIndex)?;
329 file.as_file_mut()?.set_blocking(blocking_mode);
330 Ok::<_, SyscallError>(())
331 })?;
332
333 SyscallResult::Ok(0)
334}
335
336fn sys_exit(all_state: &mut InterruptAllSavedState) -> SyscallResult {
337 let (exit_code, ..) = verify_args! {
338 sys_arg!(0, all_state.rest => i32),
339 };
340
341 exit_current_process(exit_code, all_state);
343 SyscallResult::Ok(exit_code as u64)
344}
345
346fn sys_spawn(all_state: &mut InterruptAllSavedState) -> SyscallResult {
347 let (path, argv, file_mappings, file_mappings_size, ..) = verify_args! {
348 sys_arg!(0, all_state.rest => sys_arg_to_path(*const u8)),
349 sys_arg!(1, all_state.rest => *const u8), sys_arg!(2, all_state.rest => *const u8), sys_arg!(3, all_state.rest => usize), };
353 let argv = sys_arg_to_str_array(argv).map_err(|err| to_arg_err!(1, err))?;
354 let file_mappings = sys_arg_to_file_mappings_array(file_mappings, file_mappings_size)
355 .map_err(|err| to_arg_err!(2, err))?;
356
357 if !file_mappings.is_empty() {
359 with_current_process(|process| {
361 for mapping in file_mappings {
362 process
363 .get_fs_node(mapping.src_fd)
364 .ok_or(SyscallError::InvalidFileIndex)?;
365 }
366 Ok::<_, SyscallError>(())
367 })?;
368 }
369
370 let absolute_path = path_to_proc_absolute_path(path);
371
372 let mut file = fs::File::open(absolute_path)?;
373 let elf = Elf::load(&mut file).map_err(|_| SyscallError::CouldNotLoadElf)?;
374 let (current_pid, current_dir) =
375 with_current_process(|process| (process.id, process.get_current_dir().clone()));
376 let mut new_process =
377 Process::allocate_process(current_pid, &elf, &mut file, argv, current_dir)
378 .map_err(|_| SyscallError::CouldNotAllocateProcess)?;
379
380 let mut std_needed = [true; 3];
381 with_current_process(|process| {
382 for mapping in file_mappings.iter() {
384 let file = process
385 .take_fs_node(mapping.src_fd)
386 .ok_or(SyscallError::InvalidFileIndex)?;
387 new_process.attach_fs_node_to_fd(mapping.dst_fd, file);
388 if mapping.dst_fd <= FD_STDERR {
389 std_needed[mapping.dst_fd] = false;
390 }
391 }
392
393 for (i, _) in std_needed.iter().enumerate().filter(|(_, &b)| b) {
395 let file = process
396 .get_fs_node(i)
397 .ok_or(SyscallError::InvalidFileIndex)?;
398 let inherited_file = file.as_file()?.clone_inherit();
399 new_process.attach_fs_node_to_fd(i, inherited_file);
400 }
401
402 Ok::<_, SyscallError>(())
403 })?;
404
405 let new_pid = new_process.id();
406 new_process.finish_stdio();
408 scheduler::push_process(new_process);
409
410 SyscallResult::Ok(new_pid)
411}
412
413fn sys_inc_heap(all_state: &mut InterruptAllSavedState) -> SyscallResult {
414 let (increment, ..) = verify_args! {
415 sys_arg!(0, all_state.rest => i64),
416 };
417
418 if !is_aligned(increment.unsigned_abs(), PAGE_4K) {
419 return Err(to_arg_err!(0, SyscallArgError::InvalidHeapIncrement));
420 }
421
422 let old_heap_end = with_current_process(|process| process.add_to_heap(increment as isize))
423 .ok_or(SyscallError::HeapRangesExceeded)?;
424
425 SyscallResult::Ok(old_heap_end as u64)
426}
427
428fn sys_create_pipe(all_state: &mut InterruptAllSavedState) -> SyscallResult {
429 let (read_fd_ptr, write_fd_ptr, ..) = verify_args! {
430 sys_arg!(0, all_state.rest => *mut usize),
431 sys_arg!(1, all_state.rest => *mut usize),
432 };
433 let read_fd_ptr = ptr_as_mut(read_fd_ptr as *mut u8).map_err(|err| to_arg_err!(0, err))?;
434 let write_fd_ptr = ptr_as_mut(write_fd_ptr as *mut u8).map_err(|err| to_arg_err!(1, err))?;
435
436 let (read_file, write_file) = devices::pipe::create_pipe_pair();
437 let (read_fd, write_fd) = with_current_process(|process| {
438 (
439 process.push_fs_node(read_file),
440 process.push_fs_node(write_file),
441 )
442 });
443
444 unsafe {
445 *read_fd_ptr = read_fd;
446 *write_fd_ptr = write_fd;
447 }
448
449 SyscallResult::Ok(0)
450}
451
452fn sys_wait_pid(all_state: &mut InterruptAllSavedState) -> SyscallResult {
453 let (pid, block, ..) = verify_args! {
454 sys_arg!(0, all_state.rest => u64),
455 sys_arg!(1, all_state.rest => u64),
456 };
457 let block = block != 0;
458
459 let process_exit = with_current_process(|process| process.get_child_exit(pid));
461 if let Some(exit_code) = process_exit {
462 return SyscallResult::Ok(exit_code as u64);
463 }
464
465 if !block {
466 if scheduler::is_process_running(pid) {
467 return Err(SyscallError::ProcessStillRunning);
468 }
469 return Err(SyscallError::PidNotFound);
470 }
471
472 if !scheduler::wait_for_pid(all_state, pid) {
475 return Err(SyscallError::PidNotFound);
476 }
477 SyscallResult::Ok(0)
480}
481
482fn sys_stat(all_state: &mut InterruptAllSavedState) -> SyscallResult {
483 let (path, stat_ptr, ..) = verify_args! {
484 sys_arg!(0, all_state.rest => sys_arg_to_path(*const u8)),
485 sys_arg!(1, all_state.rest => *mut u8),
486 };
487 let stat_ptr = ptr_as_mut(stat_ptr).map_err(|err| to_arg_err!(1, err))?;
488
489 let absolute_path = path_to_proc_absolute_path(path);
490 let (_, _, inode) = fs::open_inode(absolute_path)?;
491
492 unsafe {
493 *stat_ptr = inode.as_file_stat();
494 }
495
496 SyscallResult::Ok(0)
497}
498
499fn sys_open_dir(all_state: &mut InterruptAllSavedState) -> SyscallResult {
500 let (path, ..) = verify_args! {
501 sys_arg!(0, all_state.rest => sys_arg_to_path(*const u8)),
502 };
503
504 let absolute_path = path_to_proc_absolute_path(path);
505 let dir = fs::Directory::open(absolute_path)?;
506 let dir_index = with_current_process(|process| process.push_fs_node(dir));
507
508 SyscallResult::Ok(dir_index as u64)
509}
510
511fn sys_read_dir(all_state: &mut InterruptAllSavedState) -> SyscallResult {
512 let (dir_index, buf, len, ..) = verify_args! {
513 sys_arg!(0, all_state.rest => usize),
514 sys_arg!(1, all_state.rest => *mut u8),
515 sys_arg!(2, all_state.rest => usize),
516 };
517 let buf = sys_arg_to_mut_slice::<DirEntry>(buf, len).map_err(|err| to_arg_err!(1, err))?;
518
519 let entries_read = with_current_process(|process| -> Result<usize, SyscallError> {
520 let file = process
521 .get_fs_node(dir_index)
522 .ok_or(SyscallError::InvalidFileIndex)?;
523 file.as_dir_mut()?.read(buf).map_err(|e| e.into())
524 })?;
525
526 SyscallResult::Ok(entries_read as u64)
527}
528
529fn sys_get_cwd(all_state: &mut InterruptAllSavedState) -> SyscallResult {
530 let (buf, len, ..) = verify_args! {
531 sys_arg!(0, all_state.rest => *mut u8),
532 sys_arg!(1, all_state.rest => usize),
533 };
534 let buf = sys_arg_to_mut_slice::<u8>(buf, len).map_err(|err| to_arg_err!(0, err))?;
535
536 let needed_bytes = with_current_process(|process| -> Result<usize, SyscallError> {
537 let cwd = process.get_current_dir().path();
538 let needed_bytes = cwd.as_str().len();
539 if needed_bytes > len {
540 return Err(SyscallError::BufferTooSmall);
541 }
542 buf[..needed_bytes].copy_from_slice(cwd.as_str().as_bytes());
543 Ok(needed_bytes)
544 })?;
545
546 SyscallResult::Ok(needed_bytes as u64)
547}
548
549fn sys_chdir(all_state: &mut InterruptAllSavedState) -> SyscallResult {
550 let (path, ..) = verify_args! {
551 sys_arg!(0, all_state.rest => sys_arg_to_path(*const u8)),
552 };
553
554 let absolute_path = path_to_proc_absolute_path(path);
555 let dir = fs::Directory::open(absolute_path)?;
556 with_current_process(|process| process.set_current_dir(dir));
557
558 SyscallResult::Ok(0)
559}
560
561fn sys_set_file_meta(all_state: &mut InterruptAllSavedState) -> SyscallResult {
562 let (file_index, meta_id, meta_data, ..) = verify_args! {
563 sys_arg!(0, all_state.rest => usize),
564 sys_arg!(1, all_state.rest => u64),
565 sys_arg!(2, all_state.rest => u64),
566 };
567
568 let meta_op = FileMeta::try_from((meta_id, meta_data))
569 .ok()
570 .ok_or(to_arg_err!(1, SyscallArgError::GeneralInvalid))?;
571
572 let op_on_file = |op: &dyn Fn(&mut fs::File)| {
573 with_current_process(|process| {
574 let file = process
575 .get_fs_node(file_index)
576 .ok_or(SyscallError::InvalidFileIndex)?;
577 op(file.as_file_mut()?);
578 Ok::<_, SyscallError>(())
579 })
580 };
581
582 match meta_op {
583 FileMeta::BlockingMode(blocking_mode) => {
584 op_on_file(&|file| file.set_blocking(blocking_mode))?;
585 }
586 FileMeta::IsTerminal(is_terminal) => {
587 op_on_file(&|file| file.set_terminal(is_terminal))?;
588 }
589 _ => {
590 return Err(to_arg_err!(1, SyscallArgError::GeneralInvalid));
591 }
592 }
593
594 SyscallResult::Ok(0)
595}
596
597fn sys_get_file_meta(all_state: &mut InterruptAllSavedState) -> SyscallResult {
598 let (file_index, meta_id, meta_data_ptr, ..) = verify_args! {
599 sys_arg!(0, all_state.rest => usize),
600 sys_arg!(1, all_state.rest => u64),
601 sys_arg!(2, all_state.rest => *mut u64),
602 };
603 let meta_data_ptr = ptr_as_mut(meta_data_ptr as *mut u8).map_err(|err| to_arg_err!(2, err))?;
604
605 let meta_op = FileMeta::try_from((meta_id, 0))
606 .ok()
607 .ok_or(to_arg_err!(1, SyscallArgError::GeneralInvalid))?;
608
609 let data = with_current_process(|process| {
610 let file = process
611 .get_fs_node(file_index)
612 .ok_or(SyscallError::InvalidFileIndex)?;
613
614 let meta_data = match meta_op {
615 FileMeta::BlockingMode(..) => file.as_file()?.blocking_mode().to_u64(),
616 FileMeta::IsTerminal(..) => file.as_file()?.is_terminal() as u64,
617 _ => {
618 return Err(to_arg_err!(1, SyscallArgError::GeneralInvalid));
619 }
620 };
621
622 Ok::<_, SyscallError>(meta_data)
623 })?;
624
625 unsafe { *meta_data_ptr = data }
627
628 SyscallResult::Ok(0)
629}
630
631fn sys_sleep(all_state: &mut InterruptAllSavedState) -> SyscallResult {
632 let (seconds, nanoseconds, ..) = verify_args! {
633 sys_arg!(0, all_state.rest => u64),
634 sys_arg!(1, all_state.rest => u64),
635 };
636
637 if nanoseconds >= clock::NANOS_PER_SEC {
638 return Err(to_arg_err!(1, SyscallArgError::InvalidNanoseconds));
639 }
640
641 let time = clock::ClockTime {
642 seconds,
643 nanoseconds,
644 };
645
646 all_state.rest.rax = 0;
648
649 sleep_current_process(time, all_state);
651
652 SyscallResult::Ok(0)
655}
656
657fn sys_get_time(all_state: &mut InterruptAllSavedState) -> SyscallResult {
658 let (time_type, time_ptr, ..) = verify_args! {
659 sys_arg!(0, all_state.rest => u64),
660 sys_arg!(1, all_state.rest => *mut u8),
661 };
662 let time_ptr: *mut kernel_user_link::clock::ClockTime =
663 ptr_as_mut(time_ptr).map_err(|err| to_arg_err!(1, err))?;
664
665 let time_type = ClockType::try_from(time_type)
666 .map_err(|_| to_arg_err!(0, SyscallArgError::GeneralInvalid))?;
667
668 let time = match time_type {
669 ClockType::RealTime => clock::clocks().time_since_unix_epoch().into(),
670 ClockType::SystemTime => clock::clocks().time_since_startup().into(),
671 };
672 unsafe {
674 *time_ptr = time;
675 }
676
677 SyscallResult::Ok(0)
678}
679
680fn sys_graphics(all_state: &mut InterruptAllSavedState) -> SyscallResult {
681 let (command_id, extra, ..) = verify_args! {
682 sys_arg!(0, all_state.rest => u64),
683 sys_arg!(1, all_state.rest => *mut u8)
684 };
685
686 let command = GraphicsCommand::from_u64(command_id)
687 .ok_or(to_arg_err!(0, SyscallArgError::GeneralInvalid))?;
688
689 let pid = cpu::cpu().process_id;
690
691 match command {
692 GraphicsCommand::TakeOwnership => {
693 if !graphics::vga::controller()
694 .ok_or(SyscallError::GraphicsNotAvailable)?
695 .take_ownership(pid)
696 {
697 return Err(SyscallError::GraphicsAlreadyTaken);
698 }
699 }
700 GraphicsCommand::ReleaseOwnership => {
701 if !graphics::vga::controller()
702 .ok_or(SyscallError::GraphicsNotAvailable)?
703 .release(pid)
704 {
705 return Err(SyscallError::GraphicsNotOwned);
706 }
707 }
708 GraphicsCommand::GetFrameBufferInfo => {
709 let info = *graphics::vga::controller()
710 .ok_or(SyscallError::GraphicsNotAvailable)?
711 .framebuffer_info();
712 let info_ptr =
713 ptr_as_mut::<FrameBufferInfo>(extra).map_err(|err| to_arg_err!(1, err))?;
714 unsafe {
716 *info_ptr = info;
717 }
718 }
719 GraphicsCommand::Blit => {
720 let blit = ptr_as_ref::<BlitCommand>(extra).map_err(|err| to_arg_err!(1, err))?;
721 let blit = unsafe { *blit };
723
724 let buffer_len = blit.src_framebuffer_info.memory_size();
725 let buffer = sys_arg_to_slice(blit.memory, buffer_len)
726 .map_err(|_| SyscallError::InvalidGraphicsBuffer)?;
727
728 graphics::vga::controller()
729 .ok_or(SyscallError::GraphicsNotAvailable)?
730 .lock_process(pid)
731 .ok_or(SyscallError::GraphicsNotOwned)?
732 .blit(
733 buffer,
734 &blit.src_framebuffer_info,
735 blit.src,
736 blit.dst,
737 blit.size.0,
738 blit.size.1,
739 );
740 }
741 c => panic!("invalid graphics command {c:?}"),
742 }
743
744 SyscallResult::Ok(0)
745}
746
747fn sys_seek(all_state: &mut InterruptAllSavedState) -> SyscallResult {
748 let (file_index, whence, offset, ..) = verify_args! {
749 sys_arg!(0, all_state.rest => usize),
750 sys_arg!(1, all_state.rest => u64),
751 sys_arg!(2, all_state.rest => i64),
752 };
753 let seek = SeekFrom {
754 whence: whence
755 .try_into()
756 .map_err(|_| to_arg_err!(1, SyscallArgError::GeneralInvalid))?,
757 offset,
758 };
759
760 let new_position = with_current_process(|process| {
761 let file = process
762 .get_fs_node(file_index)
763 .ok_or(SyscallError::InvalidFileIndex)?;
764 let file = file.as_file_mut()?;
765
766 let size = file.size();
767
768 let new_location: u64 = match seek.whence {
769 SeekWhence::Start => seek
770 .offset
771 .try_into()
772 .map_err(|_| SyscallError::InvalidOffset)?,
773 SeekWhence::Current => {
774 let current: i64 = file.current_position().try_into().expect(
775 "current position should be positive and would be less than i64 bit in size",
776 );
777 current
778 .checked_add(seek.offset)
779 .ok_or(SyscallError::InvalidOffset)?
780 .try_into()
781 .map_err(|_| SyscallError::InvalidOffset)?
782 }
783 SeekWhence::End => {
784 let end: i64 = size
785 .try_into()
786 .expect("size should be positive and would be less than i64 bit in size");
787 end.checked_add(seek.offset)
788 .ok_or(SyscallError::InvalidOffset)?
789 .try_into()
790 .map_err(|_| SyscallError::InvalidOffset)?
791 }
792 };
793
794 file.seek(new_location)?;
795
796 Ok::<_, SyscallError>(new_location)
797 })?;
798
799 SyscallResult::Ok(new_position)
800}
801
802fn sys_priority(all_state: &mut InterruptAllSavedState) -> SyscallResult {
805 let (pid, priority_level, ..) = verify_args! {
806 sys_arg!(0, all_state.rest => u64),
807 sys_arg!(1, all_state.rest => u64),
808 };
809
810 let priority_level = if priority_level == 0 {
812 None
813 } else {
814 Some(
815 PriorityLevel::from_u64(priority_level)
816 .ok_or(to_arg_err!(1, SyscallArgError::GeneralInvalid))?,
817 )
818 };
819
820 let current_priority = with_process(pid, |process| {
821 if let Some(priority_level) = priority_level {
822 process.set_priority(priority_level);
823 }
824
825 Ok::<_, SyscallError>(process.get_priority())
826 })?;
827
828 SyscallResult::Ok(current_priority.to_u64())
829}
830
831pub fn handle_syscall(all_state: &mut InterruptAllSavedState) {
832 let syscall_number = all_state.rest.rax;
833
834 all_state.rest.rax = syscall_handler_wrapper(syscall_number, || {
837 let syscall_func = SYSCALLS[syscall_number as usize];
838 syscall_func(all_state)
839 });
840
841 crate::scheduler::yield_current_if_any(all_state);
842}