From bd5969fc876a10b18613302db7087ef3c40f18e1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 7 Mar 2024 17:28:00 -0500 Subject: lib: Add mlibc Signed-off-by: Ian Moffett --- lib/mlibc/sysdeps/aero/generic/aero.cpp | 360 ++++++++++++++++++++ lib/mlibc/sysdeps/aero/generic/entry.cpp | 36 ++ lib/mlibc/sysdeps/aero/generic/filesystem.cpp | 472 ++++++++++++++++++++++++++ lib/mlibc/sysdeps/aero/generic/signals.S | 9 + lib/mlibc/sysdeps/aero/generic/signals.cpp | 53 +++ lib/mlibc/sysdeps/aero/generic/sockets.cpp | 250 ++++++++++++++ lib/mlibc/sysdeps/aero/generic/thread.cpp | 55 +++ lib/mlibc/sysdeps/aero/generic/thread_entry.S | 10 + lib/mlibc/sysdeps/aero/generic/time.cpp | 25 ++ 9 files changed, 1270 insertions(+) create mode 100644 lib/mlibc/sysdeps/aero/generic/aero.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/filesystem.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/signals.S create mode 100644 lib/mlibc/sysdeps/aero/generic/signals.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/sockets.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/thread_entry.S create mode 100644 lib/mlibc/sysdeps/aero/generic/time.cpp (limited to 'lib/mlibc/sysdeps/aero/generic') diff --git a/lib/mlibc/sysdeps/aero/generic/aero.cpp b/lib/mlibc/sysdeps/aero/generic/aero.cpp new file mode 100644 index 0000000..e6bd277 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/aero.cpp @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +struct Slice { + void *ptr; + uint64_t len; +}; + +/// Helper function to construct a slice vector from the provided argument +/// array. A slice basically consists of a pointer to the data and the length of +/// it. +/// +/// ## Examples +/// ```cc +/// auto slice = create_slice({ "hello", "world" }); +/// ``` +/// +/// The `slice` will look like the following: +/// +/// ```cc +/// vector( +/// Slice { .ptr: hello_ptr, .size: hello_size }, +/// Slice { .ptr: world_ptr, .size: world_size } +/// ) +/// ``` +static frg::vector create_slice(char *const arg[]) { + if (arg == nullptr) { + return frg::vector{getAllocator()}; + } + + // Find out the length of arg: + size_t len = 0; + + while (arg[len] != nullptr) { + len += 1; + } + + frg::vector params{getAllocator()}; + params.resize(len); + + // Construct the slice vector: + for (size_t i = 0; i < len; ++i) { + params[i].ptr = (void *)arg[i]; + params[i].len = strlen(arg[i]); + } + + return params; +} + +namespace mlibc { +int sys_uname(struct utsname *buf) { + auto result = syscall(SYS_UNAME, buf); + + if (result < 0) { + return -result; + } + + return result; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // auto result = syscall(SYS_FUTEX_WAIT, pointer, expected, time); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_futex_wake(int *pointer) { + // auto result = syscall(SYS_FUTEX_WAKE, pointer); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_tcb_set(void *pointer) { + auto result = syscall(SYS_ARCH_PRCTL, ARCH_SET_FS, (uint64_t)pointer); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, + off_t offset, void **window) { + auto result = syscall(SYS_MMAP, hint, size, prot, flags, fd, offset); + + if (result < 0) { + return -result; + } + + *window = (void *)result; + return 0; +} + +int sys_vm_unmap(void *address, size_t size) { + return syscall(SYS_MUNMAP, address, size); +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + auto res = syscall(SYS_MPROTECT, pointer, size, prot); + if (res < 0) + return -res; + + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +void sys_libc_panic() { + mlibc::infoLogger() << "libc_panic: panicked at 'unknown'" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); + + sys_exit(1); +} + +void sys_libc_log(const char *msg) { syscall(SYS_LOG, msg, strlen(msg)); } + +void sys_exit(int status) { + syscall(SYS_EXIT, status); + + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTDL + +pid_t sys_getpid() { + auto result = syscall(SYS_GETPID); + __ensure(result >= 0); + + return result; +} + +pid_t sys_getppid() { + auto result = syscall(SYS_GETPPID); + __ensure(result != 0); + + return result; +} + +int sys_kill(int pid, int sig) { + auto result = syscall(SYS_KILL, pid, sig); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + auto result = syscall(SYS_GETTIME, clock, &ts); + + if (result < 0) { + return -result; + } + + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + + return 0; +} + +int sys_getcwd(char *buffer, size_t size) { + auto result = syscall(SYS_GETCWD, buffer, size); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_chdir(const char *path) { + auto result = syscall(SYS_CHDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + auto result = syscall(SYS_GETHOSTNAME, buffer, bufsize); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_sleep(time_t *sec, long *nanosec) { + struct timespec ts = {.tv_sec = *sec, .tv_nsec = *nanosec}; + + auto result = syscall(SYS_SLEEP, &ts); + + if (result < 0) { + return -result; + } + + return 0; +} + +pid_t sys_getpgid(pid_t pid, pid_t *pgid) { + auto ret = syscall(SYS_GETPGID, pid); + if(int e = sc_error(ret); e) + return e; + *pgid = ret; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + auto ret = syscall(SYS_SETPGID, pid, pgid); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +uid_t sys_getuid() { + mlibc::infoLogger() << "mlibc: sys_setuid is a stub" << frg::endlog; + return 0; +} + +uid_t sys_geteuid() { + mlibc::infoLogger() << "mlibc: sys_seteuid is a stub" << frg::endlog; + return 0; +} + +int sys_setsid(pid_t *sid) { + auto ret = syscall(SYS_SETSID); + if(int e = sc_error(ret); e) + return e; + *sid = ret; + return 0; +} + +int sys_seteuid(uid_t euid) UNIMPLEMENTED("sys_seteuid") + + gid_t sys_getgid() { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +gid_t sys_getegid() { + mlibc::infoLogger() << "mlibc: sys_getegid is a stub" << frg::endlog; + return 0; +} + +int sys_setgid(gid_t gid) { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +int sys_setegid(gid_t egid) { + mlibc::infoLogger() << "mlibc: sys_setegid is a stub" << frg::endlog; + return 0; +} + +void sys_yield() { + mlibc::infoLogger() << "mlibc: sys_yield is a stub" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + auto result = syscall(SYS_CLONE, (uintptr_t)__mlibc_start_thread, stack); + + if (result < 0) { + return -result; + } + + *tid_out = (pid_t)result; + return 0; +} + +void sys_thread_exit() UNIMPLEMENTED("sys_thread_exit") + + int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, + pid_t *ret_pid) { + if (ru) { + mlibc::infoLogger() + << "mlibc: struct rusage in sys_waitpid is unsupported" + << frg::endlog; + return ENOSYS; + } + + auto result = syscall(SYS_WAITPID, pid, status, flags); + + if (result < 0) { + return -result; + } + + *ret_pid = result; + return 0; +} + +int sys_fork(pid_t *child) { + auto result = syscall(SYS_FORK); + + if (result < 0) { + return -result; + } + + *child = result; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + auto envv_slice = create_slice(envp); + auto argv_slice = create_slice(argv); + + auto path_ptr = (uintptr_t)path; + auto path_len = strlen(path); + + auto result = + syscall(SYS_EXEC, path_ptr, path_len, argv_slice.data(), + argv_slice.size(), envv_slice.data(), envv_slice.size()); + + if (result < 0) { + return -result; + } + + __builtin_unreachable(); +} + +// int sys_getentropy(void *buffer, size_t length) +// UNIMPLEMENTED("sys_getentropy") + +#endif +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/entry.cpp b/lib/mlibc/sysdeps/aero/generic/entry.cpp new file mode 100644 index 0000000..77d6ed5 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/entry.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], + char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux + // sysdeps) + auto result = + main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/aero/generic/filesystem.cpp b/lib/mlibc/sysdeps/aero/generic/filesystem.cpp new file mode 100644 index 0000000..049f4c0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/filesystem.cpp @@ -0,0 +1,472 @@ +#include "mlibc/fsfd_target.hpp" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +namespace mlibc { +int sys_write(int fd, const void *buffer, size_t count, ssize_t *written) { + auto result = syscall(SYS_WRITE, fd, buffer, count); + + if (result < 0) { + return -result; + } + + *written = result; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + auto result = syscall(SYS_READ, fd, buf, count); + + if (result < 0) { + *bytes_read = 0; + return -result; + } + + *bytes_read = result; + return 0; +} + +// clang-format off +int sys_pwrite(int fd, const void *buffer, size_t count, off_t off, + ssize_t *written) UNIMPLEMENTED("sys_pwrite") + +// clang-format off +int sys_pread(int fd, void *buf, size_t count, + off_t off, ssize_t *bytes_read) UNIMPLEMENTED("sys_pread") + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto result = syscall(SYS_SEEK, fd, offset, whence); + + if (result < 0) { + return -result; + } + + *new_offset = result; + return 0; +} + +int sys_open(const char *filename, int flags, mode_t mode, int *fd) { + auto result = syscall(SYS_OPEN, 0, filename, strlen(filename), flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_close(int fd) { + auto result = syscall(SYS_CLOSE, fd); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_access(const char *filename, int mode) { + auto result = + syscall(SYS_ACCESS, AT_FDCWD, filename, strlen(filename), mode, 0); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) { + switch (fsfdt) { + case fsfd_target::path: + fd = AT_FDCWD; + break; + case fsfd_target::fd: + flags |= AT_EMPTY_PATH; + + case fsfd_target::fd_path: + break; + + default: + __ensure(!"Invalid fsfd_target"); + __builtin_unreachable(); + } + + auto ret = syscall(SYS_FSTAT, fd, path, strlen(path), flags, statbuf); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto sys_res = syscall(SYS_IOCTL, fd, request, arg); + + if (sys_res < 0) { + return -sys_res; + } + + if (result) + *result = sys_res; + return 0; +} + +int sys_isatty(int fd) { + // NOTE: The easiest way to check if a file descriptor is a TTY is to + // do an ioctl of TIOCGWINSZ on it and see if it succeeds :^) + struct winsize ws; + int result; + + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, &result)) { + return 0; + } + + return ENOTTY; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int result; + + if (int e = sys_ioctl(fd, TCGETS, (void *)attr, &result); e) + return e; + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + + switch (optional_action) { + case TCSANOW: req = TCSETS; break; + case TCSADRAIN: req = TCSETSW; break; + case TCSAFLUSH: req = TCSETSF; break; + default: return EINVAL; + } + + if (int e = sys_ioctl(fd, req, (void *)attr, NULL); e) + return e; + + return 0; +} + +int sys_mkdir(const char *path, mode_t) { + auto result = syscall(SYS_MKDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_link(const char *srcpath, const char *destpath) { + auto result = + syscall(SYS_LINK, srcpath, strlen(srcpath), destpath, strlen(destpath)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} + +int sys_unlinkat(int fd, const char *path, int flags) { + auto ret = syscall(SYS_UNLINK, fd, path, strlen(path), flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +struct aero_dir_entry { + size_t inode; + size_t offset; + size_t reclen; + size_t filetyp; + char name[]; +} __attribute__((__packed__)); + +int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read) { + auto result = syscall(SYS_GETDENTS, handle, buffer, max_size); + + // Check if we got an error. + if (result < 0) { + *bytes_read = 0; + return -result; + } + + // Nothing to read. + if (result == 0) { + *bytes_read = 0; + return 0; + } + + auto entry = (struct aero_dir_entry *)buffer; + + struct dirent dirent = { + .d_ino = static_cast(entry->inode), + .d_off = static_cast(entry->offset), + .d_reclen = static_cast(entry->reclen), + .d_type = static_cast(entry->filetyp), + }; + + // The reclen is the size of the dirent struct, plus the size of the name. + auto name_size = entry->reclen - sizeof(struct aero_dir_entry); + __ensure(name_size < 255); + + memcpy(&dirent.d_name, entry->name, name_size); + *bytes_read = entry->reclen; + + memcpy(buffer, &dirent, sizeof(struct dirent)); + return 0; +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_rename(const char *path, const char *new_path) { + auto result = + syscall(SYS_RENAME, path, strlen(path), new_path, strlen(new_path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, + ssize_t *length) { + auto result = syscall(SYS_READ_LINK, path, strlen(path), buffer, max_size); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + auto result = syscall(SYS_DUP, fd, flags); + + if (result < 0) { + return -result; + } + + *newfd = result; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + auto result = syscall(SYS_DUP2, fd, newfd, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int *result_value) { + auto result = syscall(SYS_FCNTL, fd, request, va_arg(args, uint64_t)); + + if (result < 0) { + return -result; + } + + *result_value = result; + return 0; +} + +// int sys_chmod(const char *pathname, mode_t mode) UNIMPLEMENTED("sys_chmod") + +int sys_pipe(int *fds, int flags) { + auto result = syscall(SYS_PIPE, fds, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +// epoll API syscalls: +int sys_epoll_create(int flags, int *fd) { + auto result = syscall(SYS_EPOLL_CREATE, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + auto result = syscall(SYS_EPOLL_CTL, epfd, mode, fd, ev); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, + const sigset_t *sigmask, int *raised) { + auto result = syscall(SYS_EPOLL_PWAIT, epfd, ev, n, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *raised = result; + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + auto result = syscall(SYS_EVENT_FD, initval, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + auto result = syscall(SYS_POLL, fds, nfds, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *num_events = result; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + return sys_ppoll(fds, count, &ts, NULL, num_events); +} + +#ifndef MLIBC_BUILDING_RTDL +#include +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + int fd = epoll_create1(0); + if (fd == -1) + return -1; + + for (int k = 0; k < FD_SETSIZE; k++) { + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + + if (read_set && FD_ISSET(k, read_set)) + ev.events |= EPOLLIN; + if (write_set && FD_ISSET(k, write_set)) + ev.events |= EPOLLOUT; + if (except_set && FD_ISSET(k, except_set)) + ev.events |= EPOLLPRI; + + if (!ev.events) + continue; + + ev.data.u32 = k; + if (epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) + return -1; + } + + struct epoll_event evnts[16]; + int n = epoll_pwait( + fd, evnts, 16, + timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, + sigmask); + + if (n == -1) + return -1; + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + int m = 0; + + for (int i = 0; i < n; i++) { + int k = evnts[i].data.u32; + + if (read_set && FD_ISSET(k, read_set) && + evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_read_set); + m++; + } + + if (write_set && FD_ISSET(k, write_set) && + evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_write_set); + m++; + } + + if (except_set && FD_ISSET(k, except_set) && + evnts[i].events & EPOLLPRI) { + FD_SET(k, &res_except_set); + m++; + } + } + + if (close(fd)) + __ensure("mlibc::pselect: close() failed on epoll file"); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + *num_events = m; + return 0; +} +#endif // #ifndef MLIBC_BUILDING_RTDL +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/signals.S b/lib/mlibc/sysdeps/aero/generic/signals.S new file mode 100644 index 0000000..62dee9b --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/signals.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_signal_restore + +__mlibc_signal_restore: + mov $39, %rax + syscall + ud2 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/aero/generic/signals.cpp b/lib/mlibc/sysdeps/aero/generic/signals.cpp new file mode 100644 index 0000000..a6f69ff --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/signals.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include +#include + +#define LOG_SIGACTION_INSTALL 0 + +extern "C" void __mlibc_signal_restore(); // defined in `signals.S` + +namespace mlibc { +int sys_sigaction(int how, const struct sigaction *__restrict action, + struct sigaction *__restrict old_action) { +#if LOG_SIGACTION_INSTALL + mlibc::infoLogger() << "sys_sigaction: signal " << how << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: size: " << sizeof(*action) + << frg::endlog; + + if (action != NULL) { + mlibc::infoLogger() << "sys_sigaction: handler " + << (int64_t)action->sa_handler << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: action " + << (int64_t)action->sa_sigaction << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: flags " + << (int64_t)action->sa_flags << frg::endlog; + } + + mlibc::infoLogger() << frg::endlog; +#endif + + auto sigreturn = (sc_word_t)__mlibc_signal_restore; + + auto res = syscall(SYS_SIGACTION, how, (sc_word_t)action, sigreturn, + (sc_word_t)old_action); + + if (res < 0) { + return -res; + } + + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve) { + auto result = syscall(SYS_SIGPROCMASK, how, set, retrieve); + + if (result < 0) { + return -result; + } + + return 0; +} +} // namespace mlibc \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/generic/sockets.cpp b/lib/mlibc/sysdeps/aero/generic/sockets.cpp new file mode 100644 index 0000000..0cce3c0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/sockets.cpp @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { +int sys_socket(int family, int type, int protocol, int *fd) { + auto result = syscall(SYS_SOCKET, family, type, protocol); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + auto result = syscall(SYS_BIND, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, + socklen_t addr_length) { + auto result = syscall(SYS_CONNECT, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_listen(int fd, int backlog) { + auto result = syscall(SYS_LISTEN, fd, backlog); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_accept(int sockfd, int *newfd, struct sockaddr *addr_ptr, + socklen_t *addr_length, int flags) { + auto result = syscall(SYS_ACCEPT, sockfd, addr_ptr, addr_length); + + if (result < 0) { + return -result; + } + + *newfd = result; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + auto result = syscall(SYS_SOCK_SEND, fd, hdr, flags); + if (result < 0) + return -result; + + *length = result; + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *msg_hdr, int flags, + ssize_t *length) { + auto result = syscall(SYS_SOCK_RECV, sockfd, msg_hdr, flags); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto result = syscall(SYS_SOCKET_PAIR, domain, type_and_flags, proto, fds); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, + socklen_t *__restrict size) { + (void)fd; + (void)size; + if (layer == SOL_SOCKET && number == SO_PEERCRED) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_PEERCRED is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 4096; + return 0; + } else if (layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is " + "unimplemented, hardcoding SOCK_STREAM\e[39m" + << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and " + "SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else { + mlibc::panicLogger() + << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } + + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, + socklen_t size) { + (void)fd; + (void)buffer; + (void)size; + + if (layer == SOL_SOCKET && number == SO_PASSCRED) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_PASSCRED) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is " + "not implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_KEEPALIVE is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_REUSEADDR is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == AF_NETLINK && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with AF_NETLINK " + "and SO_ACCEPTCONN is unimplemented\e[39m" + << frg::endlog; + return 0; + } else { + mlibc::infoLogger() + << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + return 0; + } +} + +int sys_shutdown(int sockfd, int how) { + auto ret = syscall(SYS_SOCK_SHUTDOWN, sockfd, how); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, NULL); + close(fd); + + if (r) + return r; + + *ret = ifr.ifr_ifindex; + return 0; +} +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/thread.cpp b/lib/mlibc/sysdeps/aero/generic/thread.cpp new file mode 100644 index 0000000..bc9a449 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/thread.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID: + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x1000000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, + size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/thread_entry.S b/lib/mlibc/sysdeps/aero/generic/thread_entry.S new file mode 100644 index 0000000..498fda3 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/thread_entry.S @@ -0,0 +1,10 @@ +.section .text +.global __mlibc_start_thread + +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/aero/generic/time.cpp b/lib/mlibc/sysdeps/aero/generic/time.cpp new file mode 100644 index 0000000..c995148 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/time.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace mlibc { +int sys_setitimer(int which, const struct itimerval *new_value, + struct itimerval *old_value) { + auto result = syscall(SYS_SETITIMER, which, new_value, old_value); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getitimer(int which, struct itimerval *curr_value) { + auto result = syscall(SYS_GETITIMER, which, curr_value); + + if (result < 0) { + return -result; + } + + return 0; +} +} // namespace mlibc \ No newline at end of file -- cgit v1.2.3