Imported Genode release 11.11

This commit is contained in:
Genode Labs
2011-12-22 16:19:25 +01:00
committed by Christian Helmuth
parent 6bcc9aef0e
commit da4e1feaa5
2462 changed files with 320115 additions and 3 deletions

View File

@ -0,0 +1,31 @@
/*
* \brief Printf backend using Linux stdout
* \author Norman Feske
* \date 2006-04-08
*
* This console back-end should only be used by core.
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/console.h>
/* Linux syscall bindings */
#include <linux_syscalls.h>
namespace Genode {
class Core_console : public Console
{
protected:
void _out_char(char c) { lx_write(1, &c, sizeof(c)); }
};
}

57
base-linux/src/base/env/debug.cc vendored Normal file
View File

@ -0,0 +1,57 @@
/*
* \brief Linux-specific debug utilities
* \author Norman Feske
* \date 2009-05-16
*/
/*
* Copyright (C) 2009-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.
*/
/*
* With the enabled 'DEBUG' flag, status information can be printed directly
* via a Linux system call by using the 'raw_write_str' function. This output
* bypasses the Genode 'LOG' mechanism, which is useful for debugging low-level
* code such as a libC back-end.
*/
#define DEBUG 1
#if DEBUG
#include <linux_syscalls.h>
#endif /* DEBUG */
/**
* Write function targeting directly the Linux system call layer and bypassing
* any Genode code.
*/
extern "C" int raw_write_str(const char *str)
{
#if DEBUG
unsigned len = 0;
for (; str[len] != 0; len++);
lx_syscall(SYS_write, (int)1, str, len);
return len;
#endif /* DEBUG */
}
/**
* Debug function waiting until the user presses return
*
* This function is there to delay the execution of a back-end function such
* that we have time to attack the GNU debugger to the running process. Once
* attached, we can continue execution and use 'gdb' for debugging. In the
* normal mode of operation, this function is never used.
*/
extern "C" void wait_for_continue(void)
{
#if DEBUG
char buf[16];
lx_syscall(SYS_read, (int)0, buf, sizeof(buf));
#endif /* DEBUG */
}

97
base-linux/src/base/env/platform_env.cc vendored Normal file
View File

@ -0,0 +1,97 @@
/*
* \brief Support for the Linux-specific environment
* \author Norman Feske
* \date 2008-12-12
*/
/*
* 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.
*/
#include <util/arg_string.h>
#include <base/platform_env.h>
using namespace Genode;
/********************************
** Platform_env::Local_parent **
********************************/
Session_capability
Platform_env::Local_parent::session(Service_name const &service_name,
Session_args const &args)
{
if (strcmp(service_name.string(),
Rm_session::service_name()) == 0)
{
size_t size =
Arg_string::find_arg(args.string(),"size")
.ulong_value(~0);
if (size == 0)
return Parent_client::session(service_name, args);
Rm_session_mmap *rm = new (env()->heap())
Rm_session_mmap(true, size);
return Local_interface::capability(rm);
}
return Parent_client::session(service_name, args);
}
void Platform_env::Local_parent::close(Session_capability session)
{
/*
* Handle non-local capabilities
*/
if (session.valid()) {
Parent_client::close(session);
return;
}
/*
* Detect capability to local RM session
*/
try {
Capability<Rm_session_mmap> rm =
static_cap_cast<Rm_session_mmap>(session);
destroy(env()->heap(), Local_interface::deref(rm));
} catch (Local_interface::Non_local_capability) { }
}
Platform_env::Local_parent::Local_parent(Parent_capability parent_cap)
: Parent_client(parent_cap) { }
/******************
** Platform_env **
******************/
/**
* List of Unix environment variables, initialized by the startup code
*/
extern char **lx_environ;
/**
* Read environment variable as long value
*/
unsigned long Platform_env::_get_env_ulong(const char *key)
{
for (char **curr = lx_environ; curr && *curr; curr++) {
Arg arg = Arg_string::find_arg(*curr, key);
if (arg.valid())
return arg.ulong_value(0);
}
return 0;
}

View File

@ -0,0 +1,283 @@
/*
* \brief Implementation of Linux-specific local region manager
* \author Norman Feske
* \date 2008-10-22
*/
/*
* 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.
*/
#include <base/platform_env.h>
#include <base/thread.h>
#include <linux_dataspace/client.h>
#include <linux_syscalls.h>
using namespace Genode;
static size_t dataspace_size(Dataspace_capability ds)
{
if (ds.valid())
return Dataspace_client(ds).size();
return Local_interface::deref(ds)->size();
}
static bool is_sub_rm_session(Dataspace_capability ds)
{
if (ds.valid())
return false;
try {
Local_interface::deref(ds); }
catch (Local_interface::Non_local_capability) {
return false; }
return true;
}
static void *map_local(Dataspace_capability ds, size_t size, addr_t offset,
bool use_local_addr, addr_t local_addr)
{
Linux_dataspace::Filename fname = Linux_dataspace_client(ds).fname();
fname.buf[sizeof(fname.buf) - 1] = 0;
bool writable = Dataspace_client(ds).writable();
int fd = lx_open(fname.buf, (writable ? O_RDWR : O_RDONLY) | LX_O_CLOEXEC);
if (fd < 0) {
PERR("map_local: Could not open file \"%s\"", fname.buf);
throw Rm_session::Invalid_dataspace();
}
int flags = MAP_SHARED | (use_local_addr ? MAP_FIXED : 0);
int prot = PROT_READ | PROT_EXEC | (writable ? PROT_WRITE : 0);
void *addr = lx_mmap(use_local_addr ? (void*)local_addr : 0, size,
prot, flags, fd, offset);
lx_close(fd);
if (((long)addr < 0) && ((long)addr > -4095)) {
PERR("map_local: return value of mmap is %ld", (long)addr);
throw Rm_session::Region_conflict();
}
return addr;
}
void Platform_env::Rm_session_mmap::_add_to_rmap(Region const &region)
{
if (_rmap.add_region(region) < 0) {
PERR("_add_to_rmap: could not add region to sub RM session");
throw Region_conflict();
}
}
Rm_session::Local_addr
Platform_env::Rm_session_mmap::attach(Dataspace_capability ds,
size_t size, off_t offset,
bool use_local_addr,
Rm_session::Local_addr local_addr)
{
Lock::Guard lock_guard(_lock);
/* only support attach_at for sub RM sessions */
if (_sub_rm && !use_local_addr) {
PERR("Rm_session_mmap::attach: attaching w/o local addr not supported\n");
throw Out_of_metadata();
}
if (offset < 0) {
PERR("Rm_session_mmap::attach: negative offset not supported\n");
throw Region_conflict();
}
size_t const remaining_ds_size = dataspace_size(ds) > (addr_t)offset
? dataspace_size(ds) - (addr_t)offset : 0;
/* determine size of virtual address region */
size_t const region_size = size ? min(remaining_ds_size, size)
: remaining_ds_size;
if (region_size == 0)
throw Region_conflict();
/*
* We have to distinguish the following cases
*
* 1 we are a root RM session and ds is a plain dataspace
* 2 we are a root RM session and ds is a sub RM session
* 2.1 ds is already attached (base != 0)
* 2.2 ds is not yet attached
* 3 we are a sub RM session and ds is a plain dataspace
* 3.1 we are attached to a root RM session
* 3.2 we are not yet attached
* 4 we are a sub RM session and ds is a sub RM session (not supported)
*/
if (_sub_rm) {
/*
* Case 4
*/
if (is_sub_rm_session(ds)) {
PERR("Rm_session_mmap::attach: nesting sub RM sessions is not supported");
throw Invalid_dataspace();
}
/*
* Check for the dataspace to not exceed the boundaries of the
* sub RM session
*/
if (region_size + (addr_t)local_addr > _size) {
PERR("Rm_session_mmap::attach: dataspace does not fit in sub RM session");
throw Region_conflict();
}
_add_to_rmap(Region(local_addr, offset, ds, region_size));
/*
* Case 3.1
*
* This RM session is a sub RM session. If the sub RM session is
* attached (_base > 0), add its attachement offset to the local base
* and map it.
*/
if (_is_attached())
map_local(ds, region_size, offset, true, _base + (addr_t)local_addr);
return (void *)local_addr;
} else {
if (is_sub_rm_session(ds)) {
Dataspace *ds_if = Local_interface::deref<Dataspace>(ds);
Rm_session_mmap *rm = dynamic_cast<Rm_session_mmap *>(ds_if);
if (!rm)
throw Invalid_dataspace();
/*
* Case 2.1
*
* Detect if sub RM session is already attached
*/
if (rm->_base) {
PERR("Rm_session_mmap::attach: mapping a sub RM session twice is not supported");
throw Out_of_metadata();
}
_add_to_rmap(Region(local_addr, offset, ds, region_size));
/*
* Allocate local address range that can hold the entire sub RM
* session.
*/
rm->_base = lx_vm_reserve(use_local_addr ? (addr_t)local_addr : 0,
region_size);
/*
* Cases 2.2, 3.2
*
* The sub rm session was not attached until now but it may have
* been populated with dataspaces. Go through all regions an map
* each of them.
*/
for (int i = 0; i < Region_map::MAX_REGIONS; i++) {
Region region = rm->_rmap.region(i);
if (!region.used())
continue;
map_local(region.dataspace(), region.size(), region.offset(),
true, rm->_base + region.start() + region.offset());
}
return rm->_base;
} else {
/*
* Case 1
*
* Boring, a plain dataspace is attached to a root RM session.
*/
void *addr = map_local(ds, region_size, offset, use_local_addr, local_addr);
_add_to_rmap(Region((addr_t)addr, offset, ds, region_size));
return addr;
}
}
}
void Platform_env::Rm_session_mmap::detach(Rm_session::Local_addr local_addr)
{
Lock::Guard lock_guard(_lock);
/*
* Cases
*
* 1 we are root RM
* 2 we are sub RM (region must be normal dataspace)
* 2.1 we are not attached
* 2.2 we are attached to a root RM
*/
Region region = _rmap.lookup(local_addr);
if (!region.used())
return;
/*
* Remove meta data from region map
*/
_rmap.remove_region(local_addr);
if (_sub_rm) {
/*
* Case 2.1, 2.2
*
* By removing a region from an attached sub RM session we mark the
* corresponding local address range as reserved. A plain 'munmap'
* would mark this range as free to use for the root RM session, which
* we need to prevent.
*
* If we are not attached, no local address-space manipulation is
* needed.
*/
if (_is_attached())
lx_vm_reserve((addr_t)local_addr + _base, region.size());
} else {
/*
* Case 1
*
* We need no distiction between detaching normal dataspaces and
* sub RM session. In both cases, we simply mark the local address
* range as free.
*/
lx_munmap(local_addr, region.size());
}
/*
* If the detached dataspace is sub RM session, mark it as detached
*/
if (is_sub_rm_session(region.dataspace())) {
Dataspace *ds_if = Local_interface::deref<Dataspace>(region.dataspace());
Rm_session_mmap *rm = dynamic_cast<Rm_session_mmap *>(ds_if);
if (rm)
rm->_base = 0;
}
}

