/* * \brief Linux system-call bindings * \author Norman Feske * \date 2008-10-22 * * This file is meant to be internally used by the framework. It is not public * interface. * * From within the framework libraries, we have to use the Linux syscall * interface directly rather than relying on convenient libc functions to be * able to link this part of the framework to a custom libc. Otherwise, we * would end up with very nasty cyclic dependencies when using framework * functions such as IPC from the libc back end. * * The Linux syscall interface looks different for 32bit and 64bit system, in * particular regarding the socket interface. On 32bit systems, all socket * operations are invoked via the 'socketcall' syscall. On 64bit systems, the * different socket functions have distinct syscalls. */ /* * Copyright (C) 2008-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _LIB__SYSCALL__LINUX_SYSCALLS_H_ #define _LIB__SYSCALL__LINUX_SYSCALLS_H_ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 /* needed to enable the definition of 'stat64' */ #endif /* Genode includes */ #include #include #include /* * Resolve ambiguity between 'Genode::size_t' and the host's header's 'size_t'. */ #ifndef __SIZE_TYPE__ #define size_t __SIZE_TYPE__ #endif /* Linux includes */ #include /* include first to avoid double definition of '__always_inline' */ #include #include #include #include #include #include #include #include #undef size_t /*********************************** ** Low-level debugging utilities ** ***********************************/ extern "C" void wait_for_continue(void); #define PRAW(fmt, ...) \ do { \ char str[128]; \ Genode::snprintf(str, sizeof(str), \ ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \ Genode::raw(Genode::Cstring(str)); \ } while (0) /********************************************************* ** System-call bindings implemented in syscall library ** *********************************************************/ extern "C" long lx_syscall(int number, ...); extern "C" int lx_clone(int (*fn)(void *), void *child_stack, int flags, void *arg); /***************************************** ** General syscalls used by base-linux ** *****************************************/ inline int lx_write(int fd, const void *buf, Genode::size_t count) { return lx_syscall(SYS_write, fd, buf, count); } inline int lx_close(int fd) { return lx_syscall(SYS_close, fd); } inline int lx_dup2(int fd, int to) { return lx_syscall(SYS_dup2, fd, to); } /***************************************** ** Functions used by the IPC framework ** *****************************************/ #include #ifdef SYS_socketcall inline int lx_socketcall(int call, long *args) { int res = lx_syscall(SYS_socketcall, call, args); return res; } inline int lx_socketpair(int domain, int type, int protocol, int sd[2]) { long args[4] = { domain, type, protocol, (long)sd }; return lx_socketcall(SYS_SOCKETPAIR, args); } inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags) { long args[3] = { sockfd, (long)msg, flags }; return lx_socketcall(SYS_SENDMSG, args); } inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags) { long args[3] = { sockfd, (long)msg, flags }; return lx_socketcall(SYS_RECVMSG, args); } inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen) { long args[3] = { sockfd, (long)name, (long)namelen }; return lx_socketcall(SYS_GETPEERNAME, args); } #else inline int lx_socketpair(int domain, int type, int protocol, int sd[2]) { return lx_syscall(SYS_socketpair, domain, type, protocol, (unsigned long)sd); } inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags) { return lx_syscall(SYS_sendmsg, sockfd, msg, flags); } inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags) { return lx_syscall(SYS_recvmsg, sockfd, msg, flags); } inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen) { return lx_syscall(SYS_getpeername, sockfd, name, namelen); } /* TODO add missing socket system calls */ #endif /* SYS_socketcall */ /******************************************* ** Functions used by the process library ** *******************************************/ inline void lx_exit(int status) { lx_syscall(SYS_exit, status); } inline void lx_exit_group(int status) { lx_syscall(SYS_exit_group, status); } /************************************************************ ** Functions used by the env library and local rm session ** ************************************************************/ /* O_CLOEXEC is a GNU extension so we provide it here */ enum { LX_O_CLOEXEC = 02000000 }; inline void *lx_mmap(void *start, Genode::size_t length, int prot, int flags, int fd, off_t offset) { #ifdef _LP64 return (void *)lx_syscall(SYS_mmap, start, length, prot, flags, fd, offset); #else return (void *)lx_syscall(SYS_mmap2, start, length, prot, flags, fd, offset/4096); #endif /* _LP64 */ } inline int lx_munmap(void *addr, Genode::size_t length) { return lx_syscall(SYS_munmap, addr, length); } /*********************************************************************** ** Functions used by thread lib and core's cancel-blocking mechanism ** ***********************************************************************/ enum { LX_SIGINT = 2, /* used by core to catch Control-C */ LX_SIGILL = 4, /* exception: illegal instruction */ LX_SIGBUS = 7, /* exception: bus error, i.e., bad memory access */ LX_SIGFPE = 8, /* exception: floating point */ LX_SIGUSR1 = 10, /* used for cancel-blocking mechanism */ LX_SIGSEGV = 11, /* exception: segmentation violation */ LX_SIGCHLD = 17, /* child process changed state, i.e., terminated */ LX_SIGCANCEL = 32, /* accoring to glibc, this equals SIGRTMIN, used for killing threads */ LX_NSIG = 64, /* number of different signals supported */ }; struct kernel_sigaction { void (*handler)(int); unsigned long flags; void (*restorer)(void); sigset_t mask; }; inline int lx_sigemptyset(sigset_t *set) { if (set == 0) return -1; Genode::memset(set, 0, sizeof(sigset_t)); return 0; } #ifdef _LP64 extern "C" void lx_restore_rt (void); #endif /** * Simplified binding for sigaction system call */ inline int lx_sigaction(int signum, void (*handler)(int), bool altstack) { struct kernel_sigaction act; act.handler = handler; #ifdef _LP64 /* * The SA_RESTORER flag is not officially documented, but used internally * by the glibc implementation of sigaction(). Without specifying this flag * tgkill() does not work on x86_64. The restorer function gets called * when leaving the signal handler and it should call the rt_sigreturn syscall. */ enum { SA_RESTORER = 0x04000000 }; act.flags = SA_RESTORER; act.restorer = lx_restore_rt; #else act.flags = 0; act.restorer = 0; #endif /* use alternate signal stack if requested */ act.flags |= altstack ? SA_ONSTACK : 0; lx_sigemptyset(&act.mask); return lx_syscall(SYS_rt_sigaction, signum, &act, 0UL, LX_NSIG/8); } /** * Send signal to thread * * This function is used by core to cancel blocking operations of * threads, and by the thread library to kill threads. */ inline int lx_tgkill(int pid, int tid, int signal) { return lx_syscall(SYS_tgkill, pid, tid, signal); } /** * Alternate signal stack (handles also SIGSEGV in a safe way) */ inline int lx_sigaltstack(void *signal_stack, Genode::size_t stack_size) { stack_t stack { signal_stack, 0, stack_size }; return lx_syscall(SYS_sigaltstack, &stack, nullptr); } inline int lx_create_thread(void (*entry)(), void *stack, void *arg) { int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM; /* * The syscall binding for clone does not exist in the FreeBSD libc, which * we are using as libc for Genode. In glibc, clone is implemented as a * assembler binding without external libc references. Hence, we are safe * to rely on the glibc version of 'clone' here. */ return lx_clone((int (*)(void *))entry, stack, flags, arg); } inline pid_t lx_getpid() { return lx_syscall(SYS_getpid); } inline pid_t lx_gettid() { return lx_syscall(SYS_gettid); } inline uid_t lx_getuid() { return lx_syscall(SYS_getuid); } /************************************ ** Functions used by lock library ** ************************************/ struct timespec; inline int lx_nanosleep(const struct timespec *req, struct timespec *rem) { return lx_syscall(SYS_nanosleep, req, rem); } enum { LX_FUTEX_WAIT = FUTEX_WAIT, LX_FUTEX_WAKE = FUTEX_WAKE, }; inline int lx_futex(const int *uaddr, int op, int val) { return lx_syscall(SYS_futex, uaddr, op, val, 0, 0, 0); } /** * Signal set corrsponding to glibc's 'sigset_t' */ class Lx_sigset { private: enum { BITS_PER_LONG = 8 * sizeof(unsigned long), SIGSET_SIZE = LX_NSIG / BITS_PER_LONG }; unsigned long _value[SIGSET_SIZE]; /* * Both '__sigword' and '__sigmask' were macros defined in the glibc * header file 'bits/sigset.h'. The macros were moved in later versions * and, therefore, we implement them explicitly. */ /* return mask that includes the bit for 'signum' only (was __sigmask) */ unsigned long _mask(int signum) { return (1UL) << ((signum - 1) % BITS_PER_LONG); } /* return word index for 'signum' (was __sigword) */ unsigned _word(int signum) { return (signum - 1) / BITS_PER_LONG; } public: /** * Constructor */ Lx_sigset() { Genode::memset(_value, 0, sizeof(_value)); } /** * Constructor * * \param signum set specified entry of sigset */ Lx_sigset(int signum) : Lx_sigset() { _value[_word(signum)] = _mask(signum); } bool is_set(int signum) { return _value[_word(signum)] && _mask(signum); } }; /** * Check if signal is pending * * \return true if signal is pending */ inline bool lx_sigpending(int signum) { Lx_sigset sigset; lx_syscall(SYS_rt_sigpending, &sigset, sizeof(sigset)); return sigset.is_set(signum); } /** * Set signal mask state * * \param signum signal to mask or unmask * \param state mask state for the signal, * true enables the signal, * false blocks the signal */ inline bool lx_sigsetmask(int signum, bool state) { Lx_sigset old_sigmask, sigset(signum); lx_syscall(SYS_rt_sigprocmask, state ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old_sigmask, sizeof(sigset)); return old_sigmask.is_set(signum); } #endif /* _LIB__SYSCALL__LINUX_SYSCALLS_H_ */