From 79d267631a01214bc1977d54161f20eeba88d0f4 Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Fri, 20 Dec 2024 04:11:01 +0200 Subject: [PATCH] kernel/syscalls: Add experimental native system calls Signed-off-by: EnderIce2 --- Kernel/{syscalls => core}/syscalls.cpp | 0 Kernel/include/interface/syscalls.h | 1110 +++++++++++++++++++++++- Kernel/kernel_thread.cpp | 2 +- Kernel/syscalls/mem.cpp | 212 +++++ Kernel/syscalls/native.cpp | 346 ++++++-- 5 files changed, 1544 insertions(+), 126 deletions(-) rename Kernel/{syscalls => core}/syscalls.cpp (100%) create mode 100644 Kernel/syscalls/mem.cpp diff --git a/Kernel/syscalls/syscalls.cpp b/Kernel/core/syscalls.cpp similarity index 100% rename from Kernel/syscalls/syscalls.cpp rename to Kernel/core/syscalls.cpp diff --git a/Kernel/include/interface/syscalls.h b/Kernel/include/interface/syscalls.h index f5936f71..bbfa6c0a 100644 --- a/Kernel/include/interface/syscalls.h +++ b/Kernel/include/interface/syscalls.h @@ -18,94 +18,1136 @@ #ifndef __FENNIX_API_SYSCALLS_LIST_H__ #define __FENNIX_API_SYSCALLS_LIST_H__ -#ifndef syscall0 -static inline long syscall0(long syscall) +#pragma region Syscall Wrappers + +#define scarg __UINTPTR_TYPE__ + +/** + * @brief Syscall wrapper with 0 arguments + * + * @details This wrapper is used to call syscalls with 0 arguments + * + * @param syscall #syscalls_t + * @return The return value of the syscall + */ +static inline scarg syscall0(scarg syscall) { - long ret; + scarg ret; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall1 -static inline long syscall1(long syscall, long arg1) +/** + * @brief Syscall wrapper with 1 argument + * + * @details This wrapper is used to call syscalls with 1 argument + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @return The return value of the syscall + */ +static inline scarg syscall1(scarg syscall, scarg arg1) { - long ret; + scarg ret; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall2 -static inline long syscall2(long syscall, long arg1, long arg2) +/** + * @brief Syscall wrapper with 2 arguments + * + * @details This wrapper is used to call syscalls with 2 arguments + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @return The return value of the syscall + */ +static inline scarg syscall2(scarg syscall, scarg arg1, scarg arg2) { - long ret; + scarg ret; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1), "S"(arg2) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall3 -static inline long syscall3(long syscall, long arg1, long arg2, long arg3) +/** + * @brief Syscall wrapper with 3 arguments + * + * @details This wrapper is used to call syscalls with 3 arguments + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @param arg3 Argument 3 + * @return The return value of the syscall + */ +static inline scarg syscall3(scarg syscall, scarg arg1, scarg arg2, scarg arg3) { - long ret; + scarg ret; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall4 -static inline long syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) +/** + * @brief Syscall wrapper with 4 arguments + * + * @details This wrapper is used to call syscalls with 4 arguments + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @param arg3 Argument 3 + * @param arg4 Argument 4 + * @return The return value of the syscall + */ +static inline scarg syscall4(scarg syscall, scarg arg1, scarg arg2, scarg arg3, scarg arg4) { - long ret; - register long r10 __asm__("r10") = arg4; + scarg ret; + register scarg r10 __asm__("r10") = arg4; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall5 -static inline long syscall5(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5) +/** + * @brief Syscall wrapper with 5 arguments + * + * @details This wrapper is used to call syscalls with 5 arguments + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @param arg3 Argument 3 + * @param arg4 Argument 4 + * @param arg5 Argument 5 + * @return The return value of the syscall + */ +static inline scarg syscall5(scarg syscall, scarg arg1, scarg arg2, scarg arg3, scarg arg4, scarg arg5) { - long ret; - register long r10 __asm__("r10") = arg4; - register long r8 __asm__("r8") = arg5; + scarg ret; + register scarg r10 __asm__("r10") = arg4; + register scarg r8 __asm__("r8") = arg5; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8) : "rcx", "r11", "memory"); return ret; } -#endif -#ifndef syscall6 -static inline long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) +/** + * @brief Syscall wrapper with 6 arguments + * + * @details This wrapper is used to call syscalls with 6 arguments + * + * @param syscall #syscalls_t + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @param arg3 Argument 3 + * @param arg4 Argument 4 + * @param arg5 Argument 5 + * @param arg6 Argument 6 + * @return The return value of the syscall + */ +static inline scarg syscall6(scarg syscall, scarg arg1, scarg arg2, scarg arg3, scarg arg4, scarg arg5, scarg arg6) { - long ret; - register long r10 __asm__("r10") = arg4; - register long r8 __asm__("r8") = arg5; - register long r9 __asm__("r9") = arg6; + scarg ret; + register scarg r10 __asm__("r10") = arg4; + register scarg r8 __asm__("r8") = arg5; + register scarg r9 __asm__("r9") = arg6; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); return ret; } -#endif + +#pragma endregion Syscall Wrappers + +typedef enum +{ + __SYS_PROT_READ = 0x1, + __SYS_PROT_WRITE = 0x2, + __SYS_PROT_EXEC = 0x4, + __SYS_PROT_NONE = 0x0, + + __SYS_MAP_SHARED = 0x1, + __SYS_MAP_PRIVATE = 0x2, + __SYS_MAP_FIXED = 0x4, + __SYS_MAP_ANONYMOUS = 0x8, + __SYS_MAP_ANON = __SYS_MAP_ANONYMOUS +} mmap_flags_t; + +typedef enum +{ + __SYS_O_RDONLY = 0x1, + __SYS_O_WRONLY = 0x2, + __SYS_O_RDWR = 0x3, + __SYS_O_APPEND = 0x4, + __SYS_O_CREAT = 0x8, + __SYS_O_DSYNC = 0x10, + __SYS_O_EXCL = 0x20, + __SYS_O_NOCTTY = 0x40, + __SYS_O_NONBLOCK = 0x80, + __SYS_O_RSYNC = 0x100, + __SYS_O_SYNC = 0x200, + __SYS_O_TRUNC = 0x400 +} open_flags_t; + +typedef enum +{ + __SYS_F_OK = 0, + __SYS_R_OK = 1, + __SYS_W_OK = 2, + __SYS_X_OK = 3 +} access_flags_t; + +typedef int __SYS_clockid_t; +typedef unsigned int __SYS_socklen_t; + +/** + * @brief List of syscalls + * + * @details This list contains all the syscalls of the Fennix Kernel API. + * + */ +typedef enum +{ + /* Initialization */ + + /** + * @brief Set syscall version + * + * @code + * int api_version(int version); + * @endcode + * + * @details This syscall is used to set the version of the list. + * To prevent applications from breaking on major changes, this should + * be called at the very beginning of the program. + * + * @param version The version of the syscall list of which the program + * was compiled with + * + * @return + * - #EOK on success + * - #EINVAL if the requested version is invalid + * + * @note If this syscall is not used, the latest version will be used. + */ + SYS_API_VERSION = 0, + + /* I/O */ + + /** + * @brief Read from a file descriptor + * + * @code + * ssize_t sys_read(int fildes, void *buf, size_t nbyte); + * @endcode + * + * @details Reads up to `count` bytes from the file descriptor `fd` into + * the buffer starting at `buf`. + * + * @param fd File descriptor to read from + * @param buf Buffer where data will be stored + * @param count Maximum number of bytes to read + * @param offset Offset in the file + * + * @return + * - Number of bytes read on success + * - 0 if the end of file is reached + * - #EFAULT if the buffer is outside accessible address space + * - #EBADF if `fd` is not a valid file descriptor + */ + SYS_READ = 100, + /** + * @brief Read from a file descriptor + * + * @code + * ssize_t sys_pread(int fildes, void *buf, size_t nbyte, off_t offset); + * @endcode + * + * @details Reads up to `count` bytes from the file descriptor `fd` into + * the buffer starting at `buf`. + * + * @param fd File descriptor to read from + * @param buf Buffer where data will be stored + * @param count Maximum number of bytes to read + * @param offset Offset in the file + * + * @return + * - Number of bytes read on success + * - 0 if the end of file is reached + * - #EFAULT if the buffer is outside accessible address space + * - #EBADF if `fd` is not a valid file descriptor + */ + SYS_PREAD, + /** + * @brief Write to a file descriptor + * + * @code + * ssize_t sys_write(int fildes, const void *buf, size_t nbyte); + * @endcode + * + * @details Writes up to `count` bytes from the buffer starting at `buf` + * to the file descriptor `fd`. + * + * @param fd File descriptor to write to + * @param buf Buffer containing data to write + * @param count Number of bytes to write + * @param offset Offset in the file + * + * @return + * - Number of bytes written on success + * - #EFAULT if the buffer is outside accessible address space + * - #EBADF if `fd` is not a valid file descriptor + * - #EPIPE if writing to a pipe with no reader + */ + SYS_WRITE, + /** + * @brief Write to a file descriptor + * + * @code + * ssize_t sys_pwrite(int fildes, const void *buf, size_t nbyte, off_t offset); + * @endcode + * + * @details Writes up to `count` bytes from the buffer starting at `buf` + * to the file descriptor `fd`. + * + * @param fd File descriptor to write to + * @param buf Buffer containing data to write + * @param count Number of bytes to write + * @param offset Offset in the file + * + * @return + * - Number of bytes written on success + * - #EFAULT if the buffer is outside accessible address space + * - #EBADF if `fd` is not a valid file descriptor + */ + SYS_PWRITE, + /** + * @brief Open a file + * + * @code + * int open(const char *pathname, int flags, mode_t mode); + * @endcode + * + * @details Opens the file specified by `pathname`. + * + * @param pathname Path to the file + * @param flags Flags for file access mode\n + * Supported values: + * - #O_RDONLY: Open file for reading only. + * - #O_WRONLY: Open file for writing only. + * - #O_RDWR: Open file for reading and writing. + * - #O_APPEND: Append data to the end of file. + * - #O_CREAT: Create file if it does not exist. + * - #O_DSYNC: + * - #O_EXCL: + * - #O_NOCTTY: + * - #O_NONBLOCK: + * - #O_RSYNC: + * - #O_SYNC: + * - #O_TRUNC: Truncate file to zero length. + * @param mode Permissions for newly created file (if applicable) + * + * @return + * - File descriptor on success + * - #ENOENT if the file does not exist + * - #EACCES if permissions are insufficient + * + * @see #open_flags_t + */ + SYS_OPEN, + /** + * @brief Close a file descriptor + * + * @code + * int close(int fd); + * @endcode + * + * @details Closes the file descriptor `fd`, releasing its resources. + * + * @param fd File descriptor to close + * + * @return + * - #EOK on success + * - #EBADF if `fd` is not a valid file descriptor + */ + SYS_CLOSE, + /** + * @brief Control a device + * + * @code + * int ioctl(int fd, unsigned long request, ...); + * @endcode + * + * @details Manipulates the underlying parameters of a device. + * + * @param fd File descriptor referring to the device + * @param request Device-specific request code + * + * @return + * - #EOK on success + * - #EBADF if `fd` is not valid + * - #EINVAL if the request is invalid + */ + SYS_IOCTL, + + /* File Status */ + + /** + * @brief Retrieve file status + * + * @code + * int stat(const char *pathname, struct stat *statbuf); + * @endcode + * + * @details Gets the status of the file specified by `pathname`. + * + * @param pathname Path to the file + * @param statbuf Buffer to store file status + * + * @return + * - #EOK on success + * - #ENOENT if the file does not exist + * - #EACCES if permissions are insufficient + */ + SYS_STAT = 200, + /** + * @brief Retrieve file status for an open file descriptor + * + * @code + * int fstat(int fd, struct stat *statbuf); + * @endcode + * + * @details Gets the status of the file referred to by `fd`. + * + * @param fd File descriptor + * @param statbuf Buffer to store file status + * + * @return + * - #EOK on success + * - #EBADF if `fd` is not a valid file descriptor + * - #EFAULT if `statbuf` is outside accessible address space + */ + SYS_FSTAT, + /** + * @brief Retrieve file status with symbolic link resolution + * + * @code + * int lstat(const char *pathname, struct stat *statbuf); + * @endcode + * + * @details Gets the status of the file specified by `pathname`, + * but does not follow symbolic links. + * + * @param pathname Path to the file + * @param statbuf Buffer to store file status + * + * @return + * - #EOK on success + * - #ENOENT if the file does not exist + * - #EACCES if permissions are insufficient + */ + SYS_LSTAT, + /** + * @brief Check a file's accessibility + * + * @code + * int access(const char *pathname, int mode); + * @endcode + * + * @details Checks if the calling process can access the file specified + * by `pathname` according to the specified `mode`. + * + * @param pathname Path to the file + * @param mode Accessibility check mode\n + * Supported values: + * - #F_OK: Check if the file exists + * - #R_OK: Check if the file is readable + * - #W_OK: Check if the file is writable + * - #X_OK: Check if the file is executable + * + * @return + * - #EOK on success + * - #EACCES if access is denied + * - #ENOENT if the file does not exist + * + * @see #access_flags_t + */ + SYS_ACCESS, + /** + * @brief Change the size of a file + * + * @code + * int truncate(const char *pathname, off_t length); + * @endcode + * + * @details Sets the size of the file specified by `pathname` to `length`. + * If the file is shorter, it is extended and the extended part is zero-filled. + * + * @param pathname Path to the file + * @param length Desired file length + * + * @return + * - #EOK on success + * - #EINVAL if `length` is invalid + * - #EACCES if permissions are insufficient + */ + SYS_TRUNCATE, + /** + * @brief Change the size of a file referred by a file descriptor + * + * @code + * int ftruncate(int fd, off_t length); + * @endcode + * + * @details Sets the size of the file referred to by `fd` to `length`. + * + * @param fd File descriptor + * @param length Desired file length + * + * @return + * - #EOK on success + * - #EBADF if `fd` is not valid + * - #EINVAL if `length` is invalid + */ + SYS_FTRUNCATE, + + /* Process Control */ + + /** + * @brief Terminate the calling process + * + * @code + * void exit(int status); + * @endcode + * + * @details Terminates the calling process with the specified `status`. + * The status code is made available to the parent process. + * + * @param status Exit status code + * + * @return This function does not return. + */ + SYS_EXIT = 300, + /** + * @brief Create a child process + * + * @code + * pid_t fork(void); + * @endcode + * + * @details Creates a new process by duplicating the calling process. + * The child process has its own copy of the parent's address space. + * + * @return + * - 0 to the child process + * - PID of the child to the parent process + * - #ENOMEM if memory is insufficient + */ + SYS_FORK, + /** + * @brief Execute a program + * + * @code + * int execve(const char *pathname, char *const argv[], char *const envp[]); + * @endcode + * + * @details Replaces the current process image with a new process image + * specified by `pathname`. + * + * @param pathname Path to the executable file + * @param argv Argument vector + * @param envp Environment variables + * + * @return + * - Does not return on success + * - #ENOENT if the file does not exist + * - #EACCES if permissions are insufficient + */ + SYS_EXECVE, + /** + * @brief Get the process ID of the calling process + * + * @code + * pid_t getpid(void); + * @endcode + * + * @details Returns the process ID of the calling process. + * + * @return + * - Process ID on success + */ + SYS_GETPID, + /** + * @brief Get the parent process ID + * + * @code + * pid_t getppid(void); + * @endcode + * + * @details Returns the parent process ID of the calling process. + * + * @return + * - Parent process ID on success + */ + SYS_GETPPID, + /** + * @brief Wait for a child process to change state + * + * @code + * pid_t waitpid(pid_t pid, int *wstatus, int options); + * @endcode + * + * @details Waits for the child process specified by `pid` to change state. + * + * @param pid Process ID to wait for + * @param wstatus Pointer to store the status information + * @param options Options for waiting behavior + * + * @return + * - Process ID of the child on success + * - #ECHILD if no child processes exist + */ + SYS_WAITPID, + /** + * @brief Send a signal to a process + * + * @code + * int kill(pid_t pid, int sig); + * @endcode + * + * @details Sends the signal `sig` to the process specified by `pid`. + * + * @param pid Process ID + * @param sig Signal to send + * + * @return + * - #EOK on success + * - #ESRCH if the process does not exist + * - #EINVAL if `sig` is invalid + */ + SYS_KILL, + + /* Memory */ + + /** + * @brief Set the program break + * + * @code + * int brk(void *end_data); + * @endcode + * + * @details Increases or decreases the program’s data space, ending at `end_data`. + * + * @param end_data New program break location + * + * @return + * - #EOK on success + * - #ENOMEM if memory allocation fails + */ + SYS_BRK = 400, + /** + * @brief Map files or devices into memory + * + * @code + * void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); + * @endcode + * + * @details Maps a file or device into memory. This can be used for memory-mapped I/O or + * for sharing memory between processes. + * + * @param addr Desired starting address of the mapping (NULL for automatic allocation) + * @param length Length of the mapping + * @param prot Desired memory protection\n + * Supported values: + * - #PROT_READ: Readable + * - #PROT_WRITE: Writable + * - #PROT_EXEC: Executable + * - #PROT_NONE: No access + * @param flags Mapping options\n + * Supported values: + * - #MAP_SHARED: Share memory with other processes + * - #MAP_PRIVATE: Create a private copy of the file + * - #MAP_FIXED: Use `addr` as the starting address of the mapping + * - #MAP_ANONYMOUS: Create an anonymous mapping + * @param fd File descriptor for the file to map + * @param offset Offset in the file to start the mapping + * + * @return There are several possible return values: + * - Pointer to mapped area on success + * - #EACCES + * - #EAGAIN + * - #EBADF + * - #EINVAL + * - #EMFILE + * - #ENODEV + * - #ENOMEM + * - #ENOTSUP + * - #ENXIO + * - #EOVERFLOW + * + * @see #mmap_flags_t + */ + SYS_MMAP, + /** + * @brief Unmap a mapped memory region + * + * @code + * int munmap(void *addr, size_t length); + * @endcode + * + * @details Unmaps a previously mapped memory region, making the memory available for reuse. + * + * @param addr Start address of the memory region + * @param length Length of the memory region to unmap + * + * @return + * - #EOK on success + * - #EINVAL if the address or length is invalid + * - #EFAULT if the memory region is not currently mapped + */ + SYS_MUNMAP, + /** + * @brief Change memory protection + * + * @code + * int mprotect(void *addr, size_t length, int prot); + * @endcode + * + * @details Sets the protection on the memory region starting at `addr` for `length`. + * + * @param addr Start address of the memory region + * @param length Length of the memory region + * @param prot Desired memory protection (e.g., PROT_READ, PROT_WRITE) + * + * @return + * - #EOK on success + * - #EACCES if protection cannot be set + */ + SYS_MPROTECT, + /** + * @brief Provide advice about memory usage + * + * @code + * int madvise(void *addr, size_t length, int advice); + * @endcode + * + * @details Provides advice to the kernel about the expected behavior of the memory region + * starting at `addr` for `length`, such as whether it will be accessed randomly or sequentially. + * + * @param addr Start address of the memory region + * @param length Length of the memory region + * @param advice Desired advice (e.g., MADV_DONTNEED, MADV_SEQUENTIAL) + * + * @return + * - #EOK on success + * - #EINVAL if the parameters are invalid + */ + SYS_MADVISE, + + /* Communication */ + + /** + * @brief Create a pipe + * + * @code + * int pipe(int pipefd[2]); + * @endcode + * + * @details Creates a pipe, returning two file descriptors in `pipefd`. One is for reading, + * and the other is for writing. + * + * @param pipefd Array to store the two file descriptors + * + * @return + * - #EOK on success + * - #EMFILE if the process has too many open file descriptors + */ + SYS_PIPE = 500, + /** + * @brief Duplicate a file descriptor + * + * @code + * int dup(int oldfd); + * @endcode + * + * @details Duplicates the file descriptor `oldfd`, returning the new file descriptor. + * + * @param oldfd File descriptor to duplicate + * + * @return + * - New file descriptor on success + * - #EBADF if `oldfd` is invalid + */ + SYS_DUP, + /** + * @brief Duplicate a file descriptor to a specific value + * + * @code + * int dup2(int oldfd, int newfd); + * @endcode + * + * @details Duplicates `oldfd` to `newfd`. If `newfd` is already open, it will be closed first. + * + * @param oldfd File descriptor to duplicate + * @param newfd File descriptor to duplicate `oldfd` to + * + * @return + * - `newfd` on success + * - #EBADF if `oldfd` is invalid + * - #EINVAL if `newfd` is invalid + */ + SYS_DUP2, + /** + * @brief Create an endpoint for communication + * + * @code + * int socket(int domain, int type, int protocol); + * @endcode + * + * @details Creates an endpoint for communication, returning a socket file descriptor. + * + * @param domain Communication domain (e.g., AF_INET for IPv4) + * @param type Type of socket (e.g., SOCK_STREAM for TCP) + * @param protocol Protocol to use (e.g., IPPROTO_TCP) + * + * @return + * - Socket file descriptor on success + * - #EINVAL if parameters are invalid + */ + SYS_SOCKET, + /** + * @brief Bind a socket to a local address + * + * @code + * int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + * @endcode + * + * @details Binds a socket to a local address so it can listen for incoming connections. + * + * @param sockfd Socket file descriptor + * @param addr Address to bind to + * @param addrlen Length of the address + * + * @return + * - #EOK on success + * - #EINVAL if the socket is invalid + */ + SYS_BIND, + /** + * @brief Connect to a remote address + * + * @code + * int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + * @endcode + * + * @details Connects a socket to a remote address. + * + * @param sockfd Socket file descriptor + * @param addr Remote address to connect to + * @param addrlen Length of the address + * + * @return + * - #EOK on success + * - #EINVAL if parameters are invalid + */ + SYS_CONNECT, + /** + * @brief Listen for incoming connections on a socket + * + * @code + * int listen(int sockfd, int backlog); + * @endcode + * + * @details Sets a socket to listen for incoming connections, specifying the backlog queue size. + * + * @param sockfd Socket file descriptor + * @param backlog Number of pending connections to allow + * + * @return + * - #EOK on success + * - #EINVAL if parameters are invalid + */ + SYS_LISTEN, + /** + * @brief Accept an incoming connection on a socket + * + * @code + * int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + * @endcode + * + * @details Accepts an incoming connection on a listening socket, creating a new socket for communication. + * + * @param sockfd Socket file descriptor + * @param addr Client address + * @param addrlen Length of the address + * + * @return + * - New socket file descriptor on success + * - #EINVAL if parameters are invalid + */ + SYS_ACCEPT, + /** + * @brief Send data on a socket + * + * @code + * ssize_t send(int sockfd, const void *buf, size_t len, int flags); + * @endcode + * + * @details Sends data through a socket. + * + * @param sockfd Socket file descriptor + * @param buf Data to send + * @param len Length of the data + * @param flags Flags for the send operation + * + * @return + * - Number of bytes sent on success + * - #EINVAL if parameters are invalid + */ + SYS_SEND, + /** + * @brief Receive data on a socket + * + * @code + * ssize_t recv(int sockfd, void *buf, size_t len, int flags); + * @endcode + * + * @details Receives data from a socket. + * + * @param sockfd Socket file descriptor + * @param buf Buffer to store received data + * @param len Maximum number of bytes to receive + * @param flags Flags for the receive operation + * + * @return + * - Number of bytes received on success + * - #EINVAL if parameters are invalid + */ + SYS_RECV, + /** + * @brief Shut down part of a full-duplex connection + * + * @code + * int shutdown(int sockfd, int how); + * @endcode + * + * @details Shuts down part of a full-duplex connection on a socket. + * + * @param sockfd Socket file descriptor + * @param how Determines which operations to shut down (e.g., SHUT_RD, SHUT_WR) + * + * @return + * - #EOK on success + * - #EINVAL if parameters are invalid + */ + SYS_SHUTDOWN, + + /* Time */ + + /** + * @brief Get the current time + * + * @code + * time_t time(time_t *t); + * @endcode + * + * @details Retrieves the current calendar time as the number of seconds since the epoch. + * + * @param t Pointer to store the time (optional) + * + * @return + * - Current time in seconds on success + * - #NULL if `t` is NULL + */ + SYS_TIME = 600, + /** + * @brief Get the current time of a specific clock + * + * @code + * int clock_gettime(clockid_t clockid, struct timespec *tp); + * @endcode + * + * @details Retrieves the current time for the specified clock (`CLOCK_REALTIME`, `CLOCK_MONOTONIC`, etc.). + * + * @param clockid Clock ID to query + * @param tp Pointer to store the time + * + * @return + * - #EOK on success + * - #EINVAL if parameters are invalid + */ + SYS_CLOCK_GETTIME, + /** + * @brief Set the current time of a specific clock + * + * @code + * int clock_settime(clockid_t clockid, const struct timespec *tp); + * @endcode + * + * @details Sets the time for the specified clock (`CLOCK_REALTIME`, `CLOCK_MONOTONIC`, etc.). + * + * @param clockid Clock ID to set + * @param tp Pointer to the time value + * + * @return + * - #EOK on success + * - #EINVAL if parameters are invalid + */ + SYS_CLOCK_SETTIME, + /** + * @brief Sleep for a specified time + * + * @code + * int nanosleep(const struct timespec *req, struct timespec *rem); + * @endcode + * + * @details Suspends the execution of the calling thread for the specified time duration. + * + * @param req Pointer to `timespec` specifying the time to sleep + * @param rem Pointer to store remaining time if interrupted + * + * @return + * - #EOK on success + * - #EINTR if interrupted by a signal + */ + SYS_NANOSLEEP, + + /* Miscellaneous */ + + /** + * @brief Get the current working directory + * + * @code + * char *getcwd(char *buf, size_t size); + * @endcode + * + * @details Retrieves the current working directory. + * + * @param buf Buffer to store the directory path + * @param size Size of the buffer + * + * @return + * - Pointer to `buf` on success + * - #NULL on error + */ + SYS_GETCWD = 700, + /** + * @brief Change the current working directory + * + * @code + * int chdir(const char *path); + * @endcode + * + * @details Changes the current working directory to the specified `path`. + * + * @param path New directory path + * + * @return + * - #EOK on success + * - #ENOENT if the directory does not exist + * - #EACCES if permission is denied + */ + SYS_CHDIR, + /** + * @brief Create a new directory + * + * @code + * int mkdir(const char *path, mode_t mode); + * @endcode + * + * @details Creates a new directory at `path` with the specified permissions. + * + * @param path Path to the new directory + * @param mode Directory permissions + * + * @return + * - #EOK on success + * - #EEXIST if the directory already exists + * - #EACCES if permission is denied + */ + SYS_MKDIR, + /** + * @brief Remove an empty directory + * + * @code + * int rmdir(const char *path); + * @endcode + * + * @details Removes the empty directory specified by `path`. + * + * @param path Path to the directory + * + * @return + * - #EOK on success + * - #ENOTEMPTY if the directory is not empty + */ + SYS_RMDIR, + /** + * @brief Remove a file + * + * @code + * int unlink(const char *pathname); + * @endcode + * + * @details Removes the file specified by `pathname`. + * + * @param pathname Path to the file + * + * @return + * - #EOK on success + * - #ENOENT if the file does not exist + * - #EACCES if permission is denied + */ + SYS_UNLINK, + /** + * @brief Rename a file or directory + * + * @code + * int rename(const char *oldpath, const char *newpath); + * @endcode + * + * @details Renames a file or directory from `oldpath` to `newpath`. + * + * @param oldpath Current name of the file or directory + * @param newpath New name of the file or directory + * + * @return + * - #EOK on success + * - #EEXIST if the target exists + * - #EACCES if permission is denied + */ + SYS_RENAME, + + /** + * @brief Max number of syscalls + * + * @details This is used to determine the size of the `syscalls_t` array. + * + * @code + * syscalls_t syscalls[SYS_MAX]; + * @endcode + * + * @note This must be the last element in the list + */ + SYS_MAX +} syscalls_t; #endif // !__FENNIX_API_SYSCALLS_LIST_H__ diff --git a/Kernel/kernel_thread.cpp b/Kernel/kernel_thread.cpp index 9b133fe0..04cbd916 100644 --- a/Kernel/kernel_thread.cpp +++ b/Kernel/kernel_thread.cpp @@ -42,7 +42,7 @@ int SpawnInit() const char *argv[4] = { Config.InitPath, - // "--help", + "--kernel", nullptr}; Tasking::TaskCompatibility compat = Tasking::Native; diff --git a/Kernel/syscalls/mem.cpp b/Kernel/syscalls/mem.cpp new file mode 100644 index 00000000..841517aa --- /dev/null +++ b/Kernel/syscalls/mem.cpp @@ -0,0 +1,212 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../kernel.h" + +using Tasking::PCB; +using Tasking::TCB; + +int sys_brk(SysFrm *, void *end_data) +{ + return -ENOSYS; +} + +void *sys_mmap(SysFrm *, void *addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (length == 0) + return (void *)-EINVAL; + + bool p_None = prot & __SYS_PROT_NONE; + bool p_Read = prot & __SYS_PROT_READ; + bool p_Write = prot & __SYS_PROT_WRITE; + bool p_Exec = prot & __SYS_PROT_EXEC; + + bool m_Shared = flags & __SYS_MAP_SHARED; + bool m_Private = flags & __SYS_MAP_PRIVATE; + bool m_Fixed = flags & __SYS_MAP_FIXED; + bool m_Anon = flags & __SYS_MAP_ANONYMOUS; + + UNUSED(p_None); + UNUSED(m_Anon); + + debug("None:%d Read:%d Write:%d Exec:%d", + p_None, p_Read, p_Write, p_Exec); + + debug("Shared:%d Private:%d Fixed:%d Anon:%d", + m_Shared, m_Private, m_Fixed, m_Anon); + + int unknownFlags = flags & ~(__SYS_MAP_SHARED | __SYS_MAP_PRIVATE | + __SYS_MAP_FIXED | __SYS_MAP_ANONYMOUS); + if (unknownFlags) + { + /* We still have some flags missing afaik... */ + fixme("Unknown flags: %x", unknownFlags); + /* FIXME: Continue? */ + } + + if (offset % PAGE_SIZE) + return (void *)-EINVAL; + + if (uintptr_t(addr) % PAGE_SIZE && m_Fixed) + return (void *)-EINVAL; + + if ((m_Shared && m_Private) || + (!m_Shared && !m_Private)) + return (void *)-EINVAL; + + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + if (fd != -1 && !m_Anon) + { + fixme("File mapping not fully implemented"); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + + auto _fd = fdt->FileMap.find(fd); + if (_fd == fdt->FileMap.end()) + { + debug("Invalid file descriptor %d", fd); + return (void *)-EBADF; + } + + if (p_Read) + { + void *pBuf = vma->RequestPages(TO_PAGES(length)); + debug("created buffer at %#lx-%#lx", + pBuf, (uintptr_t)pBuf + length); + + uintptr_t mFlags = Memory::US; + if (p_Write) + mFlags |= Memory::RW; + + if (m_Fixed) + { + if (m_Shared) + return (void *)-ENOSYS; + + int mRet = vma->Map(addr, pBuf, length, mFlags); + if (mRet < 0) + { + debug("Failed to map file: %s", strerror(mRet)); + return (void *)(uintptr_t)mRet; + } + off_t oldOff = fdt->usr_lseek(fd, 0, SEEK_CUR); + fdt->usr_lseek(fd, offset, SEEK_SET); + + ssize_t ret = fdt->usr_read(fd, pBuf, length); + fdt->usr_lseek(fd, oldOff, SEEK_SET); + + if (ret < 0) + { + debug("Failed to read file"); + return (void *)ret; + } + return addr; + } + else + { + int mRet = vma->Map(pBuf, pBuf, length, mFlags); + if (mRet < 0) + { + debug("Failed to map file: %s", strerror(mRet)); + return (void *)(uintptr_t)mRet; + } + } + + off_t oldOff = fdt->usr_lseek(fd, 0, SEEK_CUR); + fdt->usr_lseek(fd, offset, SEEK_SET); + + ssize_t ret = fdt->usr_read(fd, pBuf, length); + + fdt->usr_lseek(fd, oldOff, SEEK_SET); + + if (ret < 0) + { + debug("Failed to read file"); + return (void *)ret; + } + return pBuf; + } + + debug("???"); + return (void *)-ENOSYS; + } + + if (length < PAGE_SIZE * 100) + { + debug("length < 100 pages"); + + if (addr == nullptr) + { + addr = vma->RequestPages(TO_PAGES(length), true); + debug("Allocated %#lx-%#lx for pt %#lx", + addr, (uintptr_t)addr + length, vma->Table); + return addr; + } + + void *pAddr = vma->RequestPages(TO_PAGES(length)); + if (pAddr == nullptr) + { + debug("Failed to request pages"); + return (void *)-ENOMEM; + } + + uintptr_t mapFlags = 0; + if (p_Read) + mapFlags |= Memory::PTFlag::US; + if (p_Write) + mapFlags |= Memory::PTFlag::RW; + // if (p_Exec) + // mapFlags |= Memory::PTFlag::XD; + + vma->Map(addr, pAddr, length, mapFlags); + debug("mapped region %#lx-%#lx to %#lx-%#lx", + pAddr, (uintptr_t)pAddr + length, addr, (uintptr_t)addr + length); + return addr; + } + + debug("Creating CoWRegion"); + + void *ret = vma->CreateCoWRegion(addr, length, + p_Read, p_Write, p_Exec, + m_Fixed, m_Shared); + debug("ret: %#lx", ret); + return (void *)ret; +} + +int sys_munmap(SysFrm *Frame, void *addr, size_t length) +{ + return 0; +} + +int sys_mprotect(SysFrm *Frame, void *addr, size_t length, int prot) +{ + return 0; +} + +int sys_madvise(SysFrm *Frame, void *addr, size_t length, int advice) +{ + return 0; +} diff --git a/Kernel/syscalls/native.cpp b/Kernel/syscalls/native.cpp index ca4e3bde..49eff281 100644 --- a/Kernel/syscalls/native.cpp +++ b/Kernel/syscalls/native.cpp @@ -30,123 +30,287 @@ struct SyscallData { const char *Name; void *Handler; - int RequiredID; }; -using namespace Memory; +using Tasking::PCB; +using Tasking::TCB; -#if defined(__amd64__) -typedef long arch_t; -#elif defined(__i386__) -typedef int arch_t; -#endif +static int sys_api_version(SysFrm *Frame, int version) { return 0; } +static int sys_dummy(SysFrm *Frame) { return 0; } -void sys_0() { stub; } -void sys_1() { stub; } +static ssize_t sys_read(SysFrm *Frame, int fildes, void *buf, size_t nbyte) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; -#define sc_MaxSyscall 2 + void *pBuf = vma->UserCheckAndGetAddress(buf, nbyte); + if (pBuf == nullptr) + return -EFAULT; -static SyscallData NativeSyscallsTable[sc_MaxSyscall] = { - [0] = { - "0 syscall", - (void *)sys_0, - UINT16_MAX, - }, - [1] = { - "1 syscall", - (void *)sys_1, - UINT16_MAX, - }}; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + ssize_t ret = fdt->usr_read(fildes, pBuf, nbyte); + if (ret >= 0) + fdt->usr_lseek(fildes, ret, SEEK_CUR); + return ret; +} + +static ssize_t sys_pread(SysFrm *Frame, int fildes, void *buf, size_t nbyte, off_t offset) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + void *pBuf = vma->UserCheckAndGetAddress(buf, nbyte); + if (pBuf == nullptr) + return -EFAULT; + + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->usr_pread(fildes, pBuf, nbyte, offset); +} + +static ssize_t sys_write(SysFrm *Frame, int fildes, const void *buf, size_t nbyte) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + const void *pBuf = vma->UserCheckAndGetAddress(buf, nbyte); + if (pBuf == nullptr) + return -EFAULT; + + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + ssize_t ret = fdt->usr_write(fildes, pBuf, nbyte); + if (ret) + fdt->usr_lseek(fildes, ret, SEEK_CUR); + return ret; +} + +static ssize_t sys_pwrite(SysFrm *Frame, int fildes, const void *buf, size_t nbyte, off_t offset) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + const void *pBuf = vma->UserCheckAndGetAddress(buf, nbyte); + if (pBuf == nullptr) + return -EFAULT; + + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->usr_pwrite(fildes, pBuf, nbyte, offset); +} + +static int sys_open(SysFrm *Frame, const char *pathname, int flags, mode_t mode) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + const char *pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE); + if (pPathname == nullptr) + return -EFAULT; + + debug("%s, %d, %d", pPathname, flags, mode); + + if (flags & 0200000 /* O_DIRECTORY */) + { + FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + if (node == nullptr) + { + debug("Couldn't find %s", pPathname); + return -ENOENT; + } + + if (!node->IsDirectory()) + { + debug("%s is not a directory", pPathname); + return -ENOTDIR; + } + } + + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->usr_open(pPathname, flags, mode); +} + +static int sys_close(SysFrm *Frame, int fd) +{ + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->usr_close(fd); +} + +static int sys_ioctl(SysFrm *Frame, int fd, unsigned long request, void *argp) { return -ENOSYS; } +static int sys_stat(SysFrm *Frame, const char *pathname, struct stat *statbuf) { return -ENOSYS; } +static int sys_fstat(SysFrm *Frame, int fd, struct stat *statbuf) { return -ENOSYS; } +static int sys_lstat(SysFrm *Frame, const char *pathname, struct stat *statbuf) { return -ENOSYS; } +static int sys_access(SysFrm *Frame, const char *pathname, int mode) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + auto pPathname = vma->UserCheckAndGetAddress(pathname); + if (pPathname == nullptr) + return -EFAULT; + + debug("access(%s, %d)", (char *)pPathname, mode); + + if (!fs->PathExists(pPathname, pcb->CWD)) + return -ENOENT; + + stub; + return 0; +} + +static int sys_truncate(SysFrm *Frame, const char *pathname, off_t length) { return -ENOSYS; } +static int sys_ftruncate(SysFrm *Frame, int fd, off_t length) { return -ENOSYS; } + +static __noreturn void sys_exit(SysFrm *Frame, int status) +{ + TCB *t = thisThread; + { + CriticalSection cs; + trace("Userspace thread %s(%d) exited with code %d (%#x)", + t->Name, + t->ID, status, + status < 0 ? -status : status); + + t->SetState(Tasking::Zombie); + t->SetExitCode(status); + } + while (true) + t->GetContext()->Yield(); + __builtin_unreachable(); +} + +static pid_t sys_fork(SysFrm *Frame) { return -ENOSYS; } +static int sys_execve(SysFrm *Frame, const char *pathname, char *const argv[], char *const envp[]) { return -ENOSYS; } +static pid_t sys_getpid(SysFrm *Frame) { return -ENOSYS; } +static pid_t sys_getppid(SysFrm *Frame) { return -ENOSYS; } +static pid_t sys_waitpid(pid_t pid, int *wstatus, int options) { return -ENOSYS; } +static int sys_kill(SysFrm *Frame, pid_t pid, int sig) { return -ENOSYS; } + +int sys_brk(SysFrm *Frame, void *end_data); +void *sys_mmap(SysFrm *Frame, void *addr, size_t length, int prot, int flags, int fd, off_t offset); +int sys_munmap(SysFrm *Frame, void *addr, size_t length); +int sys_mprotect(SysFrm *Frame, void *addr, size_t length, int prot); +int sys_madvise(SysFrm *Frame, void *addr, size_t length, int advice); + +static int sys_pipe(SysFrm *Frame, int pipefd[2]) { return -ENOSYS; } +static int sys_dup(SysFrm *Frame, int oldfd) { return -ENOSYS; } +static int sys_dup2(SysFrm *Frame, int oldfd, int newfd) { return -ENOSYS; } +static int sys_socket(SysFrm *Frame, int domain, int type, int protocol) { return -ENOSYS; } +static int sys_bind(SysFrm *Frame, int sockfd, const struct sockaddr *addr, __SYS_socklen_t addrlen) { return -ENOSYS; } +static int sys_connect(SysFrm *Frame, int sockfd, const struct sockaddr *addr, __SYS_socklen_t addrlen) { return -ENOSYS; } +static int sys_listen(SysFrm *Frame, int sockfd, int backlog) { return -ENOSYS; } +static int sys_accept(SysFrm *Frame, int sockfd, struct sockaddr *addr, __SYS_socklen_t *addrlen) { return -ENOSYS; } +static ssize_t sys_send(SysFrm *Frame, int sockfd, const void *buf, size_t len, int flags) { return -ENOSYS; } +static ssize_t sys_recv(SysFrm *Frame, int sockfd, void *buf, size_t len, int flags) { return -ENOSYS; } +static int sys_shutdown(SysFrm *Frame, int sockfd, int how) { return -ENOSYS; } +static time_t sys_time(SysFrm *Frame, time_t *t) { return -ENOSYS; } +static int sys_clock_gettime(SysFrm *Frame, __SYS_clockid_t clockid, struct timespec *tp) { return -ENOSYS; } +static int sys_clock_settime(SysFrm *Frame, __SYS_clockid_t clockid, const struct timespec *tp) { return -ENOSYS; } +static int sys_nanosleep(SysFrm *Frame, const struct timespec *req, struct timespec *rem) { return -ENOSYS; } +static char *sys_getcwd(SysFrm *Frame, char *buf, size_t size) { return (char *)-ENOSYS; } +static int sys_chdir(SysFrm *Frame, const char *path) { return -ENOSYS; } +static int sys_mkdir(SysFrm *Frame, const char *path, mode_t mode) { return -ENOSYS; } +static int sys_rmdir(SysFrm *Frame, const char *path) { return -ENOSYS; } +static int sys_unlink(SysFrm *Frame, const char *pathname) { return -ENOSYS; } +static int sys_rename(SysFrm *Frame, const char *oldpath, const char *newpath) { return -ENOSYS; } + +static SyscallData scTbl[SYS_MAX] = {}; +__constructor void __init_native_syscalls(void) +{ + /* Initialization */ + scTbl[SYS_API_VERSION] = {"SYS_API_VERSION", (void *)sys_api_version}; + scTbl[1] = {"dummy", (void *)sys_dummy}; + + /* I/O */ + scTbl[SYS_READ] = {"SYS_READ", (void *)sys_read}; + scTbl[SYS_PREAD] = {"SYS_PREAD", (void *)sys_pread}; + scTbl[SYS_WRITE] = {"SYS_WRITE", (void *)sys_write}; + scTbl[SYS_PWRITE] = {"SYS_PWRITE", (void *)sys_pwrite}; + scTbl[SYS_OPEN] = {"SYS_OPEN", (void *)sys_open}; + scTbl[SYS_CLOSE] = {"SYS_CLOSE", (void *)sys_close}; + scTbl[SYS_IOCTL] = {"SYS_IOCTL", (void *)sys_ioctl}; + + /* File Status */ + scTbl[SYS_STAT] = {"SYS_STAT", (void *)sys_stat}; + scTbl[SYS_FSTAT] = {"SYS_FSTAT", (void *)sys_fstat}; + scTbl[SYS_LSTAT] = {"SYS_LSTAT", (void *)sys_lstat}; + scTbl[SYS_ACCESS] = {"SYS_ACCESS", (void *)sys_access}; + scTbl[SYS_TRUNCATE] = {"SYS_TRUNCATE", (void *)sys_truncate}; + scTbl[SYS_FTRUNCATE] = {"SYS_FTRUNCATE", (void *)sys_ftruncate}; + + /* Process Control */ + scTbl[SYS_EXIT] = {"SYS_EXIT", (void *)sys_exit}; + scTbl[SYS_FORK] = {"SYS_FORK", (void *)sys_fork}; + scTbl[SYS_EXECVE] = {"SYS_EXECVE", (void *)sys_execve}; + scTbl[SYS_GETPID] = {"SYS_GETPID", (void *)sys_getpid}; + scTbl[SYS_GETPPID] = {"SYS_GETPPID", (void *)sys_getppid}; + scTbl[SYS_WAITPID] = {"SYS_WAITPID", (void *)sys_waitpid}; + scTbl[SYS_KILL] = {"SYS_KILL", (void *)sys_kill}; + + /* Memory */ + scTbl[SYS_BRK] = {"SYS_BRK", (void *)sys_brk}; + scTbl[SYS_MMAP] = {"SYS_MMAP", (void *)sys_mmap}; + scTbl[SYS_MUNMAP] = {"SYS_MUNMAP", (void *)sys_munmap}; + scTbl[SYS_MPROTECT] = {"SYS_MPROTECT", (void *)sys_mprotect}; + scTbl[SYS_MADVISE] = {"SYS_MADVISE", (void *)sys_madvise}; + + /* Communication */ + scTbl[SYS_PIPE] = {"SYS_PIPE", (void *)sys_pipe}; + scTbl[SYS_DUP] = {"SYS_DUP", (void *)sys_dup}; + scTbl[SYS_DUP2] = {"SYS_DUP2", (void *)sys_dup2}; + scTbl[SYS_SOCKET] = {"SYS_SOCKET", (void *)sys_socket}; + scTbl[SYS_BIND] = {"SYS_BIND", (void *)sys_bind}; + scTbl[SYS_CONNECT] = {"SYS_CONNECT", (void *)sys_connect}; + scTbl[SYS_LISTEN] = {"SYS_LISTEN", (void *)sys_listen}; + scTbl[SYS_ACCEPT] = {"SYS_ACCEPT", (void *)sys_accept}; + scTbl[SYS_SEND] = {"SYS_SEND", (void *)sys_send}; + scTbl[SYS_RECV] = {"SYS_RECV", (void *)sys_recv}; + scTbl[SYS_SHUTDOWN] = {"SYS_SHUTDOWN", (void *)sys_shutdown}; + + /* Time */ + scTbl[SYS_TIME] = {"SYS_TIME", (void *)sys_time}; + scTbl[SYS_CLOCK_GETTIME] = {"SYS_CLOCK_GETTIME", (void *)sys_clock_gettime}; + scTbl[SYS_CLOCK_SETTIME] = {"SYS_CLOCK_SETTIME", (void *)sys_clock_settime}; + scTbl[SYS_NANOSLEEP] = {"SYS_NANOSLEEP", (void *)sys_nanosleep}; + + /* Miscellaneous */ + scTbl[SYS_GETCWD] = {"SYS_GETCWD", (void *)sys_getcwd}; + scTbl[SYS_CHDIR] = {"SYS_CHDIR", (void *)sys_chdir}; + scTbl[SYS_MKDIR] = {"SYS_MKDIR", (void *)sys_mkdir}; + scTbl[SYS_RMDIR] = {"SYS_RMDIR", (void *)sys_rmdir}; + scTbl[SYS_UNLINK] = {"SYS_UNLINK", (void *)sys_unlink}; + scTbl[SYS_RENAME] = {"SYS_RENAME", (void *)sys_rename}; +} uintptr_t HandleNativeSyscalls(SysFrm *Frame) { -#if defined(__amd64__) - if (unlikely(Frame->rax > sc_MaxSyscall)) + if (unlikely(Frame->ReturnValue() > SYS_MAX)) { - fixme("Syscall %ld not implemented.", Frame->rax); + fixme("Syscall %ld not implemented.", Frame->ReturnValue()); return -ENOSYS; } - SyscallData Syscall = NativeSyscallsTable[Frame->rax]; + SyscallData sc = scTbl[Frame->ReturnValue()]; uintptr_t (*call)(SysFrm *, uintptr_t, ...) = r_cst(uintptr_t(*)(SysFrm *, uintptr_t, ...), - Syscall.Handler); + sc.Handler); if (unlikely(!call)) { error("Syscall %s(%d) not implemented.", - Syscall.Name, Frame->rax); + sc.Name, Frame->ReturnValue()); return -ENOSYS; } - int euid = thisProcess->Security.Effective.UserID; - int egid = thisProcess->Security.Effective.GroupID; - int reqID = Syscall.RequiredID; - if (euid > reqID || egid > reqID) - { - warn("Process %s(%d) tried to access a system call \"%s\" with insufficient privileges.", - thisProcess->Name, thisProcess->ID, Syscall.Name); - debug("Required: %d; Effective u:%d, g:%d", reqID, euid, egid); - return -EPERM; - } - debug("> [%d:\"%s\"]( %#lx %#lx %#lx %#lx %#lx %#lx )", - Frame->rax, Syscall.Name, - Frame->rdi, Frame->rsi, Frame->rdx, - Frame->r10, Frame->r8, Frame->r9); + Frame->ReturnValue(), sc.Name, + Frame->Arg0(), Frame->Arg1(), Frame->Arg2(), + Frame->Arg3(), Frame->Arg4(), Frame->Arg5()); long sc_ret = call(Frame, - Frame->rdi, Frame->rsi, Frame->rdx, - Frame->r10, Frame->r8, Frame->r9); + Frame->Arg0(), Frame->Arg1(), Frame->Arg2(), + Frame->Arg3(), Frame->Arg4(), Frame->Arg5()); - debug("< [%d:\"%s\"] = %d", - Frame->rax, Syscall.Name, sc_ret); + debug("< [%d:\"%s\"] = %ld", + Frame->ReturnValue(), sc.Name, sc_ret); return sc_ret; -#elif defined(__i386__) - if (unlikely(Frame->eax > sc_MaxSyscall)) - { - fixme("Syscall %ld not implemented.", Frame->eax); - return -ENOSYS; - } - - SyscallData Syscall = NativeSyscallsTable[Frame->eax]; - - uintptr_t (*call)(SysFrm *, uintptr_t, ...) = - r_cst(uintptr_t(*)(SysFrm *, uintptr_t, ...), - Syscall.Handler); - - if (unlikely(!call)) - { - error("Syscall %s(%d) not implemented.", - Syscall.Name, Frame->eax); - return -ENOSYS; - } - - int euid = thisProcess->Security.Effective.UserID; - int egid = thisProcess->Security.Effective.GroupID; - int reqID = Syscall.RequiredID; - if (euid > reqID || egid > reqID) - { - warn("Process %s(%d) tried to access a system call \"%s\" with insufficient privileges.", - thisProcess->Name, thisProcess->ID, Syscall.Name); - debug("Required: %d; Effective u:%d, g:%d", reqID, euid, egid); - return -EPERM; - } - - debug("> [%d:\"%s\"]( %#x %#x %#x %#x %#x %#x )", - Frame->eax, Syscall.Name, - Frame->ebx, Frame->ecx, Frame->edx, - Frame->esi, Frame->edi, Frame->ebp); - - int sc_ret = call(Frame, - Frame->ebx, Frame->ecx, Frame->edx, - Frame->esi, Frame->edi, Frame->ebp); - - debug("< [%d:\"%s\"] = %d", - Frame->eax, Syscall.Name, sc_ret); - return sc_ret; -#elif defined(__aarch64__) - return -ENOSYS; -#endif }