View File

@ -0,0 +1,358 @@
/*
* \brief Socket-based IPC implementation for Linux
* \author Norman Feske
* \author Christian Helmuth
* \date 2011-10-11
*
* We create two sockets under lx_rpath() for each thread: client and server
* role. The naming is 'ep-<thread id>-<role>'. The socket descriptors are
* cached in Thread_base::_tid.
*
* Currently two socket files are needed, as the client does not send the reply
* socket access-rights in a combined message with the payload. In the future,
* only server sockets must be bound in lx_rpath().
*
* The current request message layout is:
*
* long server_local_name;
* long client_thread_id;
* int opcode;
* ...payload...
*
* Response messages look like this:
*
* long scratch_word;
* int exc_code;
* ...payload...
*
* All fields are naturally aligned, i.e., aligend on 4 or 8 byte boundaries on
* 32-bit resp. 64-bit systems.
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <base/ipc.h>
#include <base/thread.h>
#include <base/blocking.h>
#include <base/snprintf.h>
/* Linux includes */
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <linux_syscalls.h>
#include <linux_rpath.h>
extern "C" void wait_for_continue(void);
extern "C" int raw_write_str(const char *str);
#define PRAW(fmt, ...) \
do { \
char str[128]; \
snprintf(str, sizeof(str), \
ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \
raw_write_str(str); \
} while (0)
using namespace Genode;
/**
* Utility: Create socket address for thread ID and role (client/server)
*/
static void lx_create_sockaddr(sockaddr_un *addr, long thread_id, char const *role)
{
addr->sun_family = AF_UNIX;
Genode::snprintf(addr->sun_path, sizeof(addr->sun_path), "%s/ep-%ld-%s",
lx_rpath(), thread_id, role);
}
/**
* Utility: Create a socket descriptor and file for given thread and role
*/
static int create_socket(long thread_id, char const *role)
{
int sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sd < 0) return -1;
sockaddr_un addr;
lx_create_sockaddr(&addr, thread_id, role);
/* make sure bind succeeds */
lx_unlink(addr.sun_path);
if (lx_bind(sd, (sockaddr *)&addr, sizeof(addr)) < 0)
return -2;
return sd;
}
/**
* Utility: Unlink socket file and close descriptor
*
* XXX Currently, socket destruction is missing. The client socket could be
* used from multiple Ipc_client objects. A safe destruction would need
* reference counting.
*/
//static void destroy_socket(int sd, long thread_id, char const *role)
//{
// sockaddr_un addr;
// lx_create_sockaddr(&addr, thread_id, role);
//
// lx_unlink(addr.sun_path);
// lx_close(sd);
//}
/**
* Get client-socket descriptor for main thread
*/
static int main_client_socket()
{
static int sd = create_socket(lx_gettid(), "client");
return sd;
}
/**
* Utility: Get server socket for given thread
*/
static int server_socket(Thread_base *thread)
{
/*
* Main thread uses Ipc_server for sleep_forever() only.
*/
if (!thread)
return lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (thread->tid().server == -1)
thread->tid().server = create_socket(thread->tid().tid, "server");
return thread->tid().server;
}
/**
* Utility: Get client socket for given thread
*/
static int client_socket(Thread_base *thread)
{
if (!thread) return main_client_socket();
if (thread->tid().client == -1)
thread->tid().client = create_socket(thread->tid().tid, "client");
return thread->tid().client;
}
/**
* Utility: Send message to thread via given socket descriptor
*/
static void send_to(int sd, long thread_id, char const *target_role,
void *msg, Genode::size_t msg_len)
{
sockaddr_un addr;
lx_create_sockaddr(&addr, thread_id, target_role);
int res = lx_sendto(sd, msg, msg_len, 0, (sockaddr *)&addr, sizeof(addr));
if (res < 0) {
PRAW("Send error: %d with %s in %d", res, addr.sun_path, lx_gettid());
wait_for_continue();
throw Ipc_error();
}
}
/**
* Utility: Receive message via given socket descriptor
*/
static void recv_from(int sd, void *buf, Genode::size_t buf_len)
{
socklen_t fromlen;
int res = lx_recvfrom(sd, buf, buf_len, 0, 0, &fromlen);
if (res < 0) {
if ((-res) == EINTR)
throw Blocking_canceled();
else {
PRAW("Recv error: %d in %d", res, lx_gettid());
wait_for_continue();
throw Ipc_error();
}
}
}
/*****************
** Ipc_ostream **
*****************/
/*
* XXX This class will be removed soon.
*/
void Ipc_ostream::_prepare_next_send()
{
PRAW("unexpected call to %s (%p)", __PRETTY_FUNCTION__, this);
}
void Ipc_ostream::_send()
{
PRAW("unexpected call to %s (%p)", __PRETTY_FUNCTION__, this);
}
Ipc_ostream::Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg):
Ipc_marshaller(snd_msg->buf, snd_msg->size()), _snd_msg(snd_msg), _dst(dst)
{ }
/*****************
** Ipc_istream **
*****************/
/*
* XXX This class will be removed soon.
*/
void Ipc_istream::_prepare_next_receive()
{
PRAW("unexpected call to %s (%p)", __PRETTY_FUNCTION__, this);
}
void Ipc_istream::_wait()
{
PRAW("unexpected call to %s (%p)", __PRETTY_FUNCTION__, this);
}
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
: Ipc_unmarshaller(rcv_msg->buf, rcv_msg->size()),
Native_capability(lx_gettid(), 0),
_rcv_msg(rcv_msg), _rcv_cs(-1)
{ }
Ipc_istream::~Ipc_istream() { }
/****************
** Ipc_client **
****************/
void Ipc_client::_prepare_next_call()
{
/* prepare next request in buffer */
long local_name = _dst.local_name();
long tid = Native_capability::tid();
_write_offset = 0;
_write_to_buf(local_name);
_write_to_buf(tid);
/* prepare response buffer */
_read_offset = sizeof(long);
}
void Ipc_client::_call()
{
if (_dst.valid()) {
send_to(_rcv_cs, _dst.tid(), "server",
_snd_msg->buf, _write_offset);
recv_from(_rcv_cs, _rcv_msg->buf, _rcv_msg->size());
}
_prepare_next_call();
}
Ipc_client::Ipc_client(Native_capability const &srv,
Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
: Ipc_istream(rcv_msg), Ipc_ostream(srv, snd_msg), _result(0)
{
_rcv_cs = client_socket(Thread_base::myself());
_prepare_next_call();
}
/****************
** Ipc_server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
/* skip server-local name */
_read_offset = sizeof(long);
/* read client thread id from request buffer */
long tid;
if (_reply_needed) {
_read_from_buf(tid);
_dst = Native_capability(tid, 0); /* only _tid member is used */
}
/* prepare next reply */
_write_offset = 0;
long local_name = _dst.local_name();
_write_to_buf(local_name); /* XXX unused, needed by de/marshaller */
/* leave space for exc code at the beginning of the msgbuf */
_write_offset += align_natural(sizeof(int));
}
void Ipc_server::_wait()
{
/* wait for new server request */
try {
recv_from(_rcv_cs, _rcv_msg->buf, _rcv_msg->size());
} catch (Blocking_canceled) { }
/* now we have a request to reply, determine reply destination */
_reply_needed = true;
_prepare_next_reply_wait();
}
void Ipc_server::_reply()
{
try {
send_to(_rcv_cs, _dst.tid(), "client", _snd_msg->buf, _write_offset);
} catch (Ipc_error) { }
_prepare_next_reply_wait();
}
void Ipc_server::_reply_wait()
{
/* when first called, there was no request yet */
if (_reply_needed)
send_to(_rcv_cs, _dst.tid(), "client", _snd_msg->buf, _write_offset);
_wait();
}
Ipc_server::Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
: Ipc_istream(rcv_msg),
Ipc_ostream(Native_capability(), snd_msg), _reply_needed(false)
{
_rcv_cs = server_socket(Thread_base::myself());
_prepare_next_reply_wait();
}

