Files
asterinas/kernel/src/syscall/mod.rs
2024-12-15 16:37:40 +08:00

368 lines
8.7 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
//! Read the Cpu ctx content then dispatch syscall to corresponding handler
//! The each sub module contains functions that handle real syscall logic.
pub use clock_gettime::ClockId;
use ostd::cpu::UserContext;
use crate::{context::Context, cpu::LinuxAbi, prelude::*};
mod accept;
mod access;
mod alarm;
mod arch;
mod arch_prctl;
mod bind;
mod brk;
mod capget;
mod capset;
mod chdir;
mod chmod;
mod chown;
mod chroot;
mod clock_gettime;
mod clone;
mod close;
mod connect;
mod constants;
mod dup;
mod epoll;
mod eventfd;
mod execve;
mod exit;
mod exit_group;
mod fallocate;
mod fcntl;
mod flock;
mod fork;
mod fsync;
mod futex;
mod getcwd;
mod getdents64;
mod getegid;
mod geteuid;
mod getgid;
mod getgroups;
mod getpeername;
mod getpgid;
mod getpgrp;
mod getpid;
mod getppid;
mod getrandom;
mod getresgid;
mod getresuid;
mod getrusage;
mod getsid;
mod getsockname;
mod getsockopt;
mod gettid;
mod gettimeofday;
mod getuid;
mod ioctl;
mod kill;
mod link;
mod listen;
mod lseek;
mod madvise;
mod mkdir;
mod mknod;
mod mmap;
mod mount;
mod mprotect;
mod msync;
mod munmap;
mod nanosleep;
mod open;
mod pause;
mod pipe;
mod poll;
mod prctl;
mod pread64;
mod preadv;
mod prlimit64;
mod pselect6;
mod pwrite64;
mod pwritev;
mod read;
mod readlink;
mod recvfrom;
mod recvmsg;
mod rename;
mod rmdir;
mod rt_sigaction;
mod rt_sigpending;
mod rt_sigprocmask;
mod rt_sigreturn;
mod rt_sigsuspend;
mod sched_affinity;
mod sched_yield;
mod select;
mod semctl;
mod semget;
mod semop;
mod sendfile;
mod sendmsg;
mod sendto;
mod set_get_priority;
mod set_robust_list;
mod set_tid_address;
mod setfsgid;
mod setfsuid;
mod setgid;
mod setgroups;
mod setitimer;
mod setpgid;
mod setregid;
mod setresgid;
mod setresuid;
mod setreuid;
mod setsid;
mod setsockopt;
mod setuid;
mod shutdown;
mod sigaltstack;
mod socket;
mod socketpair;
mod stat;
mod statfs;
mod symlink;
mod sync;
mod sysinfo;
mod tgkill;
mod time;
mod timer_create;
mod timer_settime;
mod truncate;
mod umask;
mod umount;
mod uname;
mod unlink;
mod utimens;
mod wait4;
mod waitid;
mod write;
/// This macro is used to define syscall handler.
/// The first param is the number of parameters,
/// The second param is the function name of syscall handler,
/// The third is optional, means the args(if parameter number > 0),
/// The fourth is optional, means if cpu ctx is required.
macro_rules! syscall_handler {
(0, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name($ctx)
};
(0, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name($ctx, $user_ctx)
};
(1, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name($args[0] as _, $ctx)
};
(1, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name($args[0] as _, $ctx, $user_ctx)
};
(2, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name($args[0] as _, $args[1] as _, $ctx)
};
(2, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name($args[0] as _, $args[1] as _, $ctx, $user_ctx)
};
(3, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name($args[0] as _, $args[1] as _, $args[2] as _, $ctx)
};
(3, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name($args[0] as _, $args[1] as _, $args[2] as _, $ctx, $user_ctx)
};
(4, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$ctx,
)
};
(4, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$ctx,
$user_ctx,
)
};
(5, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$args[4] as _,
$ctx,
)
};
(5, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$args[4] as _,
$ctx,
$user_ctx,
)
};
(6, $fn_name: ident, $args: ident, $ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$args[4] as _,
$args[5] as _,
$ctx,
)
};
(6, $fn_name: ident, $args: ident, $ctx: expr, $user_ctx: expr) => {
$fn_name(
$args[0] as _,
$args[1] as _,
$args[2] as _,
$args[3] as _,
$args[4] as _,
$args[5] as _,
$ctx,
$user_ctx,
)
};
}
macro_rules! dispatch_fn_inner {
( $args: ident, $ctx: ident, $user_ctx: ident, $handler: ident ( args[ .. $cnt: tt ] ) ) => {
$crate::syscall::syscall_handler!($cnt, $handler, $args, $ctx)
};
( $args: ident, $ctx: ident, $user_ctx: ident, $handler: ident ( args[ .. $cnt: tt ] , &user_ctx ) ) => {
$crate::syscall::syscall_handler!($cnt, $handler, $args, $ctx, &$user_ctx)
};
( $args: ident, $ctx: ident, $user_ctx: ident, $handler: ident ( args[ .. $cnt: tt ] , &mut user_ctx ) ) => {
// `$user_ctx` is already of type `&mut ostd::cpu::UserContext`,
// so no need to take `&mut` again
$crate::syscall::syscall_handler!($cnt, $handler, $args, $ctx, $user_ctx)
};
}
macro_rules! impl_syscall_nums_and_dispatch_fn {
// $args, $user_ctx, and $dispatcher_name are needed since Rust macro is hygienic
( $( $name: ident = $num: literal => $handler: ident $args: tt );* $(;)? ) => {
// First, define the syscall numbers
$(
pub const $name: u64 = $num;
)*
// Then, define the dispatcher function
pub fn syscall_dispatch(
syscall_number: u64,
args: [u64; 6],
ctx: &crate::context::Context,
user_ctx: &mut ostd::cpu::UserContext,
) -> $crate::prelude::Result<$crate::syscall::SyscallReturn> {
match syscall_number {
$(
$num => {
$crate::log_syscall_entry!($name);
$crate::syscall::dispatch_fn_inner!(args, ctx, user_ctx, $handler $args)
}
)*
_ => {
log::warn!("Unimplemented syscall number: {}", syscall_number);
$crate::return_errno_with_message!($crate::error::Errno::ENOSYS, "Syscall was unimplemented");
}
}
}
}
}
// Export macros to sub-modules
use dispatch_fn_inner;
use impl_syscall_nums_and_dispatch_fn;
use syscall_handler;
pub struct SyscallArgument {
syscall_number: u64,
args: [u64; 6],
}
/// Syscall return
#[derive(Debug, Clone, Copy)]
pub enum SyscallReturn {
/// return isize, this value will be used to set rax
Return(isize),
/// does not need to set rax
NoReturn,
}
impl SyscallArgument {
fn new_from_context(user_ctx: &UserContext) -> Self {
let syscall_number = user_ctx.syscall_num() as u64;
let args = user_ctx.syscall_args().map(|x| x as u64);
Self {
syscall_number,
args,
}
}
}
pub fn handle_syscall(ctx: &Context, user_ctx: &mut UserContext) {
let syscall_frame = SyscallArgument::new_from_context(user_ctx);
let syscall_return = arch::syscall_dispatch(
syscall_frame.syscall_number,
syscall_frame.args,
ctx,
user_ctx,
);
match syscall_return {
Ok(return_value) => {
if let SyscallReturn::Return(return_value) = return_value {
user_ctx.set_syscall_ret(return_value as usize);
}
}
Err(err) => {
debug!("syscall return error: {:?}", err);
let errno = err.error() as i32;
user_ctx.set_syscall_ret((-errno) as usize)
}
}
}
#[macro_export]
macro_rules! log_syscall_entry {
($syscall_name: tt) => {
if log::log_enabled!(log::Level::Info) {
let syscall_name_str = stringify!($syscall_name);
let pid = $crate::current!().pid();
let tid = {
use $crate::process::posix_thread::AsPosixThread;
$crate::current_thread!().as_posix_thread().unwrap().tid()
};
log::info!(
"[pid={}][tid={}][id={}][{}]",
pid,
tid,
$syscall_name,
syscall_name_str
);
}
};
}
pub(super) fn init() {
uname::init();
}