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

396 lines
9.9 KiB
C
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Linux system-call bindings
2011-12-22 16:19:25 +01:00
* \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
2011-12-22 16:19:25 +01:00
* would end up with very nasty cyclic dependencies when using framework
Linux: move process creation into core Genode used to create new processes by directly forking from the respective Genode parent using the process library. The forking process created a PD session at core merely for propagating the PID of the new process into core (for later destruction). This traditional mechanisms has the following disadvantages: First, the PID reported by the creating process to core cannot easily be validated by core. Therefore core has to trust the PD client to not specify a PID of an existing process, which would happen to be killed once the PD session gets destructed. This problem is documented by issue #318. Second, there is no way for a Genode process to detect the failure of its any grandchildren. The immediate parent of a faulting process could use the SIGCHLD-and-waitpid mechanism to observe its children but this mechanism does not work transitively. By performing the process creation exclusively within core, all Genode processes become immediate child processes of core. Hence, core can respond to failures of any of those processes and reflect such conditions via core's session interfaces. Furthermore, the PID associated to a PD session is locally known within core and cannot be forged anymore. In fact, there is actually no need at all to make processes aware of any PIDs of other processes. Please note that this patch breaks the 'chroot' mechanism that comes in the form of the 'os/src/app/chroot' program. Because all processes are forked from core, a chroot'ed process could sneak outside its chroot environment by just creating a new Genode process. To address this issue, the chroot mechanism must be added to core.
2012-08-15 19:14:05 +02:00
* functions such as IPC from the libc back end.
2011-12-22 16:19:25 +01:00
*
* 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.
*/
/*
2013-01-10 21:44:47 +01:00
* Copyright (C) 2008-2013 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* 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>
2011-12-22 16:19:25 +01:00
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/syscall.h>
/* Genode includes */
#include <util/string.h>
#include <base/printf.h>
2012-11-05 17:10:55 +01:00
#include <base/snprintf.h>
2011-12-22 16:19:25 +01:00
/***********************************
** 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 **
*********************************************************/
2011-12-22 16:19:25 +01:00
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)
2011-12-22 16:19:25 +01:00
{
return lx_syscall(SYS_write, fd, buf, count);
2011-12-22 16:19:25 +01:00
}
inline int lx_close(int fd)
2011-12-22 16:19:25 +01:00
{
return lx_syscall(SYS_close, fd);
2011-12-22 16:19:25 +01:00
}
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>
2011-12-22 16:19:25 +01:00
#ifdef SYS_socketcall
inline int lx_socketcall(int call, long *args)
2011-12-22 16:19:25 +01:00
{
int res = lx_syscall(SYS_socketcall, call, args);
return res;
}
inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
2011-12-22 16:19:25 +01:00
{
long args[4] = { domain, type, protocol, (long)sd };
return lx_socketcall(SYS_SOCKETPAIR, args);
2011-12-22 16:19:25 +01:00
}
inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags)
2011-12-22 16:19:25 +01:00
{
long args[3] = { sockfd, (long)msg, flags };
return lx_socketcall(SYS_SENDMSG, args);
2011-12-22 16:19:25 +01:00
}
inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags)
2011-12-22 16:19:25 +01:00
{
long args[3] = { sockfd, (long)msg, flags };
return lx_socketcall(SYS_RECVMSG, args);
2011-12-22 16:19:25 +01:00
}
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);
}
2011-12-22 16:19:25 +01:00
#else
2012-08-14 10:46:11 +02:00
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)
{
2012-08-14 10:46:11 +02:00
return lx_syscall(SYS_getpeername, sockfd, name, namelen);
}
/* TODO add missing socket system calls */
2011-12-22 16:19:25 +01:00
#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 */
2011-12-22 16:19:25 +01:00
LX_SIGUSR1 = 10, /* used for cancel-blocking mechanism */
LX_SIGSEGV = 11, /* exception: segmentation violation */
LX_SIGCHLD = 17, /* child process changed state, i.e., terminated */
2011-12-22 16:19:25 +01:00
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)
2011-12-22 16:19:25 +01:00
{
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);
}
2011-12-22 16:19:25 +01:00
/**
* 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);
}
2011-12-22 16:19:25 +01:00
#endif /* _PLATFORM__LINUX_SYSCALLS_H_ */