View File

@ -0,0 +1,80 @@
/*
* \brief Linux-specific helper functions for the Lock implementation
* \author Norman Feske
* \date 2009-07-20
*
* This file serves as adapter between the generic lock implementation
* in 'lock.cc' and the underlying kernel.
*
* For documentation about the interface, please revisit the 'base-pistachio'
* implementation.
*/
/*
* Copyright (C) 2009-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.
*/
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
/* Linux includes */
#include <linux_syscalls.h>
/**
* Resolve 'Thread_base::myself' when not linking the thread library
*
* This weak symbol is primarily used by test cases. Most other Genode programs
* use the thread library. If the thread library is not used, 'myself' can only
* be called by the main thread, for which 'myself' is defined as zero.
*/
Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself() { return 0; }
static inline void thread_yield()
{
struct timespec ts = { 0, 1000 };
lx_nanosleep(&ts, 0);
}
static bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
{
lx_tgkill(tid.pid, tid.tid, LX_SIGUSR1);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
return Genode::Native_thread_id(lx_gettid(), lx_getpid());
}
static inline Genode::Native_thread_id thread_invalid_id()
{
return Genode::Native_thread_id();
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return (tid.pid != 0);
}
static inline void thread_switch_to(Genode::Native_thread_id tid)
{
thread_yield();
}
static inline void thread_stop_myself()
{
struct timespec ts = { 1000, 0 };
while (lx_nanosleep(&ts, 0) == 0);
}

View File

@ -0,0 +1,203 @@
/*
* \brief Implementation of process creation for Linux
* \author Norman Feske
* \date 2006-07-06
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/elf.h>
#include <base/env.h>
#include <base/process.h>
#include <base/printf.h>
#include <base/snprintf.h>
#include <linux_dataspace/client.h>
/* Framework-internal includes */
#include <linux_syscalls.h>
using namespace Genode;
Dataspace_capability Process::_dynamic_linker_cap;
/**
* Argument frame for passing 'execve' paremeters through 'clone'
*/
struct execve_args {
const char *filename;
char *const*argv;
char *const*envp;
};
/**
* Startup code of the new child process
*/
static int _exec_child(struct execve_args *arg)
{
return lx_execve(arg->filename, arg->argv, arg->envp);
}
/**
* List of Unix environment variables, initialized by the startup code
*/
extern char **lx_environ;
/**
* Read environment variable as string
*
* If no matching key exists, return an empty string.
*/
static const char *get_env(const char *key)
{
Genode::size_t key_len = strlen(key);
for (char **curr = lx_environ; curr && *curr; curr++)
if ((Genode::strcmp(*curr, key, key_len) == 0) && (*curr)[key_len] == '=')
return (const char *)(*curr + key_len + 1);
return "";
}
/**
* Check for dynamic ELF header
*/
static bool _check_dynamic_elf(Dataspace_capability elf_ds_cap)
{
/* attach ELF locally */
addr_t elf_addr;
try { elf_addr = env()->rm_session()->attach(elf_ds_cap); }
catch (...) { return false; }
/*
* If attach is called within core, it will return zero because
* Linux uses Core_rm_session.
*/
if (!elf_addr) return false;
/* read program header and interpreter */
Elf_binary elf((addr_t)elf_addr);
env()->rm_session()->detach((void *)elf_addr);
return elf.is_dynamically_linked();
}
const char *Process::_priv_pd_args(Parent_capability parent_cap,
Dataspace_capability elf_data_ds_cap,
const char *name, char *const argv[])
{
/*
* Serialize calls of this function because it uses the static 'envbuf' and
* 'stack' variables.
*/
static Lock _priv_pd_args_lock;
Lock::Guard _lock_guard(_priv_pd_args_lock);
/* check for dynamic program header */
if (_check_dynamic_elf(elf_data_ds_cap)) {
if (!_dynamic_linker_cap.valid()) {
PERR("Dynamically linked file found, but no dynamic linker binary present");
return 0;
}
elf_data_ds_cap = _dynamic_linker_cap;
}
/* pass parent capability as environment variable to the child */
enum { ENV_STR_LEN = 256 };
static char envbuf[5][ENV_STR_LEN];
Genode::snprintf(envbuf[0], ENV_STR_LEN, "parent_tid=%ld",
parent_cap.tid());
Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu",
parent_cap.local_name());
Genode::snprintf(envbuf[2], ENV_STR_LEN, "DISPLAY=%s",
get_env("DISPLAY"));
Genode::snprintf(envbuf[3], ENV_STR_LEN, "HOME=%s",
get_env("HOME"));
Genode::snprintf(envbuf[4], ENV_STR_LEN, "LD_LIBRARY_PATH=%s",
get_env("LD_LIBRARY_PATH"));
char *env[] = { &envbuf[0][0], &envbuf[1][0], &envbuf[2][0],
&envbuf[3][0], &envbuf[4][0], 0 };
/* determine name of binary to start */
Linux_dataspace_client elf_data_ds(elf_data_ds_cap);
Linux_dataspace::Filename fname = elf_data_ds.fname();
fname.buf[sizeof(fname.buf) - 1] = 0;
/* prefix name of Linux program (helps killing some zombies) */
char pname_buf[9 + Linux_dataspace::FNAME_LEN];
snprintf(pname_buf, sizeof(pname_buf), "[Genode] %s", name);
/* it may happen, that argv is null */
char *argv_buf[2];
if (!argv) {
argv_buf[0] = pname_buf;
argv_buf[1] = 0;
argv = argv_buf;
} else
((char **)argv)[0] = pname_buf;
/*
* We cannot create the new process via 'fork()' because all our used
* memory including stack memory is backed by dataspaces, which had been
* mapped with the 'MAP_SHARED' flag. Therefore, after being created, the
* new process starts using the stack with the same physical memory pages
* as used by parent process. This would ultimately lead to stack
* corruption. To prevent both processes from concurrently accessing the
* same stack, we pause the execution of the parent until the child calls
* 'execve'. From then on, the child has its private memory layout. The
* desired behaviour is normally provided by 'vfork' but we use the more
* modern 'clone' call for this purpose.
*/
enum { STACK_SIZE = 4096 };
static char stack[STACK_SIZE]; /* initial stack used by the child until
calling 'execve' */
/*
* Argument frame as passed to 'clone'. Because, we can only pass a single
* pointer, all arguments are embedded within the 'execve_args' struct.
*/
struct execve_args arg = {
fname.buf,
argv,
env
};
pid_t pid = lx_create_process((int (*)(void *))_exec_child,
stack + STACK_SIZE - sizeof(umword_t), &arg);
/*
* We create a pseudo pd session with the new pd's pid as argument
* to enable Core to kill the process when the pd session gets closed.
*/
snprintf(_priv_pd_argbuf, sizeof(_priv_pd_argbuf), "PID=%d", pid);
return _priv_pd_argbuf;
}
Process::Process(Dataspace_capability elf_data_ds_cap,
Ram_session_capability ram_session_cap,
Cpu_session_capability cpu_session_cap,
Rm_session_capability rm_session_cap,
Parent_capability parent_cap,
const char *name,
char *const argv[])
:
_pd(_priv_pd_args(parent_cap, elf_data_ds_cap, name, argv)),
_cpu_session_client(Cpu_session_capability()),
_rm_session_client(Rm_session_capability())
{ }
Process::~Process() { }

