From 9314528b9bd6d656f2b445d7617c2d506864564a Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 12 Feb 2024 21:47:40 +0200 Subject: [PATCH] Kernel: Improve syscall handling Syscalls are now called from a list of function pointers --- kernel/arch/x86_64/Signal.S | 2 - kernel/include/kernel/Process.h | 6 +- kernel/kernel/Process.cpp | 2 +- kernel/kernel/Syscall.cpp | 227 ++------------------------------ kernel/kernel/Terminal/TTY.cpp | 2 +- libc/dirent.cpp | 2 +- libc/include/sys/syscall.h | 143 ++++++++++---------- 7 files changed, 97 insertions(+), 287 deletions(-) diff --git a/kernel/arch/x86_64/Signal.S b/kernel/arch/x86_64/Signal.S index cdb610baea..afa7095af0 100644 --- a/kernel/arch/x86_64/Signal.S +++ b/kernel/arch/x86_64/Signal.S @@ -1,7 +1,5 @@ .section .userspace, "aw" -#include - // stack contains // return address // signal number diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index c4f2d15741..ad7571591e 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -96,6 +96,8 @@ namespace Kernel BAN::ErrorOr sys_getegid() const { return m_credentials.egid(); } BAN::ErrorOr sys_getpgid(pid_t); + BAN::ErrorOr sys_getpid() const { return pid(); } + BAN::ErrorOr open_inode(BAN::RefPtr, int flags); BAN::ErrorOr create_file_or_dir(BAN::StringView name, mode_t mode); @@ -148,7 +150,7 @@ namespace Kernel BAN::ErrorOr mount(BAN::StringView source, BAN::StringView target); - BAN::ErrorOr sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size); + BAN::ErrorOr sys_readdir(int fd, DirectoryEntryList* buffer, size_t buffer_size); BAN::ErrorOr sys_mmap(const sys_mmap_t*); BAN::ErrorOr sys_munmap(void* addr, size_t len); @@ -157,7 +159,7 @@ namespace Kernel BAN::ErrorOr sys_tty_ctrl(int fildes, int command, int flags); BAN::ErrorOr sys_signal(int, void (*)(int)); - static BAN::ErrorOr sys_kill(pid_t pid, int signal); + BAN::ErrorOr sys_kill(pid_t pid, int signal); BAN::ErrorOr sys_tcsetpgrp(int fd, pid_t pgid); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index e8269a7be6..83eeb8620a 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1218,7 +1218,7 @@ namespace Kernel return BAN::Error::from_errno(EUNKNOWN); } - BAN::ErrorOr Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) + BAN::ErrorOr Process::sys_readdir(int fd, DirectoryEntryList* list, size_t list_size) { LockGuard _(m_lock); TRY(validate_pointer_access(list, list_size)); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 1e8dbab312..ff167e1b7f 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -19,6 +20,14 @@ namespace Kernel extern "C" long sys_fork_trampoline(); + using SyscallHandler = BAN::ErrorOr (Process::*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + + static const SyscallHandler s_syscall_handlers[] = { +#define O(enum, name) BAN::bit_cast(&Process::sys_ ## name), + __SYSCALL_LIST(O) +#undef O + }; + extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, InterruptStack& interrupt_stack) { ASSERT((interrupt_stack.cs & 0b11) == 0b11); @@ -28,222 +37,14 @@ namespace Kernel asm volatile("sti"); - (void)arg1; - (void)arg2; - (void)arg3; - (void)arg4; - (void)arg5; - (void)interrupt_stack; - BAN::ErrorOr ret = BAN::Error::from_errno(ENOSYS); - switch (syscall) - { - case SYS_EXIT: - ret = Process::current().sys_exit((int)arg1); - break; - case SYS_READ: - ret = Process::current().sys_read((int)arg1, (void*)arg2, (size_t)arg3); - break; - case SYS_WRITE: - ret = Process::current().sys_write((int)arg1, (const void*)arg2, (size_t)arg3); - break; - case SYS_TERMID: - ret = Process::current().sys_termid((char*)arg1); - break; - case SYS_CLOSE: - ret = Process::current().sys_close((int)arg1); - break; - case SYS_OPEN: - ret = Process::current().sys_open((const char*)arg1, (int)arg2, (mode_t)arg3); - break; - case SYS_OPENAT: - ret = Process::current().sys_openat((int)arg1, (const char*)arg2, (int)arg3, (mode_t)arg4); - break; - case SYS_SEEK: - ret = Process::current().sys_seek((int)arg1, (long)arg2, (int)arg3); - break; - case SYS_TELL: - ret = Process::current().sys_tell((int)arg1); - break; - case SYS_GET_TERMIOS: - ret = Process::current().sys_gettermios((::termios*)arg1); - break; - case SYS_SET_TERMIOS: - ret = Process::current().sys_settermios((const ::termios*)arg1); - break; - case SYS_FORK: + if (syscall < 0 || syscall >= __SYSCALL_COUNT) + dwarnln("No syscall {}", syscall); + else if (syscall == SYS_FORK) ret = sys_fork_trampoline(); - break; - case SYS_EXEC: - ret = Process::current().sys_exec((const char*)arg1, (const char* const*)arg2, (const char* const*)arg3); - break; - case SYS_SLEEP: - ret = Process::current().sys_sleep((unsigned int)arg1); - break; - case SYS_WAIT: - ret = Process::current().sys_wait((pid_t)arg1, (int*)arg2, (int)arg3); - break; - case SYS_FSTAT: - ret = Process::current().sys_fstat((int)arg1, (struct stat*)arg2); - break; - case SYS_READ_DIR_ENTRIES: - ret = Process::current().sys_read_dir_entries((int)arg1, (API::DirectoryEntryList*)arg2, (size_t)arg3); - break; - case SYS_SET_UID: - ret = Process::current().sys_setuid((uid_t)arg1); - break; - case SYS_SET_GID: - ret = Process::current().sys_setgid((gid_t)arg1); - break; - case SYS_SET_EUID: - ret = Process::current().sys_seteuid((uid_t)arg1); - break; - case SYS_SET_EGID: - ret = Process::current().sys_setegid((gid_t)arg1); - break; - case SYS_SET_REUID: - ret = Process::current().sys_setreuid((uid_t)arg1, (uid_t)arg2); - break; - case SYS_SET_REGID: - ret = Process::current().sys_setregid((gid_t)arg1, (gid_t)arg2); - break; - case SYS_GET_UID: - ret = Process::current().sys_getuid(); - break; - case SYS_GET_GID: - ret = Process::current().sys_getgid(); - break; - case SYS_GET_EUID: - ret = Process::current().sys_geteuid(); - break; - case SYS_GET_EGID: - ret = Process::current().sys_getegid(); - break; - case SYS_GET_PWD: - ret = Process::current().sys_getpwd((char*)arg1, (size_t)arg2); - break; - case SYS_SET_PWD: - ret = Process::current().sys_setpwd((const char*)arg1); - break; - case SYS_CLOCK_GETTIME: - ret = Process::current().sys_clock_gettime((clockid_t)arg1, (timespec*)arg2); - break; - case SYS_PIPE: - ret = Process::current().sys_pipe((int*)arg1); - break; - case SYS_DUP: - ret = Process::current().sys_dup((int)arg1); - break; - case SYS_DUP2: - ret = Process::current().sys_dup2((int)arg1, (int)arg2); - break; - case SYS_KILL: - ret = Process::current().sys_kill((pid_t)arg1, (int)arg2); - break; - case SYS_SIGNAL: - ret = Process::current().sys_signal((int)arg1, (void (*)(int))arg2); - break; - case SYS_TCSETPGRP: - ret = Process::current().sys_tcsetpgrp((int)arg1, (pid_t)arg2); - break; - case SYS_GET_PID: - ret = Process::current().pid(); - break; - case SYS_GET_PGID: - ret = Process::current().sys_getpgid((pid_t)arg1); - break; - case SYS_SET_PGID: - ret = Process::current().sys_setpgid((pid_t)arg1, (pid_t)arg2); - break; - case SYS_FCNTL: - ret = Process::current().sys_fcntl((int)arg1, (int)arg2, (int)arg3); - break; - case SYS_NANOSLEEP: - ret = Process::current().sys_nanosleep((const timespec*)arg1, (timespec*)arg2); - break; - case SYS_FSTATAT: - ret = Process::current().sys_fstatat((int)arg1, (const char*)arg2, (struct stat*)arg3, (int)arg4); - break; - case SYS_STAT: - ret = Process::current().sys_stat((const char*)arg1, (struct stat*)arg2, (int)arg3); - break; - case SYS_SYNC: - ret = Process::current().sys_sync((bool)arg1); - break; - case SYS_MMAP: - ret = Process::current().sys_mmap((const sys_mmap_t*)arg1); - break; - case SYS_MUNMAP: - ret = Process::current().sys_munmap((void*)arg1, (size_t)arg2); - break; - case SYS_TTY_CTRL: - ret = Process::current().sys_tty_ctrl((int)arg1, (int)arg2, (int)arg3); - break; - case SYS_POWEROFF: - ret = Process::current().sys_poweroff((int)arg1); - break; - case SYS_CHMOD: - ret = Process::current().sys_chmod((const char*)arg1, (mode_t)arg2); - break; - case SYS_CREATE: - ret = Process::current().sys_create((const char*)arg1, (mode_t)arg2); - break; - case SYS_CREATE_DIR: - ret = Process::current().sys_create_dir((const char*)arg1, (mode_t)arg2); - break; - case SYS_UNLINK: - ret = Process::current().sys_unlink((const char*)arg1); - break; - case SYS_READLINK: - ret = Process::current().sys_readlink((const char*)arg1, (char*)arg2, (size_t)arg3); - break; - case SYS_READLINKAT: - ret = Process::current().sys_readlinkat((int)arg1, (const char*)arg2, (char*)arg3, (size_t)arg4); - break; - case SYS_MSYNC: - ret = Process::current().sys_msync((void*)arg1, (size_t)arg2, (int)arg3); - break; - case SYS_PREAD: - ret = Process::current().sys_pread((int)arg1, (void*)arg2, (size_t)arg3, (off_t)arg4); - break; - case SYS_CHOWN: - ret = Process::current().sys_chown((const char*)arg1, (uid_t)arg2, (gid_t)arg3); - break; - case SYS_LOAD_KEYMAP: - ret = Process::current().sys_load_keymap((const char*)arg1); - break; - case SYS_SOCKET: - ret = Process::current().sys_socket((int)arg1, (int)arg2, (int)arg3); - break; - case SYS_BIND: - ret = Process::current().sys_bind((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3); - break; - case SYS_SENDTO: - ret = Process::current().sys_sendto((const sys_sendto_t*)arg1); - break; - case SYS_RECVFROM: - ret = Process::current().sys_recvfrom((sys_recvfrom_t*)arg1); - break; - case SYS_IOCTL: - ret = Process::current().sys_ioctl((int)arg1, (int)arg2, (void*)arg3); - break; - case SYS_ACCEPT: - ret = Process::current().sys_accept((int)arg1, (sockaddr*)arg2, (socklen_t*)arg3); - break; - case SYS_CONNECT: - ret = Process::current().sys_connect((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3); - break; - case SYS_LISTEN: - ret = Process::current().sys_listen((int)arg1, (int)arg2); - break; - case SYS_PSELECT: - ret = Process::current().sys_pselect((sys_pselect_t*)arg1); - break; - default: - dwarnln("Unknown syscall {}", syscall); - break; - } + else + ret = (Process::current().*s_syscall_handlers[syscall])(arg1, arg2, arg3, arg4, arg5); asm volatile("cli"); diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 0e3e594c11..14e1d09cbb 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -210,7 +210,7 @@ namespace Kernel // ^C if (ch == '\x03') { - if (auto ret = Process::sys_kill(-m_foreground_pgrp, SIGINT); ret.is_error()) + if (auto ret = Process::current().sys_kill(-m_foreground_pgrp, SIGINT); ret.is_error()) dwarnln("TTY: {}", ret.error()); return; } diff --git a/libc/dirent.cpp b/libc/dirent.cpp index 9c16c27745..339162ac0a 100644 --- a/libc/dirent.cpp +++ b/libc/dirent.cpp @@ -79,7 +79,7 @@ struct dirent* readdir(DIR* dirp) return &dirp->current->dirent; } - if (syscall(SYS_READ_DIR_ENTRIES, dirp->fd, dirp->buffer, dirp->buffer_size) == -1) + if (syscall(SYS_READ_DIR, dirp->fd, dirp->buffer, dirp->buffer_size) == -1) return nullptr; if (dirp->buffer->entry_count == 0) diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 6fa892a107..c2382c150e 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -5,73 +5,82 @@ __BEGIN_DECLS -#define SYS_EXIT 1 -#define SYS_READ 2 -#define SYS_WRITE 3 -#define SYS_TERMID 4 -#define SYS_CLOSE 5 -#define SYS_OPEN 6 -#define SYS_OPENAT 7 -#define SYS_SEEK 11 -#define SYS_TELL 12 -#define SYS_GET_TERMIOS 13 -#define SYS_SET_TERMIOS 14 -#define SYS_FORK 15 -#define SYS_EXEC 16 -#define SYS_SLEEP 17 -#define SYS_WAIT 18 -#define SYS_FSTAT 19 -#define SYS_READ_DIR_ENTRIES 21 -#define SYS_SET_UID 22 -#define SYS_SET_GID 23 -#define SYS_SET_EUID 24 -#define SYS_SET_EGID 25 -#define SYS_SET_REUID 26 -#define SYS_SET_REGID 27 -#define SYS_GET_UID 28 -#define SYS_GET_GID 29 -#define SYS_GET_EUID 30 -#define SYS_GET_EGID 31 -#define SYS_GET_PWD 32 -#define SYS_SET_PWD 33 -#define SYS_CLOCK_GETTIME 34 -#define SYS_PIPE 35 -#define SYS_DUP 36 -#define SYS_DUP2 37 -#define SYS_KILL 39 -#define SYS_SIGNAL 40 -#define SYS_TCSETPGRP 42 -#define SYS_GET_PID 43 -#define SYS_GET_PGID 44 -#define SYS_SET_PGID 45 -#define SYS_FCNTL 46 -#define SYS_NANOSLEEP 47 -#define SYS_FSTATAT 48 -#define SYS_STAT 49 // stat/lstat -#define SYS_SYNC 50 -#define SYS_MMAP 51 -#define SYS_MUNMAP 52 -#define SYS_TTY_CTRL 53 -#define SYS_POWEROFF 54 -#define SYS_CHMOD 55 -#define SYS_CREATE 56 // creat, mkfifo -#define SYS_CREATE_DIR 57 // mkdir -#define SYS_UNLINK 58 -#define SYS_READLINK 59 -#define SYS_READLINKAT 60 -#define SYS_MSYNC 61 -#define SYS_PREAD 62 -#define SYS_CHOWN 63 -#define SYS_LOAD_KEYMAP 64 -#define SYS_SOCKET 65 -#define SYS_BIND 66 -#define SYS_SENDTO 67 -#define SYS_RECVFROM 68 -#define SYS_IOCTL 69 -#define SYS_ACCEPT 70 -#define SYS_CONNECT 71 -#define SYS_LISTEN 72 -#define SYS_PSELECT 73 +#define __SYSCALL_LIST(O) \ + O(SYS_EXIT, exit) \ + O(SYS_READ, read) \ + O(SYS_WRITE, write) \ + O(SYS_TERMID, termid) \ + O(SYS_CLOSE, close) \ + O(SYS_OPEN, open) \ + O(SYS_OPENAT, openat) \ + O(SYS_SEEK, seek) \ + O(SYS_TELL, tell) \ + O(SYS_GET_TERMIOS, gettermios) \ + O(SYS_SET_TERMIOS, settermios) \ + O(SYS_FORK, fork) \ + O(SYS_EXEC, exec) \ + O(SYS_SLEEP, sleep) \ + O(SYS_WAIT, wait) \ + O(SYS_FSTAT, fstat) \ + O(SYS_READ_DIR, readdir) \ + O(SYS_SET_UID, setuid) \ + O(SYS_SET_GID, setgid) \ + O(SYS_SET_EUID, seteuid) \ + O(SYS_SET_EGID, setegid) \ + O(SYS_SET_REUID, setreuid) \ + O(SYS_SET_REGID, setregid) \ + O(SYS_GET_UID, getuid) \ + O(SYS_GET_GID, getgid) \ + O(SYS_GET_EUID, geteuid) \ + O(SYS_GET_EGID, getegid) \ + O(SYS_GET_PWD, getpwd) \ + O(SYS_SET_PWD, setpwd) \ + O(SYS_CLOCK_GETTIME, clock_gettime) \ + O(SYS_PIPE, pipe) \ + O(SYS_DUP, dup) \ + O(SYS_DUP2, dup2) \ + O(SYS_KILL, kill) \ + O(SYS_SIGNAL, signal) \ + O(SYS_TCSETPGRP, tcsetpgrp) \ + O(SYS_GET_PID, getpid) \ + O(SYS_GET_PGID, getpgid) \ + O(SYS_SET_PGID, setpgid) \ + O(SYS_FCNTL, fcntl) \ + O(SYS_NANOSLEEP, nanosleep) \ + O(SYS_FSTATAT, fstatat) \ + O(SYS_STAT, stat) \ + O(SYS_SYNC, sync) \ + O(SYS_MMAP, mmap) \ + O(SYS_MUNMAP, munmap) \ + O(SYS_TTY_CTRL, tty_ctrl) \ + O(SYS_POWEROFF, poweroff) \ + O(SYS_CHMOD, chmod) \ + O(SYS_CREATE, create) \ + O(SYS_CREATE_DIR, create_dir) \ + O(SYS_UNLINK, unlink) \ + O(SYS_READLINK, readlink) \ + O(SYS_READLINKAT, readlinkat) \ + O(SYS_MSYNC, msync) \ + O(SYS_PREAD, pread) \ + O(SYS_CHOWN, chown) \ + O(SYS_LOAD_KEYMAP, load_keymap) \ + O(SYS_SOCKET, socket) \ + O(SYS_BIND, bind) \ + O(SYS_SENDTO, sendto) \ + O(SYS_RECVFROM, recvfrom) \ + O(SYS_IOCTL, ioctl) \ + O(SYS_ACCEPT, accept) \ + O(SYS_CONNECT, connect) \ + O(SYS_LISTEN, listen) \ + O(SYS_PSELECT, pselect) \ + +enum Syscall +{ +#define O(enum, name) enum, + __SYSCALL_LIST(O) +#undef O + __SYSCALL_COUNT +}; __END_DECLS