/* * \brief Linux system-call wrappers * \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-2011 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #ifndef _PLATFORM__LINUX_SYSCALLS_H_ #define _PLATFORM__LINUX_SYSCALLS_H_ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 /* needed to enable the definition of 'stat64' */ #endif /* Linux includes */ #include #include #include #include #include /* Genode includes */ #include /***************************************** ** Functions used by the IPC framework ** *****************************************/ #include extern "C" long lx_syscall(int number, ...); extern "C" int lx_clone(int (*fn)(void *), void *child_stack, int flags, void *arg); inline Genode::uint16_t lx_bswap16(Genode::uint16_t x) { char v[2] = { (x & 0xff00) >> 8, (x & 0x00ff) >> 0, }; return *(Genode::uint16_t *)v; } inline Genode::uint32_t lx_bswap32(Genode::uint32_t x) { char v[4] = { (x & 0xff000000) >> 24, (x & 0x00ff0000) >> 16, (x & 0x0000ff00) >> 8, (x & 0x000000ff) >> 0, }; return *(Genode::uint32_t *)v; } #define lx_htonl(x) lx_bswap32(x) #define lx_htons(x) lx_bswap16(x) #define lx_ntohs(x) lx_bswap16(x) #ifdef SYS_socketcall inline int lx_socketcall(int call, unsigned long *args) { int res = lx_syscall(SYS_socketcall, call, args); return res; } inline int lx_socket(int domain, int type, int protocol) { unsigned long args[3] = { domain, type, protocol }; return lx_socketcall(SYS_SOCKET, args); } inline int lx_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { unsigned long args[3] = { sockfd, (unsigned long)serv_addr, addrlen }; return lx_socketcall(SYS_CONNECT, args); } inline int lx_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { unsigned long args[3] = { sockfd, (unsigned long)addr, addrlen }; return lx_socketcall(SYS_BIND, args); } inline int lx_getsockname(int s, struct sockaddr *name, socklen_t *namelen) { unsigned long args[3] = { s, (unsigned long)name, (unsigned long)namelen }; return lx_socketcall(SYS_GETSOCKNAME, args); } inline ssize_t lx_recvfrom(int s, void *buf, Genode::size_t len, int flags, struct sockaddr *from, socklen_t *from_len) { unsigned long args[6] = { s, (unsigned long)buf, len, flags, (unsigned long)from, (unsigned long)from_len }; return lx_socketcall(SYS_RECVFROM, args); } inline ssize_t lx_sendto(int s, void *buf, Genode::size_t len, int flags, struct sockaddr *to, socklen_t to_len) { unsigned long args[6] = { s, (unsigned long)buf, len, flags, (unsigned long)to, (unsigned long)to_len }; return lx_socketcall(SYS_SENDTO, args); } #else inline int lx_socket(int domain, int type, int protocol) { return lx_syscall(SYS_socket, domain, type, protocol); } inline int lx_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { return lx_syscall(SYS_connect, sockfd, serv_addr, addrlen); } inline int lx_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { return lx_syscall(SYS_bind, sockfd, addr, addrlen); } inline int lx_getsockname(int s, struct sockaddr *name, socklen_t *namelen) { return lx_syscall(SYS_getsockname, s, name, namelen); } inline ssize_t lx_recvfrom(int s, void *buf, Genode::size_t len, int flags, struct sockaddr *from, socklen_t *from_len) { return lx_syscall(SYS_recvfrom, s, buf, len, flags, from, from_len); } inline ssize_t lx_sendto(int s, void *buf, Genode::size_t len, int flags, struct sockaddr *to, socklen_t to_len) { return lx_syscall(SYS_sendto, s, buf, len, flags, to, to_len); } #endif /* SYS_socketcall */ 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); } /******************************************* ** Functions used by the process library ** *******************************************/ inline int lx_execve(const char *filename, char *const argv[], char *const envp[]) { return lx_syscall(SYS_execve, filename, argv, envp); } 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 int lx_open(const char *pathname, int flags, mode_t mode = 0) { return lx_syscall(SYS_open, pathname, flags, mode); } 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, size_t length) { return lx_syscall(SYS_munmap, addr, length); } /** * Exclude local virtual memory area from being used by mmap * * \param base base address of area to reserve * \param size number of bytes to reserve * * \return start of allocated reserved area, or ~0 on failure */ inline Genode::addr_t lx_vm_reserve(Genode::addr_t base, Genode::size_t size) { /* we cannot include sys/mman.h from here */ enum { LX_MAP_PRIVATE = 0x02, LX_MAP_FIXED = 0x10, LX_MAP_ANONYMOUS = 0x20, LX_PROT_NONE = 0x0 }; int const flags = LX_MAP_ANONYMOUS | LX_MAP_PRIVATE | (base ? LX_MAP_FIXED : 0); void * const res = lx_mmap((void *)base, size, LX_PROT_NONE, flags, -1, 0); if (base) return ((Genode::addr_t)res == base) ? base : ~0; else return (Genode::addr_t)res; } /******************************************************* ** Functions used by core's ram-session support code ** *******************************************************/ inline int lx_mkdir(char const *pathname, mode_t mode) { return lx_syscall(SYS_mkdir, pathname, mode); } inline int lx_ftruncate(int fd, unsigned long length) { return lx_syscall(SYS_ftruncate, fd, length); } inline int lx_unlink(const char *fname) { return lx_syscall(SYS_unlink, fname); } /******************************************************* ** Functions used by core's rom-session support code ** *******************************************************/ inline int lx_stat(const char *path, struct stat64 *buf) { #ifdef _LP64 return lx_syscall(SYS_stat, path, buf); #else return lx_syscall(SYS_stat64, path, buf); #endif } /*********************************************************************** ** Functions used by thread lib and core's cancel-blocking mechanism ** ***********************************************************************/ enum { LX_SIGUSR1 = 10, /* used for cancel-blocking mechanism */ LX_SIGCANCEL = 32, /* accoring to glibc, this equals SIGRTMIN, used for killing threads */ }; 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)) { 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 lx_sigemptyset(&act.mask); return lx_syscall(SYS_rt_sigaction, signum, &act, 0UL, _NSIG/8); } /** * Send signal to process * * This function is used by core to kill processes. */ inline int lx_kill(int pid, int signal) { return lx_syscall(SYS_kill, pid, signal); } /** * 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); } inline int lx_create_thread(void (*entry)(void *), 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 int lx_create_process(int (*entry)(void *), void *stack, void *arg) { int flags = CLONE_VFORK | SIGCHLD; 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); } /** * Signal set corrsponding to glibc's 'sigset_t' */ class Lx_sigset { unsigned long int _value[_SIGSET_NWORDS]; public: /** * Constructor */ Lx_sigset() { } /** * Constructor * * \param signum set specified entry of sigset */ Lx_sigset(int signum) { for (unsigned i = 0; i < _SIGSET_NWORDS; i++) _value[i] = 0; /* * Both '__sigword' and '__sigmask' are macros, defined in the * glibc header file 'bits/sigset.h' and not external functions. * Therefore we can use them here without getting into conflicts * with the linkage of another libc. */ _value[__sigword(signum)] = __sigmask(signum); } bool is_set(int signum) { return _value[__sigword(signum)] && __sigmask(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, _NSIG/8); 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, _NSIG/8); return old_sigmask.is_set(signum); } #endif /* _PLATFORM__LINUX_SYSCALLS_H_ */