View File

@ -0,0 +1,115 @@
/*
* \brief Implementation of the Thread API via Linux threads
* \author Norman Feske
* \date 2006-06-13
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/env.h>
#include <base/thread.h>
#include <base/snprintf.h>
#include <base/sleep.h>
/* Linux syscall bindings */
#include <linux_syscalls.h>
using namespace Genode;
static void empty_signal_handler(int) { }
/**
* Signal handler for killing the thread
*/
static void thread_exit_signal_handler(int) { lx_exit(0); }
static void thread_start(void *)
{
/*
* Set signal handler such that canceled system calls get not
* transparently retried after a signal gets received.
*/
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
Thread_base::myself()->entry();
sleep_forever();
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
/*
* Kill thread until it is really really dead
*
* We use the 'tgkill' system call to kill the thread. This system call
* returns immediately and just flags the corresponding signal at the
* targeted thread context. However, the thread still lives until the
* signal flags are evaluated. When leaving this function, however, we want
* to be sure that the thread is no more executing any code such that we
* an safely free and unmap the thread's stack. So we call 'tgkill' in a
* loop until we get an error indicating that the thread does not exists
* anymore.
*/
for (;;) {
/* destroy thread locally */
int ret = lx_tgkill(_tid.pid, _tid.tid, LX_SIGCANCEL);
if (ret < 0) break;
/* if thread still exists, wait a bit and try to kill it again */
struct timespec ts = { 0, 500 };
lx_nanosleep(&ts, 0);
}
/* inform core about the killed thread */
env()->cpu_session()->kill_thread(_thread_cap);
}
void Thread_base::start()
{
/*
* The first time we enter this code path, the 'start' function is
* called by the main thread as there cannot exist other threads
* without executing this function. When first called, we initialize
* the thread lib here.
*/
static bool threadlib_initialized = false;
if (!threadlib_initialized) {
lx_sigaction(LX_SIGCANCEL, thread_exit_signal_handler);
threadlib_initialized = true;
}
/* align initial stack to 16 byte boundary */
void *thread_sp = (void *)((addr_t)(_context->stack) & ~0xf);
_tid.tid = lx_create_thread(thread_start, thread_sp, this);
_tid.pid = lx_getpid();
/*
* Inform core about the new thread by calling create_thread and encoding
* the thread's PID in the thread-name argument.
*/
char name_and_pid[Cpu_session::THREAD_NAME_LEN + 2*16];
snprintf(name_and_pid, sizeof(name_and_pid), "%s:0x%x:0x%x",
_context->name, _tid.tid, _tid.pid);
_thread_cap = env()->cpu_session()->create_thread(name_and_pid);
}
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
}

View File

@ -0,0 +1,112 @@
/*
* \brief Linux-specific support code for the thread API
* \author Norman Feske
* \date 2010-01-13
*/
/*
* Copyright (C) 2010-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.
*/
/* Genode includes */
#include <rm_session/rm_session.h>
#include <ram_session/ram_session.h>
#include <base/printf.h>
#include <base/thread.h>
/* Linux includes */
#include <linux_syscalls.h>
#include <sys/mman.h>
/**
* Region-manager session for allocating thread contexts
*
* This class corresponds to the managed dataspace that is normally
* used for organizing thread contexts with the thread context area.
* It "emulates" the sub address space by adjusting the local address
* argument to 'attach' with the offset of the thread context area.
*/
class Context_area_rm_session : public Genode::Rm_session
{
public:
/**
* Attach backing store to thread-context area
*/
Local_addr attach(Genode::Dataspace_capability ds_cap,
Genode::size_t size, Genode::off_t offset,
bool use_local_addr, Local_addr local_addr)
{
using namespace Genode;
/* convert context-area-relative to absolute virtual address */
addr_t addr = local_addr;
addr += Thread_base::CONTEXT_AREA_VIRTUAL_BASE;
/* use anonymous mmap for allocating stack backing store */
int flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE;
int prot = PROT_READ | PROT_WRITE;
void *res = lx_mmap((void*)addr, size, prot, flags, -1, 0);
if ((addr_t)res != addr)
throw Region_conflict();
return local_addr;
}
void detach(Local_addr local_addr) {
PWRN("context area detach from 0x%p - not implemented", (void *)local_addr); }
Genode::Pager_capability add_client(Genode::Thread_capability) {
return Genode::Pager_capability(); }
void fault_handler(Genode::Signal_context_capability) { }
State state() { return State(); }
Genode::Dataspace_capability dataspace() {
return Genode::Dataspace_capability(); }
};
class Context_area_ram_session : public Genode::Ram_session
{
public:
Genode::Ram_dataspace_capability alloc(Genode::size_t size) {
return Genode::Ram_dataspace_capability(); }
void free(Genode::Ram_dataspace_capability) { }
int ref_account(Genode::Ram_session_capability) { return 0; }
int transfer_quota(Genode::Ram_session_capability, Genode::size_t) { return 0; }
size_t quota() { return 0; }
size_t used() { return 0; }
};
/**
* Return single instance of the context-area RM and RAM session
*/
namespace Genode {
Rm_session *env_context_area_rm_session()
{
static Context_area_rm_session inst;
return &inst;
}
Ram_session *env_context_area_ram_session()
{
static Context_area_ram_session inst;
return &inst;
}
}

View File

@ -0,0 +1,47 @@
/*
* \brief Capability allocation service
* \author Norman Feske
* \date 2006-06-26
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__CAP_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__CAP_SESSION_COMPONENT_H_
#include <cap_session/cap_session.h>
#include <base/rpc_server.h>
#include <base/lock.h>
namespace Genode {
class Cap_session_component : public Rpc_object<Cap_session>
{
private:
static long _unique_id_cnt;
static Lock &_lock()
{
static Lock static_lock;
return static_lock;
}
public:
Native_capability alloc(Native_capability ep)
{
Lock::Guard lock_guard(_lock());
return Native_capability(ep.tid(), ++_unique_id_cnt);
}
void free(Native_capability cap) { }
};
}
#endif /* _CORE__INCLUDE__LINUX__CAP_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,91 @@
/*
* \brief Core-internal dataspace representation on Linux
* \author Norman Feske
* \date 2006-05-19
*
* On Linux userland, we do not deal with physical memory. Instead,
* we create a file for each dataspace that is to be mmapped.
* Therefore, the allocator is not really used for allocating
* memory but only as a container for quota.
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__DATASPACE_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__DATASPACE_COMPONENT_H_
#include <linux_dataspace/linux_dataspace.h>
#include <util/string.h>
#include <util/misc_math.h>
#include <base/rpc_server.h>
#include <base/printf.h>
namespace Genode {
class Dataspace_component : public Rpc_object<Linux_dataspace>
{
private:
size_t _size; /* size of dataspace in bytes */
addr_t _addr; /* meaningless on linux */
Filename _fname; /* filename for mmap */
bool _writable; /* false if read-only */
public:
/**
* Constructor
*/
Dataspace_component(size_t size, addr_t addr, bool writable)
: _size(size), _addr(addr), _writable(writable) { }
/**
* Default constructor returns invalid dataspace
*/
Dataspace_component() : _size(0), _addr(0), _writable(false) { }
/**
* This constructor is only provided for compatibility
* reasons and should not be used.
*/
Dataspace_component(size_t size, addr_t core_local_addr,
addr_t phys_addr, bool write_combined,
bool writable)
: _size(size), _addr(phys_addr)
{
PWRN("Should only be used for IOMEM and not within Linux.");
}
/**
* Define/request corresponding filename of dataspace
*
* To use dataspaces as shared memory objects on Linux, we have to
* assign a file to each dataspace. This way, multiple Linux process
* can mmap this file.
*/
void fname(const char *fname) { strncpy(_fname.buf, fname, sizeof(_fname.buf)); }
/*************************
** Dataspace interface **
*************************/
size_t size() { return _size; }
addr_t phys_addr() { return _addr; }
bool writable() { return _writable; }
/****************************************
** Linux-specific dataspace interface **
****************************************/
Filename fname() { return _fname; }
};
}
#endif /* _CORE__INCLUDE__LINUX__DATASPACE_COMPONENT_H_ */

View File

