genode/repos/base-linux/src/platform/linux_syscalls.h

396 lines
9.9 KiB
C++

/*
* \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-2013 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 <linux/futex.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/syscall.h>
/* Genode includes */
#include <util/string.h>
#include <base/printf.h>
#include <base/snprintf.h>
/***********************************
** Low-level debugging utilities **
***********************************/
extern "C" void wait_for_continue(void);
extern "C" int raw_write_str(const char *str);
#define PRAW(fmt, ...) \
do { \
char str[128]; \
Genode::snprintf(str, sizeof(str), \
ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \
raw_write_str(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 <linux/net.h>
#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, 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 */
};
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 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 *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
{
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_ */