167 lines
4.7 KiB
Rust

//! System function call handlers
use core::time::Duration;
use abi::{
error::Error,
io::{OpenFlags, RawFd},
syscall::SyscallFunction,
};
use vfs::{Read, Write};
use yggdrasil_abi::{
error::SyscallResult,
io::{MountOptions, UnmountOptions},
};
use crate::{
fs,
mem::table::{PageAttributes, VirtualMemoryManager},
proc::wait,
task::process::Process,
};
mod arg;
use arg::*;
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
match func {
SyscallFunction::DebugTrace => {
let pid = Process::get_current()
.as_deref()
.map(Process::id)
.unwrap_or(0);
let arg = arg_user_str(args[0] as usize, args[1] as usize)?;
debugln!("[{}] TRACE: {:?}", pid, arg);
Ok(0)
}
SyscallFunction::Nanosleep => {
let seconds = args[0];
let nanos = args[1] as u32;
let duration = Duration::new(seconds, nanos);
let mut remaining = Duration::ZERO;
wait::sleep(duration, &mut remaining).unwrap();
Ok(0)
}
SyscallFunction::Exit => {
Process::current().exit(args[0] as _);
panic!();
}
SyscallFunction::MapMemory => {
let len = args[1] as usize;
let proc = Process::current();
let space = proc.address_space();
if len & 0xFFF != 0 {
todo!();
}
let addr = space.allocate(None, len / 0x1000, PageAttributes::AP_BOTH_READWRITE);
debugln!("mmap({:#x}) = {:x?}", len, addr);
addr
}
SyscallFunction::UnmapMemory => {
let addr = args[0] as usize;
let len = args[1] as usize;
let proc = Process::current();
let space = proc.address_space();
if len & 0xFFF != 0 {
todo!();
}
debugln!("munmap({:#x}, {:#x})", addr, len);
space.deallocate(addr, len)?;
Ok(0)
}
SyscallFunction::Write => {
let fd = RawFd(args[0] as u32);
let data = arg_buffer_ref(args[1] as _, args[2] as _)?;
let proc = Process::current();
let io = proc.io.lock();
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.write(data)
}
SyscallFunction::Read => {
let fd = RawFd(args[0] as u32);
let data = arg_buffer_mut(args[1] as _, args[2] as _)?;
let proc = Process::current();
let io = proc.io.lock();
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.read(data)
}
SyscallFunction::Open => {
let path = arg_user_str(args[0] as usize, args[1] as usize)?;
let opts = OpenFlags(args[2] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
let file = io.ioctx().open(None, path, opts)?;
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
}
SyscallFunction::Close => {
let fd = RawFd(args[0] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
io.close_file(fd)?;
Ok(0)
}
SyscallFunction::Mount => {
let options = arg_user_ref::<MountOptions>(args[0] as usize)?;
let proc = Process::current();
let mut io = proc.io.lock();
let target_node = io.ioctx().find(None, options.target, true, false)?;
if !target_node.is_directory() {
return Err(Error::NotADirectory);
}
let fs_root = fs::create_filesystem(options)?;
target_node.mount(fs_root)?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
}
SyscallFunction::Unmount => {
let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
let proc = Process::current();
let mut io = proc.io.lock();
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
mountpoint.unmount_target()?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
}
}
}
/// Entrypoint for system calls that takes raw argument values
pub fn raw_syscall_handler(func: u64, args: &[u64]) -> u64 {
let Ok(func) = SyscallFunction::try_from(func as usize) else {
todo!("Undefined syscall: {}", func);
};
syscall_handler(func, args).into_syscall_result() as u64
}