@ -0,0 +1,64 @@
/*
* \brief Core-specific instance of the IO_MEM session interface (Linux)
* \author Christian Helmuth
* \date 2007-09-14
*/
/*
* Copyright (C) 2007-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 _CORE__INCLUDE__LINUX__IO_MEM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__IO_MEM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/printf.h>
#include <base/rpc_server.h>
#include <io_mem_session/io_mem_session.h>
/* core includes */
#include <dataspace_component.h>
namespace Genode {
class Io_mem_session_component : public Rpc_object<Io_mem_session>
{
public:
/**
* Constructor
*
* \param io_mem_alloc MMIO region allocator
* \param ram_alloc RAM allocator that will be checked for
* region collisions
* \param ds_ep entry point to manage the dataspace
* corresponding the io_mem session
* \param args session construction arguments, in
* particular MMIO region base, size and
* caching demands
*/
Io_mem_session_component(Range_allocator *io_mem_alloc,
Range_allocator *ram_alloc,
Rpc_entrypoint *ds_ep,
const char *args);
/**
* Destructor
*/
~Io_mem_session_component() { }
/*****************************
** Io-mem session interface **
*****************************/
Io_mem_dataspace_capability dataspace() {
return Io_mem_dataspace_capability(); }
};
}
#endif /* _CORE__INCLUDE__LINUX__IO_MEM_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,60 @@
/*
* \brief Core-specific instance of the IRQ session interface for Linux
* \author Christian Helmuth
* \date 2007-09-13
*/
/*
* Copyright (C) 2007-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 _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_
#include <util/list.h>
#include <base/lock.h>
#include <base/rpc_server.h>
#include <irq_session/irq_session.h>
namespace Genode {
class Irq_session_component : public List<Irq_session_component>::Element
{
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args) { }
/**
* Destructor
*/
~Irq_session_component() { }
/**
* Return capability to this session
*
* Capability is always invalid under Linux.
*/
Session_capability cap() const { return Session_capability(); }
/***************************
** Irq session interface **
***************************/
void wait_for_irq() { }
};
}
#endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,61 @@
/*
* \brief CORE-specific instance of the PD session interface for Linux
* \author Norman Feske
* \date 2006-08-14
*
* On Linux, we use a pd session only for keeping the information about the
* existence of protection domains to enable us to destruct all pds of a whole
* subtree. A pd is killed by CORE when closing the corresponding pd session.
* The PID of the process is passed to CORE as an argument of the session
* construction.
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_
/* Genode includes */
#include <util/arg_string.h>
#include <base/printf.h>
#include <base/rpc_server.h>
#include <pd_session/pd_session.h>
/* local includes */
#include "platform.h"
namespace Genode {
class Pd_session_component : public Rpc_object<Pd_session>
{
private:
unsigned long _pid;
public:
Pd_session_component(Rpc_entrypoint *thread_ep,
const char *args);
~Pd_session_component();
/****************************/
/** Pd session interface **/
/****************************/
/*
* This interface is not functional on Linux.
*/
int bind_thread(Thread_capability thread);
int assign_parent(Parent_capability);
};
}
#endif /* _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,62 @@
/*
* \brief Linux platform
* \author Christian Helmuth
* \author Norman Feske
* \date 2007-09-10
*/
/*
* Copyright (C) 2007-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 _CORE__INCLUDE__LINUX__PLATFORM_H_
#define _CORE__INCLUDE__LINUX__PLATFORM_H_
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <base/lock_guard.h>
#include <platform_generic.h>
#include <platform_pd.h>
#include <platform_thread.h>
namespace Genode {
using namespace Genode;
class Platform : public Platform_generic
{
private:
Synchronized_range_allocator<Allocator_avl> _ram_alloc; /* RAM allocator */
public:
/**
* Constructor
*/
Platform();
/********************************
** Generic platform interface **
********************************/
Range_allocator *core_mem_alloc() { return &_ram_alloc; }
Range_allocator *ram_alloc() { return &_ram_alloc; }
Range_allocator *io_mem_alloc() { return 0; }
Range_allocator *io_port_alloc() { return 0; }
Range_allocator *irq_alloc() { return 0; }
Range_allocator *region_alloc() { return 0; }
addr_t vm_start() const { return 0; }
size_t vm_size() const { return 0; }
Rom_fs *rom_fs() { return 0; }
void wait_for_exit();
};
}
#endif /* _CORE__INCLUDE__PLATFORM_H_ */

View File

@ -0,0 +1,25 @@
/*
* \brief Linux protection domain facility
* \author Norman Feske
* \date 2006-06-13
*
* Pretty dumb.
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__PLATFORM_PD_H_
#define _CORE__INCLUDE__LINUX__PLATFORM_PD_H_
namespace Genode {
class Platform_pd
{ };
}
#endif /* _CORE__INCLUDE__LINUX__PLATFORM_PD_H_ */

View File

@ -0,0 +1,65 @@
/*
* \brief Linux thread facility
* \author Norman Feske
* \date 2006-06-13
*
* Pretty dumb.
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_
#define _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_
#include <base/pager.h>
#include <base/thread_state.h>
namespace Genode {
class Platform_thread
{
private:
unsigned long _tid;
unsigned long _pid;
char _name[32];
public:
/**
* Constructor
*/
Platform_thread(const char *name, unsigned priority);
/**
* Cancel currently blocking operation
*/
void cancel_blocking();
/**
* Pause this thread
*/
void pause();
/**
* Resume this thread
*/
void resume();
/**
* Dummy implementation of platform-thread interface
*/
Pager_object *pager() { return 0; }
void pager(Pager_object *) { }
int start(void *ip, void *sp) { return 0; }
int state(Thread_state *state_dst) { return 0; }
const char *name() { return _name; }
};
}
#endif /* _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_ */

View File

@ -0,0 +1,64 @@
/*
* \brief Core-specific instance of the RM session interface
* \author Christian Helmuth
* \date 2006-07-17
*
* Dummies for Linux platform
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__LINUX__RM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__LINUX__RM_SESSION_COMPONENT_H_
/* Genode */
#include <base/pager.h>
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <rm_session/rm_session.h>
namespace Genode {
struct Rm_client;
class Rm_session_component : public Rpc_object<Rm_session>
{
public:
Rm_session_component(Rpc_entrypoint *ds_ep,
Rpc_entrypoint *thread_ep,
Allocator *md_alloc,
size_t ram_quota,
Pager_entrypoint *pager_ep,
addr_t vm_start,
size_t vm_size) { }
void upgrade_ram_quota(size_t ram_quota) { }
Local_addr attach(Dataspace_capability, size_t, off_t, bool, Local_addr) {
return (addr_t)0; }
void detach(Local_addr) { }
Pager_capability add_client(Thread_capability) {
return Pager_capability(); }
void fault_handler(Signal_context_capability) { }
State state() { return State(); }
Dataspace_capability dataspace() { return Dataspace_capability(); }
void dissolve(Rm_client *cl) { }
};
struct Rm_member { Rm_session_component *member_rm_session() { return 0; } };
struct Rm_client : Pager_object, Rm_member { };
}
#endif /* _CORE__INCLUDE__LINUX__RM_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,27 @@
/*
* \brief Linux-specific IO_MEM service
* \author Christian Helmuth
* \date 2006-09-01
*/
/*
* Copyright (C) 2006-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.
*/
#include <base/printf.h>
#include <io_mem_session_component.h>
using namespace Genode;
Io_mem_session_component::Io_mem_session_component(Range_allocator *io_mem_alloc,
Range_allocator *ram_alloc,
Rpc_entrypoint *ds_ep,
const char *args)
{
PWRN("no io_mem support on Linux (args=\"%s\")", args);
}

View File

@ -0,0 +1,59 @@
/*
* \brief Linux-specific IO_PORT service
* \author Christian Helmuth
* \date 2007-04-18
*/
/*
* Copyright (C) 2007-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.
*/
#include <base/printf.h>
#include <root/root.h>
#include "io_port_session_component.h"
using namespace Genode;
unsigned char Io_port_session_component::inb(unsigned short address) {
return 0; }
unsigned short Io_port_session_component::inw(unsigned short address) {
return 0; }
unsigned Io_port_session_component::inl(unsigned short address) {
return 0; }
void Io_port_session_component::outb(unsigned short address, unsigned char value) {
}
void Io_port_session_component::outw(unsigned short address, unsigned short value) {
}
void Io_port_session_component::outl(unsigned short address, unsigned value) {
}
Io_port_session_component::Io_port_session_component(Range_allocator *io_port_alloc,
const char *args)
: _io_port_alloc(io_port_alloc)
{
PWRN("no IO_PORT support under Linux (args=\"%s\")", args);
_size = 0;
throw Root::Invalid_args();
}
Io_port_session_component::~Io_port_session_component()
{
PERR("Implement me, immediately!");
}

