feature: better ABI for system call numbers
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::mem;
|
||||
use crate::proc::{sched, Thread, Process};
|
||||
use crate::syscall;
|
||||
use cortex_a::registers::{ESR_EL1, FAR_EL1};
|
||||
use libsys::{abi, signal::Signal};
|
||||
use libsys::{abi::SystemCall, signal::Signal};
|
||||
use tock_registers::interfaces::Readable;
|
||||
|
||||
/// Trapped SIMD/FP functionality
|
||||
@@ -116,24 +116,30 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) {
|
||||
dump_data_abort(Level::Error, esr, far as u64);
|
||||
}
|
||||
EC_SVC_AA64 => {
|
||||
unsafe {
|
||||
if exc.x[8] == abi::SYS_FORK {
|
||||
match syscall::sys_fork(exc) {
|
||||
Ok(pid) => exc.x[0] = pid.value() as usize,
|
||||
Err(err) => {
|
||||
exc.x[0] = err.to_negative_isize() as usize;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
let num = SystemCall::from_repr(exc.x[8]);
|
||||
if num.is_none() {
|
||||
todo!();
|
||||
return;
|
||||
}
|
||||
let num = num.unwrap();
|
||||
|
||||
match syscall::syscall(exc.x[8], &exc.x[..6]) {
|
||||
Ok(val) => exc.x[0] = val,
|
||||
if num == SystemCall::Fork {
|
||||
match unsafe { syscall::sys_fork(exc) } {
|
||||
Ok(pid) => exc.x[0] = pid.value() as usize,
|
||||
Err(err) => {
|
||||
exc.x[0] = err.to_negative_isize() as usize;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
match syscall::syscall(num, &exc.x[..6]) {
|
||||
Ok(val) => exc.x[0] = val,
|
||||
Err(err) => {
|
||||
exc.x[0] = err.to_negative_isize() as usize;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+111
-112
@@ -8,7 +8,7 @@ use core::mem::size_of;
|
||||
use core::ops::DerefMut;
|
||||
use core::time::Duration;
|
||||
use libsys::{
|
||||
abi,
|
||||
abi::SystemCall,
|
||||
error::Errno,
|
||||
ioctl::IoctlCmd,
|
||||
proc::{ExitCode, Pid},
|
||||
@@ -52,23 +52,26 @@ fn find_at_node<T: DerefMut<Target = ProcessIo>>(
|
||||
}
|
||||
|
||||
/// Main system call dispatcher function
|
||||
pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
match num {
|
||||
// Process management system calls
|
||||
abi::SYS_EXIT => {
|
||||
Process::exit(ExitCode::from(args[0] as i32));
|
||||
unreachable!();
|
||||
}
|
||||
abi::SYS_EX_THREAD_EXIT => {
|
||||
Process::exit_thread(Thread::current(), ExitCode::from(args[0] as i32));
|
||||
unreachable!();
|
||||
},
|
||||
abi::SYS_EX_GETTID => {
|
||||
Ok(Thread::current().id() as usize)
|
||||
},
|
||||
// I/O
|
||||
SystemCall::Read => {
|
||||
let proc = Process::current();
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let mut io = proc.io.lock();
|
||||
let buf = validate_user_ptr(args[1], args[2])?;
|
||||
|
||||
// I/O system calls
|
||||
abi::SYS_OPENAT => {
|
||||
io.file(fd)?.borrow_mut().read(buf)
|
||||
},
|
||||
SystemCall::Write => {
|
||||
let proc = Process::current();
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let mut io = proc.io.lock();
|
||||
let buf = validate_user_ptr(args[1], args[2])?;
|
||||
|
||||
io.file(fd)?.borrow_mut().write(buf)
|
||||
},
|
||||
SystemCall::Open => {
|
||||
let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
|
||||
let path = validate_user_str(args[1], args[2])?;
|
||||
let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
@@ -85,24 +88,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
|
||||
let file = io.ioctx().open(at, path, mode, opts)?;
|
||||
Ok(u32::from(io.place_file(file)?) as usize)
|
||||
}
|
||||
abi::SYS_READ => {
|
||||
},
|
||||
SystemCall::Close => {
|
||||
let proc = Process::current();
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let mut io = proc.io.lock();
|
||||
let buf = validate_user_ptr(args[1], args[2])?;
|
||||
|
||||
io.file(fd)?.borrow_mut().read(buf)
|
||||
}
|
||||
abi::SYS_WRITE => {
|
||||
let proc = Process::current();
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let mut io = proc.io.lock();
|
||||
let buf = validate_user_ptr(args[1], args[2])?;
|
||||
|
||||
io.file(fd)?.borrow_mut().write(buf)
|
||||
}
|
||||
abi::SYS_FSTATAT => {
|
||||
io.close_file(fd)?;
|
||||
Ok(0)
|
||||
},
|
||||
SystemCall::FileStatus => {
|
||||
let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
|
||||
let filename = validate_user_str(args[1], args[2])?;
|
||||
let buf = validate_user_ptr_struct::<Stat>(args[3])?;
|
||||
@@ -112,16 +107,52 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
let mut io = proc.io.lock();
|
||||
find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat(buf)?;
|
||||
Ok(0)
|
||||
}
|
||||
abi::SYS_CLOSE => {
|
||||
},
|
||||
SystemCall::Ioctl => {
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let cmd = IoctlCmd::try_from(args[1] as u32)?;
|
||||
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
|
||||
io.close_file(fd)?;
|
||||
let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?;
|
||||
node.ioctl(cmd, args[2], args[3])
|
||||
},
|
||||
SystemCall::Select => {
|
||||
let rfds = validate_user_ptr_struct_option::<FdSet>(args[0])?;
|
||||
let wfds = validate_user_ptr_struct_option::<FdSet>(args[1])?;
|
||||
let timeout = if args[2] == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Duration::from_nanos(args[2] as u64))
|
||||
};
|
||||
|
||||
wait::select(Thread::current(), rfds, wfds, timeout)
|
||||
},
|
||||
SystemCall::Access => {
|
||||
let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
|
||||
let path = validate_user_str(args[1], args[2])?;
|
||||
let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
let flags = args[4] as u32;
|
||||
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?;
|
||||
Ok(0)
|
||||
}
|
||||
abi::SYS_EXECVE => {
|
||||
},
|
||||
|
||||
// Process
|
||||
SystemCall::Clone => {
|
||||
let entry = args[0];
|
||||
let stack = args[1];
|
||||
let arg = args[2];
|
||||
|
||||
Process::current()
|
||||
.new_user_thread(entry, stack, arg)
|
||||
.map(|e| e as usize)
|
||||
},
|
||||
SystemCall::Exec => {
|
||||
let node = {
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
@@ -134,8 +165,20 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
let file = node.open(OpenFlags::O_RDONLY)?;
|
||||
Process::execve(|space| elf::load_elf(space, file), 0).unwrap();
|
||||
panic!();
|
||||
}
|
||||
abi::SYS_WAITPID => {
|
||||
},
|
||||
SystemCall::Exit => {
|
||||
let status = ExitCode::from(args[0] as i32);
|
||||
let flags = args[1];
|
||||
|
||||
if flags & (1 << 0) != 0 {
|
||||
Process::exit_thread(Thread::current(), status);
|
||||
} else {
|
||||
Process::exit(status);
|
||||
}
|
||||
|
||||
unreachable!();
|
||||
},
|
||||
SystemCall::WaitPid => {
|
||||
// TODO special "pid" values
|
||||
let pid = unsafe { Pid::from_raw(args[0] as u32) };
|
||||
let status = validate_user_ptr_struct::<i32>(args[1])?;
|
||||
@@ -147,8 +190,8 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
abi::SYS_EX_THREAD_WAIT => {
|
||||
},
|
||||
SystemCall::WaitTid => {
|
||||
let tid = args[0] as u32;
|
||||
|
||||
match Thread::waittid(tid) {
|
||||
@@ -158,28 +201,9 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
_ => todo!(),
|
||||
}
|
||||
},
|
||||
abi::SYS_IOCTL => {
|
||||
let fd = FileDescriptor::from(args[0] as u32);
|
||||
let cmd = IoctlCmd::try_from(args[1] as u32)?;
|
||||
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?;
|
||||
node.ioctl(cmd, args[2], args[3])
|
||||
}
|
||||
|
||||
// Extra system calls
|
||||
abi::SYS_EX_DEBUG_TRACE => {
|
||||
let buf = validate_user_ptr(args[0], args[1])?;
|
||||
print!(Level::Debug, "[trace] ");
|
||||
for &byte in buf.iter() {
|
||||
print!(Level::Debug, "{}", byte as char);
|
||||
}
|
||||
println!(Level::Debug, "");
|
||||
Ok(args[1])
|
||||
}
|
||||
abi::SYS_EX_NANOSLEEP => {
|
||||
SystemCall::GetPid => todo!(),
|
||||
SystemCall::GetTid => Ok(Thread::current().id() as usize),
|
||||
SystemCall::Sleep => {
|
||||
let rem_buf = validate_user_ptr_null(args[1], size_of::<u64>() * 2)?;
|
||||
let mut rem = Duration::new(0, 0);
|
||||
let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem);
|
||||
@@ -190,16 +214,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
}
|
||||
}
|
||||
res.map(|_| 0)
|
||||
}
|
||||
abi::SYS_EX_SIGNAL => {
|
||||
},
|
||||
SystemCall::SetSignalEntry => {
|
||||
Thread::current().set_signal_entry(args[0], args[1]);
|
||||
Ok(0)
|
||||
}
|
||||
abi::SYS_EX_SIGRETURN => {
|
||||
},
|
||||
SystemCall::SignalReturn => {
|
||||
Thread::current().return_from_signal();
|
||||
panic!("This code won't run");
|
||||
}
|
||||
abi::SYS_EX_KILL => {
|
||||
unreachable!();
|
||||
},
|
||||
SystemCall::SendSignal => {
|
||||
let target = SignalDestination::from(args[0] as isize);
|
||||
let signal = Signal::try_from(args[1] as u32)?;
|
||||
|
||||
@@ -211,55 +235,30 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
_ => todo!(),
|
||||
};
|
||||
Ok(0)
|
||||
}
|
||||
abi::SYS_EX_CLONE => {
|
||||
let entry = args[0];
|
||||
let stack = args[1];
|
||||
let arg = args[2];
|
||||
|
||||
Process::current()
|
||||
.new_user_thread(entry, stack, arg)
|
||||
.map(|e| e as usize)
|
||||
}
|
||||
abi::SYS_EX_YIELD => {
|
||||
},
|
||||
SystemCall::Yield => {
|
||||
proc::switch();
|
||||
Ok(0)
|
||||
},
|
||||
|
||||
abi::SYS_SELECT => {
|
||||
let rfds = validate_user_ptr_struct_option::<FdSet>(args[0])?;
|
||||
let wfds = validate_user_ptr_struct_option::<FdSet>(args[1])?;
|
||||
let timeout = if args[2] == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Duration::from_nanos(args[2] as u64))
|
||||
};
|
||||
|
||||
wait::select(Thread::current(), rfds, wfds, timeout)
|
||||
}
|
||||
abi::SYS_FACCESSAT => {
|
||||
let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
|
||||
let path = validate_user_str(args[1], args[2])?;
|
||||
let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
let flags = args[4] as u32;
|
||||
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?;
|
||||
Ok(0)
|
||||
},
|
||||
abi::SYS_EX_GETCPUTIME => {
|
||||
// System
|
||||
SystemCall::GetCpuTime => {
|
||||
let time = machine::local_timer().timestamp()?;
|
||||
Ok(time.as_nanos() as usize)
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
let thread = Thread::current();
|
||||
let proc = thread.owner().unwrap();
|
||||
errorln!("Undefined system call: {}", num);
|
||||
proc.enter_fault_signal(thread, Signal::InvalidSystemCall);
|
||||
Err(Errno::InvalidArgument)
|
||||
}
|
||||
// Debugging
|
||||
SystemCall::DebugTrace => {
|
||||
let buf = validate_user_ptr(args[0], args[1])?;
|
||||
print!(Level::Debug, "[trace] ");
|
||||
for &byte in buf.iter() {
|
||||
print!(Level::Debug, "{}", byte as char);
|
||||
}
|
||||
println!(Level::Debug, "");
|
||||
Ok(args[1])
|
||||
},
|
||||
|
||||
// Handled elsewhere
|
||||
SystemCall::Fork => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user