user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <aero/syscall.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/thread-entry.hpp>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <frg/vector.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
#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>(
|
||||
/// Slice { .ptr: hello_ptr, .size: hello_size },
|
||||
/// Slice { .ptr: world_ptr, .size: world_size }
|
||||
/// )
|
||||
/// ```
|
||||
static frg::vector<Slice, MemoryAllocator> create_slice(char *const arg[]) {
|
||||
if (arg == nullptr) {
|
||||
return frg::vector<Slice, MemoryAllocator>{getAllocator()};
|
||||
}
|
||||
|
||||
// Find out the length of arg:
|
||||
size_t len = 0;
|
||||
|
||||
while (arg[len] != nullptr) {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
frg::vector<Slice, MemoryAllocator> 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_RTLD
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int sys_thread_setname(void *tcb, const char *name) {
|
||||
mlibc::infoLogger() << "The name of this thread is " << name << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_thread_exit() {
|
||||
syscall(SYS_EXIT);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
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
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/elf/startup.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" uintptr_t *__dlapi_entrystack();
|
||||
|
||||
extern char **environ;
|
||||
|
||||
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::entry_stack.argc, mlibc::entry_stack.argv, environ);
|
||||
exit(result);
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
#include "mlibc/fsfd_target.hpp"
|
||||
#include <aero/syscall.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int sys_fsync(int) {
|
||||
mlibc::infoLogger() << "\e[35mmlibc: fsync is a stub\e[39m" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_fdatasync(int) {
|
||||
mlibc::infoLogger() << "\e[35mmlibc: fdatasync() is a no-op\e[39m" << frg::endlog;
|
||||
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_faccessat(int dirfd, const char *pathname, int mode, int flags) {
|
||||
auto ret = syscall(SYS_ACCESS, dirfd, pathname, strlen(pathname), mode, flags);
|
||||
if(int e = sc_error(ret); e)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_access(const char *filename, int mode) {
|
||||
return sys_faccessat(AT_FDCWD, filename, mode, 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;
|
||||
}
|
||||
|
||||
int sys_symlink(const char *target_path, const char *link_path) {
|
||||
return sys_symlinkat(target_path, AT_FDCWD, link_path);
|
||||
}
|
||||
|
||||
int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) {
|
||||
auto ret = syscall(SYS_SYMLINK_AT, dirfd, target_path, strlen(target_path), link_path, strlen(link_path));
|
||||
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<ino_t>(entry->inode),
|
||||
.d_off = static_cast<off_t>(entry->offset),
|
||||
.d_reclen = static_cast<unsigned short>(entry->reclen),
|
||||
.d_type = static_cast<unsigned char>(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_RTLD
|
||||
#include <stdio.h>
|
||||
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_RTLD
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,9 @@
|
||||
.section .text
|
||||
.global __mlibc_signal_restore
|
||||
|
||||
__mlibc_signal_restore:
|
||||
mov $39, %rax
|
||||
syscall
|
||||
ud2
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
#include <aero/syscall.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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 ret = syscall(SYS_SIGACTION, how, (sc_word_t)action, sigreturn,
|
||||
(sc_word_t)old_action);
|
||||
|
||||
if(int e = sc_error(ret); e)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_sigprocmask(int how, const sigset_t *__restrict set,
|
||||
sigset_t *__restrict retrieve) {
|
||||
|
||||
auto ret = syscall(SYS_SIGPROCMASK, how, set, retrieve);
|
||||
if(int e = sc_error(ret); e)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,266 @@
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/thread-entry.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <abi-bits/in.h>
|
||||
#include <abi-bits/errno.h>
|
||||
|
||||
#include <aero/syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
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_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) {
|
||||
auto ret = syscall(SYS_GETPEERNAME, fd, addr_ptr, &max_addr_length);
|
||||
if(int e = sc_error(ret); e)
|
||||
return e;
|
||||
*actual_length = max_addr_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) {
|
||||
auto ret = syscall(SYS_GETSOCKNAME, fd, addr_ptr, &max_addr_length);
|
||||
if(int e = sc_error(ret); e)
|
||||
return e;
|
||||
*actual_length = max_addr_length;
|
||||
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
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/thread-entry.hpp>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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 *>(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<uintptr_t *>(reinterpret_cast<uintptr_t>(*stack_base) + *stack_size);
|
||||
|
||||
*--sp = reinterpret_cast<uintptr_t>(tcb);
|
||||
*--sp = reinterpret_cast<uintptr_t>(user_arg);
|
||||
*--sp = reinterpret_cast<uintptr_t>(entry);
|
||||
*stack = reinterpret_cast<void *>(sp);
|
||||
return 0;
|
||||
}
|
||||
} // namespace mlibc
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <aero/syscall.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user