View File

@ -0,0 +1,51 @@
/**
* \brief Core implementation of the PD session interface
* \author Christian Helmuth
* \date 2006-07-17
*
* FIXME arg_string and quota missing
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode */
#include <base/printf.h>
/* Core */
#include <pd_session_component.h>
/* Linux includes */
#include <linux_syscalls.h>
using namespace Genode;
Pd_session_component::Pd_session_component(Rpc_entrypoint *thread_ep,
const char *args)
{
_pid = Arg_string::find_arg(args, "PID").long_value(0);
}
Pd_session_component::~Pd_session_component()
{
if (_pid)
lx_kill(_pid, 9);
}
int Pd_session_component::bind_thread(Thread_capability)
{
return -1;
}
int Pd_session_component::assign_parent(Parent_capability)
{
return -1;
}

View File

@ -0,0 +1,62 @@
/*
* \brief Linux platform interface implementation
* \author Norman Feske
* \date 2006-06-13
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/lock.h>
/* local includes */
#include "platform.h"
#include "core_env.h"
/* Linux includes */
#include <linux_syscalls.h>
#include <linux_rpath.h>
using namespace Genode;
static char _some_mem[80*1024*1024];
static Lock _wait_for_exit_lock(Lock::LOCKED); /* exit() sync */
static void signal_handler(int signum)
{
_wait_for_exit_lock.unlock();
}
Platform::Platform()
: _ram_alloc(0)
{
/* catch control-c */
lx_sigaction(2, signal_handler);
/* create resource directory under /tmp */
lx_mkdir(lx_rpath(), S_IRWXU);
_ram_alloc.add_range((addr_t)_some_mem, sizeof(_some_mem));
}
void Platform::wait_for_exit()
{
/* block until exit condition is satisfied */
try { _wait_for_exit_lock.lock(); }
catch (Blocking_canceled) { };
}
void Core_parent::exit(int exit_value)
{
lx_exit_group(exit_value);
}

View File

@ -0,0 +1,86 @@
/*
* \brief Linux-specific platform thread implementation
* \author Norman Feske
* \date 2007-10-15
*/
/*
* Copyright (C) 2007-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.
*/
/* Genode includes */
#include <util/token.h>
#include <util/misc_math.h>
#include <base/printf.h>
/* local includes */
#include "platform_thread.h"
/* Linux syscall helper */
#include <linux_syscalls.h>
using namespace Genode;
typedef Token<Scanner_policy_identifier_with_underline> Tid_token;
Platform_thread::Platform_thread(const char *name, unsigned)
{
/* search for thread-id portion of thread name */
Tid_token tok(name);
while (tok.type() != Tid_token::END && tok[0] != ':')
tok = tok.next();
/* tok points at the colon separator, next token is the id */
tok = tok.next();
if (tok.type() == Tid_token::END) {
PWRN("Invalid format of thread name.");
return;
}
/* convert string to thread id */
ascii_to(tok.start(), &_tid);
/* search for process-id portion of thread name */
while (tok.type() != Tid_token::END && tok[0] != ':')
tok = tok.next();
/* tok points at the colon separator, next token is the id */
tok = tok.next();
if (tok.type() == Tid_token::END) {
PWRN("Invalid format of thread name.");
return;
}
/* convert string to process id */
ascii_to(tok.start(), &_pid);
/* initialize private members */
size_t name_len = tok.start() - name;
strncpy(_name, name, min(sizeof(_name), name_len));
}
void Platform_thread::cancel_blocking()
{
PDBG("send cancel-blocking signal to %ld\n", _tid);
lx_tgkill(_pid, _tid, LX_SIGUSR1);
}
void Platform_thread::pause()
{
PDBG("not implemented");
}
void Platform_thread::resume()
{
PDBG("not implemented");
}

View File

@ -0,0 +1,59 @@
/*
* \brief Make dataspace accessible to other Linux processes
* \author Norman Feske
* \date 2006-07-03
*/
/*
* Copyright (C) 2006-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.
*/
/* glibc includes */
#include <fcntl.h>
/* Genode includes */
#include <base/snprintf.h>
/* local includes */
#include "ram_session_component.h"
/* Linux syscall bindings */
#include <linux_syscalls.h>
#include <linux_rpath.h>
using namespace Genode;
static int ram_ds_cnt = 0; /* counter for creating unique dataspace IDs */
void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
{
char fname_buf[Linux_dataspace::FNAME_LEN];
/* assign filename to dataspace */
snprintf(fname_buf, sizeof(fname_buf), "%s/ds-%d", lx_rpath(), ram_ds_cnt++);
ds->fname(fname_buf);
/* create new file representing the dataspace */
lx_unlink(fname_buf);
int fd = lx_open(fname_buf, O_CREAT | O_RDWR | O_TRUNC | LX_O_CLOEXEC, S_IRWXU);
lx_ftruncate(fd, ds->size());
lx_close(fd);
}
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
{
lx_unlink(ds->fname().buf);
}
void Ram_session_component::_clear_ds(Dataspace_component *ds)
{
memset((void *)ds->phys_addr(), 0, ds->size());
}

View File

@ -0,0 +1,71 @@
/*
* \brief Linux-specific core implementation of the ROM session interface
* \author Norman Feske
* \date 2006-07-06
*
* The Linux version of ROM session component does not use the
* Rom_fs as provided as constructor argument. Instead, we map
* rom modules directly to files of the host file system.
*/
/*
* Copyright (C) 2006-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.
*/
/* Linux includes */
#include <linux_syscalls.h>
/* Genode includes */
#include <linux_dataspace/linux_dataspace.h>
#include <util/arg_string.h>
#include <root/root.h>
/* local includes */
#include "rom_session_component.h"
using namespace Genode;
static Genode::size_t file_size(const char *path)
{
struct stat64 s;
if (lx_stat(path, &s) < 0)
return 0;
else
return s.st_size;
}
Rom_session_component::Rom_session_component(Rom_fs *rom_fs,
Rpc_entrypoint *ds_ep,
const char *args)
: _ds_ep(ds_ep)
{
/* extract filename from session arguments */
char fname_buf[Linux_dataspace::FNAME_LEN];
Arg_string::find_arg(args, "filename").string(fname_buf, sizeof(fname_buf), "");
Genode::size_t fsize = file_size(fname_buf);
/* use invalid capability as default value */
_ds_cap = Rom_dataspace_capability();
/* ROM module not found */
if (fsize == 0)
throw Root::Invalid_args();
_ds = Dataspace_component(fsize, 0, false);
_ds.fname(fname_buf);
Dataspace_capability ds_cap = _ds_ep->manage(&_ds);
_ds_cap = static_cap_cast<Rom_dataspace>(ds_cap);
}
Rom_session_component::~Rom_session_component()
{
_ds_ep->dissolve(&_ds);
}

View File

@ -0,0 +1,36 @@
TARGET = core
REQUIRES = linux
LIBS = cxx ipc heap core_printf process lock raw_server syscall rpath
GEN_CORE_DIR = $(BASE_DIR)/src/core
SRC_CC = main.cc \
platform.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
rom_session_component.cc \
cpu_session_component.cc \
pd_session_component.cc \
io_mem_session_component.cc \
io_port_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
thread.cc \
thread_linux.cc \
context_area.cc \
debug.cc
INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include \
$(REP_DIR)/src/platform \
/usr/include
vpath main.cc $(GEN_CORE_DIR)
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath debug.cc $(REP_DIR)/src/base/env
vpath %.cc $(PRG_DIR)

View File

@ -0,0 +1,55 @@
/*
* \brief Implementation of the core-internal Thread API via Linux threads
* \author Norman Feske
* \date 2006-06-13
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/thread.h>
#include <base/sleep.h>
/* Linux syscall bindings */
#include <linux_syscalls.h>
using namespace Genode;
static void empty_signal_handler(int) { }
static void thread_start(void *)
{
/*
* Set signal handler such that canceled system calls get not
* transparently retried after a signal gets received.
*/
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
Thread_base::myself()->entry();
sleep_forever();
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread() { }
void Thread_base::start()
{
/* align initial stack to 16 byte boundary */
void *thread_sp = (void *)((addr_t)(_context->stack) & ~0xf);
_tid.tid = lx_create_thread(thread_start, thread_sp, this);
_tid.pid = lx_getpid();
}
void Thread_base::cancel_blocking() { }

View File

@ -0,0 +1,40 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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___MAIN_HELPER_H_
#define _PLATFORM___MAIN_HELPER_H_
#include <base/thread.h>
#include <linux_syscalls.h>
/*
* Define 'lx_environ' pointer that is supposed to be initialized by the
* startup code.
*/
__attribute__((weak)) char **lx_environ = (char **)0;
static void main_thread_bootstrap()
{
using namespace Genode;
/* reserve context area */
Genode::addr_t base = Thread_base::CONTEXT_AREA_VIRTUAL_BASE;
Genode::size_t size = Thread_base::CONTEXT_AREA_VIRTUAL_SIZE;
if (lx_vm_reserve(base, size) != base)
PERR("reservation of context area [%lx,%lx) failed",
(unsigned long) base, (unsigned long) base + size);
}
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@ -0,0 +1,25 @@
/*
* \brief Linux-specific linker script additions (STDLIB = no)
* \author Christian Helmuth
* \date 2010-09-22
*/
/*
* Copyright (C) 2010-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.
*/
PHDRS
{
context_area PT_LOAD FLAGS(0);
}
SECTIONS
{
. = 0x40000000;
_context_area_start = .;
.context_area : { . += 0x10000000; } : context_area
_context_area_end = .;
}

View File

@ -0,0 +1,20 @@
/*
* \brief Linux-specific linker script additions (STDLIB = yes)
* \author Christian Helmuth
* \date 2010-09-22
*/
/*
* Copyright (C) 2010-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.
*/
SECTIONS
{
. = 0x40000000;
_context_area_start = .;
.context_area : { . += 0x10000000; }
_context_area_end = .;
}

View File

@ -0,0 +1,39 @@
/*
* \brief Linux resource path
* \author Christian Helmuth
* \date 2011-09-25
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <base/snprintf.h>
#include <linux_syscalls.h>
#include <linux_rpath.h>
namespace {
struct Rpath
{
char string[32];
Rpath()
{
Genode::snprintf(string, sizeof(string), "/tmp/genode-%d", lx_getuid());
}
};
}
char const * lx_rpath()
{
static Rpath rpath;
return rpath.string;
}

View File

@ -0,0 +1,25 @@
/*
* \brief Linux resource path
* \author Christian Helmuth
* \date 2011-09-25
*/
/*
* Copyright (C) 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_RPATH_H_
#define _PLATFORM__LINUX_RPATH_H_
/**
* Return resource path for Genode
*
* Genode creates files for dataspaces and endpoints under in this directory.
*/
char const * lx_rpath();
#endif /* _PLATFORM__LINUX_RPATH_H_ */

View File

@ -0,0 +1,501 @@
/*
* \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 <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/syscall.h>
/* Genode includes */
#include <util/string.h>
/*****************************************
** Functions used by the IPC framework **
*****************************************/
#include <linux/net.h>
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_ */

View File

@ -0,0 +1,47 @@
/*
* \brief Supplemental code for hybrid Genode/Linux programs
* \author Norman Feske
* \date 2011-09-02
*/
/*
* Copyright (C) 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.
*/
#include <base/crt0.h>
#include <base/printf.h>
#include <_main_helper.h>
extern "C" int raw_write_str(const char *str);
/**
* Dummy for symbol that is normally provided by '_main.cc'
*/
int genode___cxa_atexit(void (*func)(void*), void *arg, void *dso)
{
raw_write_str("genode___cxa_atexit called, not implemented\n");
return 0;
}
/*
* Manually initialize the 'lx_environ' pointer. For non-hybrid programs, this
* pointer is initialized by the startup code.
*/
extern char **environ;
extern char **lx_environ;
/*
* This function must be called before any other static constructor in the Genode
* application, so it gets the highest priority (lowest priority number >100)
*/
__attribute__((constructor(101))) void lx_hybrid_init()
{
main_thread_bootstrap();
lx_environ = environ;
}

View File

@ -0,0 +1,70 @@
/*
* \brief Startup code for Genode applications
* \author Christian Helmuth
* \date 2006-07-06
*/
/*
* Copyright (C) 2006-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.
*/
/*--- .text (program code) -------------------------*/
.text
.globl _start
_start:
movl %esp, __initial_sp
/*
* environ = &argv[argc + 1]
* in Genode argc is always 1
*/
popl %eax /* argc */
popl %eax /* argv[0] */
popl %eax /* NULL */
movl %esp, lx_environ
/* XXX Switch to our own stack. */
movl $_stack_high,%esp
/* Clear the base pointer so that stack backtraces will work. */
xorl %ebp,%ebp
/* Jump into init C code */
call _main
/* We should never get here since _main does not return */
1: int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
/*--------------------------------------------------*/
.data
.globl __dso_handle
__dso_handle:
.long 0
.globl __initial_sp
__initial_sp:
.long 0
/*--- .eh_frame (exception frames) -----------------*/
/*
.section .eh_frame,"aw"
.globl __EH_FRAME_BEGIN__
__EH_FRAME_BEGIN__:
*/
/*--- .bss (non-initialized data) ------------------*/
.bss
.p2align 4
.globl _stack_low
_stack_low:
.space 64*1024
.globl _stack_high
_stack_high:

View File

@ -0,0 +1,109 @@
/*
* \brief Linux clone() binding
* \author Christian Prochaska
* \date 2009-07-14
*
* based on glibc-2.9/sysdeps/unix/sysv/linux/i386/clone.S
*/
#define L(name) name
#define ENTER_KERNEL int $0x80
#define SYS_clone 120
#define SYS_exit 1
#define LINKAGE 4
#define PTR_SIZE 4
#define PARMS LINKAGE /* no space for saved regs */
#define FUNC PARMS
#define STACK FUNC+4
#define FLAGS STACK+PTR_SIZE
#define ARG FLAGS+4
#define PTID ARG+PTR_SIZE
#define TLS PTID+PTR_SIZE
#define CTID TLS+PTR_SIZE
.text
.globl lx_clone
.type lx_clone, @function
lx_clone:
.cfi_startproc
/* Insert the argument onto the new stack. Make sure the new
thread is started with an alignment of (mod 16). */
movl STACK(%esp),%ecx
andl $0xfffffff0, %ecx
subl $28,%ecx
movl ARG(%esp),%eax /* no negative argument counts */
movl %eax,12(%ecx)
/* Save the function pointer as the zeroth argument.
It will be popped off in the child in the ebx frobbing below. */
movl FUNC(%esp),%eax
movl %eax,8(%ecx)
/* Don't leak any information. */
movl $0,4(%ecx)
movl $0,(%ecx)
/* Do the system call */
pushl %ebx
.cfi_adjust_cfa_offset (4)
pushl %esi
.cfi_adjust_cfa_offset (4)
pushl %edi
.cfi_adjust_cfa_offset (4)
movl TLS+12(%esp),%esi
.cfi_rel_offset %esi, 4
movl PTID+12(%esp),%edx
movl FLAGS+12(%esp),%ebx
.cfi_rel_offset %ebx, 8
movl CTID+12(%esp),%edi
.cfi_rel_offset %edi, 0
movl $SYS_clone,%eax
/* End FDE now, because in the child the unwind info will be
wrong. */
.cfi_endproc
ENTER_KERNEL
popl %edi
popl %esi
popl %ebx
test %eax,%eax
jz L(thread_start)
L(pseudo_end):
ret
L(thread_start):
.cfi_startproc;
/* Clearing frame pointer is insufficient, use CFI. */
.cfi_undefined %eip;
/* Note: %esi is zero. */
movl %esi,%ebp /* terminate the stack frame */
call *%ebx
#ifdef PIC
call L(here)
L(here):
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
#endif
movl %eax, %ebx
movl $SYS_exit, %eax
ENTER_KERNEL
.cfi_endproc;
.cfi_startproc
.cfi_endproc
/*
* Allow stacks to be mapped executable (needed because Genode does not
* offer an API to handle non-execute mappings yet).
*/
.section .note.GNU-stack, "", @progbits

View File

@ -0,0 +1,77 @@
/*
* \brief Linux syscall() binding
* \author Christian Prochaska
* \date 2009-07-14
*
* based on glibc-2.9/sysdeps/unix/sysv/linux/i386/syscall.S
*
* error case:
* glibc's syscall() function returns -1 and sets errno
* lx_syscall() returns -errno
*/
#define L(name) name
#define ENTER_KERNEL int $0x80
.text
.globl lx_syscall
.type lx_syscall, @function
lx_syscall:
.cfi_startproc
/* PUSHARGS_6*/ /* Save register contents. */
/* PUSHARGS_6 begin */
pushl %ebp;
.cfi_adjust_cfa_offset 4;
.cfi_rel_offset %ebp, 0;
L(PUSHBP1):
pushl %edi;
.cfi_adjust_cfa_offset 4;
.cfi_rel_offset %edi, 0;
L(PUSHDI1):
pushl %esi;
.cfi_adjust_cfa_offset 4;
.cfi_rel_offset %esi, 0;
L(PUSHSI1):
pushl %ebx;
.cfi_adjust_cfa_offset 4;
.cfi_rel_offset %ebx, 0;
L(PUSHBX1):
/* PUSHARGS_6 end */
/*_DOARGS_6(44)*/ /* Load arguments. */
/*_DOARGS_6(44) begin*/
movl 44(%esp), %ebp;
movl 40(%esp), %edi;
movl 36(%esp), %esi;
movl 32(%esp), %edx;
movl 28(%esp), %ecx;
movl 24(%esp), %ebx;
/*_DOARGS_6(44) end*/
movl 20(%esp), %eax /* Load syscall number into %eax. */
ENTER_KERNEL /* Do the system call. */
/* POPARGS_6*/ /* Restore register contents. */
/* POPARGS_6 begin */
popl %ebx;
.cfi_adjust_cfa_offset -4;
.cfi_restore %ebx;
L(POPBX1):
popl %esi;
.cfi_adjust_cfa_offset -4;
.cfi_restore %esi;
L(POPSI1):
popl %edi;
.cfi_adjust_cfa_offset -4;
.cfi_restore %edi;
L(POPDI1):
popl %ebp;
.cfi_adjust_cfa_offset -4;
.cfi_restore %ebp;
L(POPBP1):
/* POPARGS_6 end */
L(pseudo_end):
ret /* Return to caller. */
.cfi_endproc

View File

@ -0,0 +1,74 @@
/*
* \brief Startup code for Genode applications
* \author Christian Helmuth
* \date 2006-07-06
*/
/*
* Copyright (C) 2006-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.
*/
/*--- .text (program code) -------------------------*/
.text
.globl _start
_start:
movq __initial_sp@GOTPCREL(%rip), %rax
movq %rsp, (%rax)
/*
* environ = &argv[argc + 1]
* in Genode argc is always 1
*/
popq %rax /* argc */
popq %rax /* argv[0] */
popq %rax /* NULL */
movq lx_environ@GOTPCREL(%rip), %rax
movq %rsp, (%rax)
/* XXX Switch to our own stack. */
leaq _stack_high@GOTPCREL(%rip), %rax
movq (%rax), %rsp
/* Clear the base pointer so that stack backtraces will work. */
xorq %rbp,%rbp
/* Jump into init C code */
callq _main
/* We should never get here since _main does not return */
1: int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
/*--------------------------------------------------*/
.data
.p2align 8
.globl __dso_handle
__dso_handle:
.quad 0
.globl __initial_sp
__initial_sp:
.quad 0
/*--- .eh_frame (exception frames) -----------------*/
/*
.section .eh_frame,"aw"
.globl __EH_FRAME_BEGIN__
__EH_FRAME_BEGIN__:
*/
/*--- .bss (non-initialized data) ------------------*/
.bss
.p2align 8
.globl _stack_low
_stack_low:
.space 64*1024
.globl _stack_high
_stack_high:

View File

@ -0,0 +1,71 @@
/*
* \brief Linux clone() binding
* \author Christian Prochaska
* \date 2009-07-14
*
* based on glibc-2.9/sysdeps/unix/sysv/linux/x86_64/clone.S
*/
#define L(name) name
#define SYS_clone 56
#define SYS_exit 60
.text
.globl lx_clone
.type lx_clone, @function
lx_clone:
.cfi_startproc
/* Insert the argument onto the new stack. */
subq $16,%rsi
movq %rcx,8(%rsi)
/* Save the function pointer. It will be popped off in the
child in the ebx frobbing below. */
movq %rdi,0(%rsi)
/* Do the system call. */
movq %rdx, %rdi
movq %r8, %rdx
movq %r9, %r8
movq 8(%rsp), %r10
movl $SYS_clone,%eax
/* End FDE now, because in the child the unwind info will be
wrong. */
.cfi_endproc
syscall
testq %rax,%rax
jz L(thread_start)
L(pseudo_end):
/* parent returns */
ret
L(thread_start):
.cfi_startproc
/* Clearing frame pointer is insufficient, use CFI. */
.cfi_undefined (%rip);
/* Clear the frame pointer. The ABI suggests this be done, to mark
the outermost frame obviously. */
xorl %ebp, %ebp
/* Set up arguments for the function call. */
popq %rax /* Function to call. */
popq %rdi /* Argument. */
call *%rax
/* Call exit with return value from function call. */
movq %rax, %rdi
movq $SYS_exit, %rax
syscall
.cfi_endproc
/*
* Allow stacks to be mapped executable (needed because Genode does not
* offer an API to handle non-executable mappings yet).
*/
.section .note.GNU-stack, "", @progbits

View File

@ -0,0 +1,16 @@
/*
* \brief Linux signal handler restorer function
* \author Christian Prochaska
* \date 2009-07-14
*
*/
#define SYS_rt_sigreturn 15
.text
.globl lx_restore_rt
.type lx_restore_rt, @function
lx_restore_rt:
movq $SYS_rt_sigreturn, %rax
syscall

View File

@ -0,0 +1,29 @@
/*
* \brief Linux syscall() binding
* \author Christian Prochaska
* \date 2009-07-14
*
* based on glibc-2.9/sysdeps/unix/sysv/linux/x86_64/syscall.S
*
* error case:
* glibc's syscall() function returns -1 and sets errno
* lx_syscall() returns -errno
*/
#define L(name) name
.text
.globl lx_syscall
.type lx_syscall, @function
lx_syscall:
movq %rdi, %rax /* Syscall number -> rax. */
movq %rsi, %rdi /* shift arg1 - arg5. */
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp),%r9 /* arg6 is on the stack. */
syscall /* Do the system call. */
L(pseudo_end):
ret /* Return to caller. */

View File

@ -0,0 +1,39 @@
/*
* \brief Test if global static constructors in hybrid applications get called
* \author Christian Prochaska
* \date 2011-11-24
*/
/*
* Copyright (C) 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.
*/
#include <base/printf.h>
using namespace Genode;
struct Testapp_testclass
{
Testapp_testclass()
{
Genode::printf("Global static constructor of Genode application called\n");
}
};
Testapp_testclass testapp_testclass;
int main(int argc, char *argv[])
{
printf("--- lx_hybrid global static constructor test ---\n");
printf("--- returning from main ---\n");
return 0;
}

View File

@ -0,0 +1,22 @@
TARGET = test-lx_hybrid_ctors
SRC_CC = main.cc
LIBS = env lx_hybrid
EXT_OBJECTS += $(BUILD_BASE_DIR)/test/lx_hybrid_ctors/libtestlib.so
TESTLIB_SO = libtestlib.so
TESTLIB_SRC_CC = testlib.cc
$(TARGET): libtestlib.so
$(TESTLIB_SO): $(TESTLIB_SRC_CC)
$(MSG_BUILD)$(TESTLIB_SO)
$(VERBOSE)g++ -fPIC -c $^
$(VERBOSE)g++ -shared -Wlsoname,$(TESTLIB_SO) -o $@ $(notdir $(^:.cc=.o))
clean_libtestlib:
$(VERBOSE)rm -f $(TESTLIB_SO) $(TESTLIB_SRC_CC:.cc=.o)
clean: clean_libtestlib
vpath testlib.cc $(PRG_DIR)

View File

@ -0,0 +1,24 @@
/*
* \brief Test if global static constructors in host shared libs get called
* \author Christian Prochaska
* \date 2011-11-24
*/
/*
* Copyright (C) 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.
*/
#include <stdio.h>
struct Testlib_testclass
{
Testlib_testclass()
{
printf("[init -> test-lx_hybrid_ctors] Global static constructor of host library called.\n");
}
};
Testlib_testclass testlib_testclass;

View File

@ -0,0 +1,37 @@
/*
* \brief Test if the exception mechanism works in hybrid applications
* \author Christian Prochaska
* \date 2011-11-22
*/
/*
* Copyright (C) 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.
*/
#include <base/printf.h>
using namespace Genode;
class Test_exception { };
/**
* Main program
*/
int main(int, char **)
{
printf("--- lx_hybrid exception test ---\n");
try {
printf("Throwing Test_exception\n");
throw Test_exception();
} catch(Test_exception) {
printf("Caught Test_exception\n");
}
printf("--- returning from main ---\n");
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-lx_hybrid_exception
SRC_CC = main.cc
LIBS = env lx_hybrid

View File

@ -0,0 +1,22 @@
/*
* \brief Linux-specific policy for sub_rm test
* \author Norman Feske
* \date 2011-11-22
*/
/*
* Copyright (C) 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.
*/
/*
* The Linux implementation of the RM service does not support attaching
* the same sub RM session twice. This configuration enables the respective
* error-handling test.
*/
enum { attach_twice_forbidden = true };
enum { support_attach_sub_any = false };