mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-17 22:58:26 +00:00
Move repositories to 'repos/' subdirectory
This patch changes the top-level directory layout as a preparatory step for improving the tools for managing 3rd-party source codes. The rationale is described in the issue referenced below. Issue #1082
This commit is contained in:
31
repos/base-linux/src/base/console/core_console.h
Normal file
31
repos/base-linux/src/base/console/core_console.h
Normal 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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* 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)); }
|
||||
};
|
||||
}
|
||||
|
60
repos/base-linux/src/base/env/debug.cc
vendored
Normal file
60
repos/base-linux/src/base/env/debug.cc
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* \brief Linux-specific debug utilities
|
||||
* \author Norman Feske
|
||||
* \date 2009-05-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
}
|
||||
|
||||
|
||||
extern "C" int get_pid() { return lx_getpid(); }
|
212
repos/base-linux/src/base/env/platform_env.cc
vendored
Normal file
212
repos/base-linux/src/base/env/platform_env.cc
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* \brief Support for the Linux-specific environment
|
||||
* \author Norman Feske
|
||||
* \date 2008-12-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2008-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/arg_string.h>
|
||||
#include <base/thread.h>
|
||||
#include <linux_dataspace/client.h>
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
/* local includes */
|
||||
#include <platform_env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/****************************************************
|
||||
** Support for Platform_env_base::Rm_session_mmap **
|
||||
****************************************************/
|
||||
|
||||
Genode::size_t
|
||||
Platform_env_base::Rm_session_mmap::_dataspace_size(Dataspace_capability ds)
|
||||
{
|
||||
if (ds.valid())
|
||||
return Dataspace_client(ds).size();
|
||||
|
||||
return Dataspace_capability::deref(ds)->size();
|
||||
}
|
||||
|
||||
|
||||
int Platform_env_base::Rm_session_mmap::_dataspace_fd(Dataspace_capability ds)
|
||||
{
|
||||
return Linux_dataspace_client(ds).fd().dst().socket;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Platform_env_base::Rm_session_mmap::_dataspace_writable(Dataspace_capability ds)
|
||||
{
|
||||
return Dataspace_client(ds).writable();
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
** Platform_env::Local_parent **
|
||||
********************************/
|
||||
|
||||
static inline size_t get_page_size_log2() { return 12; }
|
||||
|
||||
|
||||
Session_capability
|
||||
Platform_env::Local_parent::session(Service_name const &service_name,
|
||||
Session_args const &args,
|
||||
Affinity const &affinity)
|
||||
{
|
||||
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 Expanding_parent_client::session(service_name, args, affinity);
|
||||
|
||||
if (size != ~0UL)
|
||||
size = align_addr(size, get_page_size_log2());
|
||||
|
||||
Rm_session_mmap *rm = new (env()->heap())
|
||||
Rm_session_mmap(true, size);
|
||||
|
||||
return Session_capability::local_cap(rm);
|
||||
}
|
||||
|
||||
return Expanding_parent_client::session(service_name, args, affinity);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
*/
|
||||
Capability<Rm_session_mmap> rm = static_cap_cast<Rm_session_mmap>(session);
|
||||
|
||||
destroy(env()->heap(), Capability<Rm_session_mmap>::deref(rm));
|
||||
}
|
||||
|
||||
|
||||
Platform_env::Local_parent::Local_parent(Parent_capability parent_cap,
|
||||
Emergency_ram_reserve &reserve)
|
||||
: Expanding_parent_client(parent_cap, reserve)
|
||||
{ }
|
||||
|
||||
|
||||
/******************
|
||||
** Platform_env **
|
||||
******************/
|
||||
|
||||
/**
|
||||
* List of Unix environment variables, initialized by the startup code
|
||||
*/
|
||||
extern char **lx_environ;
|
||||
|
||||
|
||||
/**
|
||||
* Read environment variable as long value
|
||||
*/
|
||||
static unsigned long 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;
|
||||
}
|
||||
|
||||
|
||||
static Parent_capability obtain_parent_cap()
|
||||
{
|
||||
long local_name = get_env_ulong("parent_local_name");
|
||||
|
||||
/* produce typed capability manually */
|
||||
typedef Native_capability::Dst Dst;
|
||||
Dst const dst(PARENT_SOCKET_HANDLE);
|
||||
return reinterpret_cap_cast<Parent>(Native_capability(dst, local_name));
|
||||
}
|
||||
|
||||
|
||||
Platform_env::Local_parent &Platform_env::_parent()
|
||||
{
|
||||
static Local_parent local_parent(obtain_parent_cap(), *this);
|
||||
return local_parent;
|
||||
}
|
||||
|
||||
|
||||
void Platform_env::reinit(Native_capability::Dst, long) { }
|
||||
void Platform_env::reinit_main_thread(Rm_session_capability &) { }
|
||||
|
||||
|
||||
Platform_env::Platform_env()
|
||||
:
|
||||
Platform_env_base(static_cap_cast<Ram_session>(_parent().session("Env::ram_session", "")),
|
||||
static_cap_cast<Cpu_session>(_parent().session("Env::cpu_session", "")),
|
||||
static_cap_cast<Pd_session> (_parent().session("Env::pd_session", ""))),
|
||||
_heap(Platform_env_base::ram_session(), Platform_env_base::rm_session()),
|
||||
_emergency_ram_ds(ram_session()->alloc(_emergency_ram_size()))
|
||||
{
|
||||
/* register TID and PID of the main thread at core */
|
||||
cpu_session()->thread_id(parent()->main_thread_cap(),
|
||||
lx_getpid(), lx_gettid());
|
||||
}
|
||||
|
||||
|
||||
/*****************************
|
||||
** Support for IPC library **
|
||||
*****************************/
|
||||
|
||||
namespace Genode {
|
||||
|
||||
Native_connection_state server_socket_pair()
|
||||
{
|
||||
/*
|
||||
* Obtain access to Linux-specific extension of the CPU session
|
||||
* interface. We can cast to the specific type because the Linux
|
||||
* version of 'Platform_env' is hosting a 'Linux_cpu_client' object.
|
||||
*/
|
||||
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
|
||||
|
||||
if (!cpu) {
|
||||
PERR("could not obtain Linux extension to CPU session interface");
|
||||
struct Could_not_access_linux_cpu_session { };
|
||||
throw Could_not_access_linux_cpu_session();
|
||||
}
|
||||
|
||||
Native_connection_state ncs;
|
||||
|
||||
Thread_base *thread = Thread_base::myself();
|
||||
if (thread) {
|
||||
ncs.server_sd = cpu->server_sd(thread->cap()).dst().socket;
|
||||
ncs.client_sd = cpu->client_sd(thread->cap()).dst().socket;
|
||||
}
|
||||
return ncs;
|
||||
}
|
||||
|
||||
void destroy_server_socket_pair(Native_connection_state const &ncs)
|
||||
{
|
||||
/* close local file descriptor if it is valid */
|
||||
if (ncs.server_sd != -1) lx_close(ncs.server_sd);
|
||||
if (ncs.client_sd != -1) lx_close(ncs.client_sd);
|
||||
}
|
||||
}
|
462
repos/base-linux/src/base/env/platform_env.h
vendored
Normal file
462
repos/base-linux/src/base/env/platform_env.h
vendored
Normal file
@ -0,0 +1,462 @@
|
||||
/*
|
||||
* \brief Linux-specific environment
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-07-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_ENV_H_
|
||||
#define _PLATFORM_ENV_H_
|
||||
|
||||
/* Linux includes */
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/misc_math.h>
|
||||
#include <base/heap.h>
|
||||
#include <linux_cpu_session/client.h>
|
||||
|
||||
/* local includes (from 'base/src/base/env/') */
|
||||
#include <platform_env_common.h>
|
||||
|
||||
|
||||
namespace Genode {
|
||||
struct Expanding_cpu_session_client;
|
||||
class Platform_env;
|
||||
}
|
||||
|
||||
|
||||
struct Genode::Expanding_cpu_session_client
|
||||
:
|
||||
Upgradeable_client<Genode::Linux_cpu_session_client>
|
||||
{
|
||||
Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap)
|
||||
: Upgradeable_client<Genode::Linux_cpu_session_client>(cap) { }
|
||||
|
||||
Thread_capability create_thread(Name const &name, addr_t utcb)
|
||||
{
|
||||
return retry<Cpu_session::Out_of_metadata>(
|
||||
[&] () { return Linux_cpu_session_client::create_thread(name, utcb); },
|
||||
[&] () { upgrade_ram(8*1024); });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Common base class of the 'Platform_env' implementations for core and
|
||||
* non-core processes.
|
||||
*/
|
||||
class Platform_env_base : public Env
|
||||
{
|
||||
private:
|
||||
|
||||
/**************************
|
||||
** Local region manager **
|
||||
**************************/
|
||||
|
||||
class Region
|
||||
{
|
||||
private:
|
||||
|
||||
addr_t _start;
|
||||
off_t _offset;
|
||||
Dataspace_capability _ds;
|
||||
size_t _size;
|
||||
|
||||
/**
|
||||
* Return offset of first byte after the region
|
||||
*/
|
||||
addr_t _end() const { return _start + _size; }
|
||||
|
||||
public:
|
||||
|
||||
Region() : _start(0), _offset(0), _size(0) { }
|
||||
|
||||
Region(addr_t start, off_t offset, Dataspace_capability ds, size_t size)
|
||||
: _start(start), _offset(offset), _ds(ds), _size(size) { }
|
||||
|
||||
bool used() const { return _size > 0; }
|
||||
addr_t start() const { return _start; }
|
||||
off_t offset() const { return _offset; }
|
||||
size_t size() const { return _size; }
|
||||
Dataspace_capability dataspace() const { return _ds; }
|
||||
|
||||
bool intersects(Region const &r) const
|
||||
{
|
||||
return (r.start() < _end()) && (_start < r._end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Meta data about dataspaces attached to an RM session
|
||||
*/
|
||||
class Region_map
|
||||
{
|
||||
public:
|
||||
|
||||
enum { MAX_REGIONS = 4096 };
|
||||
|
||||
private:
|
||||
|
||||
Region _map[MAX_REGIONS];
|
||||
|
||||
bool _id_valid(int id) const {
|
||||
return (id >= 0 && id < MAX_REGIONS); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Add region to region map
|
||||
*
|
||||
* \return region ID, or
|
||||
* -1 if out of metadata, or
|
||||
* -2 if region conflicts existing region
|
||||
*/
|
||||
int add_region(Region const ®ion)
|
||||
{
|
||||
/*
|
||||
* Check for region conflicts
|
||||
*/
|
||||
for (int i = 0; i < MAX_REGIONS; i++) {
|
||||
if (_map[i].intersects(region))
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate new region metadata
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < MAX_REGIONS; i++)
|
||||
if (!_map[i].used()) break;
|
||||
|
||||
if (i == MAX_REGIONS) {
|
||||
PERR("maximum number of %d regions reached",
|
||||
MAX_REGIONS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_map[i] = region;
|
||||
return i;
|
||||
}
|
||||
|
||||
Region region(int id) const
|
||||
{
|
||||
return _id_valid(id) ? _map[id] : Region();
|
||||
}
|
||||
|
||||
Region lookup(addr_t start)
|
||||
{
|
||||
for (int i = 0; i < MAX_REGIONS; i++)
|
||||
if (_map[i].start() == start)
|
||||
return _map[i];
|
||||
return Region();
|
||||
}
|
||||
|
||||
void remove_region(addr_t start)
|
||||
{
|
||||
for (int i = 0; i < MAX_REGIONS; i++)
|
||||
if (_map[i].start() == start)
|
||||
_map[i] = Region();
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* 'Rm_session_mmap' is 'protected' because it is instantiated by
|
||||
* 'Platform_env::Local_parent::session()'.
|
||||
*/
|
||||
|
||||
/*
|
||||
* On Linux, we use a local region manager session that attaches
|
||||
* dataspaces via mmap to the local address space.
|
||||
*/
|
||||
class Rm_session_mmap : public Rm_session,
|
||||
public Dataspace
|
||||
{
|
||||
private:
|
||||
|
||||
Lock _lock; /* protect '_rmap' */
|
||||
Region_map _rmap;
|
||||
bool const _sub_rm; /* false if RM session is root */
|
||||
size_t const _size;
|
||||
|
||||
/**
|
||||
* Base offset of the RM session
|
||||
*
|
||||
* For a normal RM session (the one that comes with the
|
||||
* 'env()', this value is zero. If the RM session is
|
||||
* used as nested dataspace, '_base' contains the address
|
||||
* where the managed dataspace is attached in the root RM
|
||||
* session.
|
||||
*
|
||||
* Note that a managed dataspace cannot be attached more
|
||||
* than once. Furthermore, managed dataspace cannot be
|
||||
* attached to another managed dataspace. The nested
|
||||
* dataspace emulation is solely implemented to support
|
||||
* the common use case of managed dataspaces as mechanism
|
||||
* to reserve parts of the local address space from being
|
||||
* populated by the 'env()->rm_session()'. (i.e., for the
|
||||
* context area, or for the placement of consecutive
|
||||
* shared-library segments)
|
||||
*/
|
||||
addr_t _base;
|
||||
|
||||
bool _is_attached() const { return _base > 0; }
|
||||
|
||||
void _add_to_rmap(Region const &);
|
||||
|
||||
/**
|
||||
* Reserve VM region for sub-rm dataspace
|
||||
*/
|
||||
addr_t _reserve_local(bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
Genode::size_t size);
|
||||
|
||||
/**
|
||||
* Map dataspace into local address space
|
||||
*/
|
||||
void *_map_local(Dataspace_capability ds,
|
||||
Genode::size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap = false);
|
||||
|
||||
/**
|
||||
* Determine size of dataspace
|
||||
*
|
||||
* For core, this function performs a local lookup of the
|
||||
* 'Dataspace_component' object. For non-core programs, the
|
||||
* dataspace size is determined via an RPC to core
|
||||
* (calling 'Dataspace::size()').
|
||||
*/
|
||||
size_t _dataspace_size(Capability<Dataspace>);
|
||||
|
||||
/**
|
||||
* Determine file descriptor of dataspace
|
||||
*/
|
||||
int _dataspace_fd(Capability<Dataspace>);
|
||||
|
||||
/**
|
||||
* Determine whether dataspace is writable
|
||||
*/
|
||||
bool _dataspace_writable(Capability<Dataspace>);
|
||||
|
||||
public:
|
||||
|
||||
Rm_session_mmap(bool sub_rm, size_t size = ~0)
|
||||
: _sub_rm(sub_rm), _size(size), _base(0) { }
|
||||
|
||||
~Rm_session_mmap()
|
||||
{
|
||||
/* detach sub RM session when destructed */
|
||||
if (_sub_rm && _is_attached())
|
||||
env()->rm_session()->detach((void *)_base);
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
** Region manager session interface **
|
||||
**************************************/
|
||||
|
||||
Local_addr attach(Dataspace_capability ds, size_t size,
|
||||
off_t, bool, Local_addr,
|
||||
bool executable);
|
||||
|
||||
void detach(Local_addr local_addr);
|
||||
|
||||
Pager_capability add_client(Thread_capability thread) {
|
||||
return Pager_capability(); }
|
||||
|
||||
void remove_client(Pager_capability pager) { }
|
||||
|
||||
void fault_handler(Signal_context_capability handler) { }
|
||||
|
||||
State state() { return State(); }
|
||||
|
||||
|
||||
/*************************
|
||||
** Dataspace interface **
|
||||
*************************/
|
||||
|
||||
size_t size() { return _size; }
|
||||
|
||||
addr_t phys_addr() { return 0; }
|
||||
|
||||
bool writable() { return true; }
|
||||
|
||||
/**
|
||||
* Return pseudo dataspace capability of the RM session
|
||||
*
|
||||
* The capability returned by this function is only usable
|
||||
* as argument to 'Rm_session_mmap::attach'. It is not a
|
||||
* real capability.
|
||||
*/
|
||||
Dataspace_capability dataspace()
|
||||
{
|
||||
return Dataspace_capability::local_cap(this);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/*******************************
|
||||
** Platform-specific members **
|
||||
*******************************/
|
||||
|
||||
Ram_session_capability _ram_session_cap;
|
||||
Expanding_ram_session_client _ram_session_client;
|
||||
Cpu_session_capability _cpu_session_cap;
|
||||
Expanding_cpu_session_client _cpu_session_client;
|
||||
Rm_session_mmap _rm_session_mmap;
|
||||
Pd_session_client _pd_session_client;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_env_base(Ram_session_capability ram_cap,
|
||||
Cpu_session_capability cpu_cap,
|
||||
Pd_session_capability pd_cap)
|
||||
:
|
||||
_ram_session_cap(ram_cap),
|
||||
_ram_session_client(_ram_session_cap),
|
||||
_cpu_session_cap(cpu_cap),
|
||||
_cpu_session_client(static_cap_cast<Linux_cpu_session>(cpu_cap)),
|
||||
_rm_session_mmap(false),
|
||||
_pd_session_client(pd_cap)
|
||||
{ }
|
||||
|
||||
|
||||
/*******************
|
||||
** Env interface **
|
||||
*******************/
|
||||
|
||||
Ram_session *ram_session() { return &_ram_session_client; }
|
||||
Ram_session_capability ram_session_cap() { return _ram_session_cap; }
|
||||
Rm_session *rm_session() { return &_rm_session_mmap; }
|
||||
Linux_cpu_session *cpu_session() { return &_cpu_session_client; }
|
||||
Cpu_session_capability cpu_session_cap() { return _cpu_session_cap; }
|
||||
Pd_session *pd_session() { return &_pd_session_client; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 'Platform_env' used by all processes except for core
|
||||
*/
|
||||
class Platform_env : public Platform_env_base, public Emergency_ram_reserve
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Local interceptor of parent requests
|
||||
*
|
||||
* On Linux, we need to intercept calls to the parent interface to
|
||||
* implement the RM service locally. This particular service is
|
||||
* used for creating managed dataspaces, which allow the
|
||||
* reservation of parts of the local address space from being
|
||||
* automatically managed by the 'env()->rm_session()'.
|
||||
*
|
||||
* All requests that do not refer to the RM service are passed
|
||||
* through the real parent interface.
|
||||
*/
|
||||
class Local_parent : public Expanding_parent_client
|
||||
{
|
||||
public:
|
||||
|
||||
/**********************
|
||||
** Parent interface **
|
||||
**********************/
|
||||
|
||||
Session_capability session(Service_name const &,
|
||||
Session_args const &,
|
||||
Affinity const & = Affinity());
|
||||
void close(Session_capability);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param parent_cap real parent capability used to
|
||||
* promote requests to non-local
|
||||
* services
|
||||
*/
|
||||
Local_parent(Parent_capability parent_cap,
|
||||
Emergency_ram_reserve &);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return instance of parent interface
|
||||
*/
|
||||
Local_parent &_parent();
|
||||
|
||||
Heap _heap;
|
||||
|
||||
/*
|
||||
* Emergency RAM reserve
|
||||
*
|
||||
* See the comment of '_fallback_sig_cap()' in 'env/env.cc'.
|
||||
*/
|
||||
constexpr static size_t _emergency_ram_size() { return 4*1024; }
|
||||
Ram_dataspace_capability _emergency_ram_ds;
|
||||
|
||||
|
||||
/*************************************
|
||||
** Linux-specific helper functions **
|
||||
*************************************/
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_env();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Platform_env() { _parent().exit(0); }
|
||||
|
||||
/*
|
||||
* Support functions for implementing fork on Noux.
|
||||
*
|
||||
* Not supported on Linux.
|
||||
*
|
||||
* See the documentation in 'base/src/base/env/platform_env.h'
|
||||
*/
|
||||
void reinit(Native_capability::Dst, long);
|
||||
void reinit_main_thread(Rm_session_capability &);
|
||||
|
||||
|
||||
/*************************************
|
||||
** Emergency_ram_reserve interface **
|
||||
*************************************/
|
||||
|
||||
void release() { ram_session()->free(_emergency_ram_ds); }
|
||||
|
||||
|
||||
/*******************
|
||||
** Env interface **
|
||||
*******************/
|
||||
|
||||
Parent *parent() { return &_parent(); }
|
||||
Heap *heap() { return &_heap; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _PLATFORM_ENV_H_ */
|
363
repos/base-linux/src/base/env/rm_session_mmap.cc
vendored
Normal file
363
repos/base-linux/src/base/env/rm_session_mmap.cc
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* \brief Implementation of Linux-specific local region manager
|
||||
* \author Norman Feske
|
||||
* \date 2008-10-22
|
||||
*
|
||||
* Under Linux, region management happens at the mercy of the Linux kernel. So,
|
||||
* all we can do in user land is 1) keep track of regions and (managed)
|
||||
* dataspaces and 2) get the kernel to manage VM regions as we intent.
|
||||
*
|
||||
* The kernel sets up mappings for the binary on execve(), which are text and
|
||||
* data segments, the context area and special regions (stack, vdso, vsyscall).
|
||||
* Later mappings are done by the Genode program itself, which knows nothing
|
||||
* about these initial mappings. Therefore, most mmap() operations are _soft_
|
||||
* to detect region conflicts with existing mappings or let the kernel find
|
||||
* some empty VM area (as core does on other platforms). The only _hard_
|
||||
* overmaps happen on attachment and population of managed dataspaces. Mapped,
|
||||
* but not populated dataspaces are "holes" in the Linux VM space represented
|
||||
* by PROT_NONE mappings (see _reserve_local()).
|
||||
*
|
||||
* The context area is a managed dataspace as on other platforms, which is
|
||||
* created and attached during program launch. The managed dataspace replaces
|
||||
* the inital reserved area, which is therefore flushed beforehand. Hybrid
|
||||
* programs have no context area.
|
||||
*
|
||||
* Note, we do not support nesting of managed dataspaces.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2008-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <linux_dataspace/client.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <context_area.h>
|
||||
|
||||
/* local includes */
|
||||
#include <platform_env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
static bool is_sub_rm_session(Dataspace_capability ds)
|
||||
{
|
||||
if (ds.valid())
|
||||
return false;
|
||||
|
||||
return Dataspace_capability::deref(ds) != 0;
|
||||
}
|
||||
|
||||
|
||||
addr_t Platform_env_base::Rm_session_mmap::_reserve_local(bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
Genode::size_t size)
|
||||
{
|
||||
/* special handling for context area */
|
||||
if (use_local_addr
|
||||
&& local_addr == Native_config::context_area_virtual_base()
|
||||
&& size == Native_config::context_area_virtual_size()) {
|
||||
|
||||
/*
|
||||
* On the first request to reserve the context area, we flush the
|
||||
* initial mapping preserved in linker script and apply the actual
|
||||
* reservation. Subsequent requests are just ignored.
|
||||
*/
|
||||
|
||||
static struct Context
|
||||
{
|
||||
Context()
|
||||
{
|
||||
flush_context_area();
|
||||
reserve_context_area();
|
||||
}
|
||||
} inst;
|
||||
|
||||
return local_addr;
|
||||
}
|
||||
|
||||
int const flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||
int const prot = PROT_NONE;
|
||||
void * const addr_in = use_local_addr ? (void *)local_addr : 0;
|
||||
void * const addr_out = lx_mmap(addr_in, size, prot, flags, -1, 0);
|
||||
|
||||
/* reserve at local address failed - unmap incorrect mapping */
|
||||
if (use_local_addr && addr_in != addr_out)
|
||||
lx_munmap((void *)addr_out, size);
|
||||
|
||||
if ((use_local_addr && addr_in != addr_out)
|
||||
|| (((long)addr_out < 0) && ((long)addr_out > -4095))) {
|
||||
PERR("_reserve_local: lx_mmap failed (addr_in=%p,addr_out=%p/%ld)",
|
||||
addr_in, addr_out, (long)addr_out);
|
||||
throw Rm_session::Region_conflict();
|
||||
}
|
||||
|
||||
return (addr_t) addr_out;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
Platform_env_base::Rm_session_mmap::_map_local(Dataspace_capability ds,
|
||||
Genode::size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap)
|
||||
{
|
||||
int const fd = _dataspace_fd(ds);
|
||||
bool const writable = _dataspace_writable(ds);
|
||||
|
||||
int const flags = MAP_SHARED | (overmap ? MAP_FIXED : 0);
|
||||
int const prot = PROT_READ
|
||||
| (writable ? PROT_WRITE : 0)
|
||||
| (executable ? PROT_EXEC : 0);
|
||||
void * const addr_in = use_local_addr ? (void*)local_addr : 0;
|
||||
void * const addr_out = lx_mmap(addr_in, size, prot, flags, fd, offset);
|
||||
|
||||
/*
|
||||
* We can close the file after calling mmap. The Linux kernel will still
|
||||
* keep the file mapped. By immediately closing the file descriptor, we
|
||||
* won't need to keep track of dataspace file descriptors within the
|
||||
* process.
|
||||
*/
|
||||
lx_close(fd);
|
||||
|
||||
/* attach at local address failed - unmap incorrect mapping */
|
||||
if (use_local_addr && addr_in != addr_out)
|
||||
lx_munmap((void *)addr_out, size);
|
||||
|
||||
if ((use_local_addr && addr_in != addr_out)
|
||||
|| (((long)addr_out < 0) && ((long)addr_out > -4095))) {
|
||||
PERR("_map_local: lx_mmap failed (addr_in=%p,addr_out=%p/%ld) overmap=%d",
|
||||
addr_in, addr_out, (long)addr_out, overmap);
|
||||
throw Rm_session::Region_conflict();
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
|
||||
void Platform_env::Rm_session_mmap::_add_to_rmap(Region const ®ion)
|
||||
{
|
||||
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,
|
||||
bool executable)
|
||||
{
|
||||
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 attachment offset to the local base
|
||||
* and map it. We have to enforce the mapping via the 'overmap'
|
||||
* argument as the region was reserved by a PROT_NONE mapping.
|
||||
*/
|
||||
if (_is_attached())
|
||||
_map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true);
|
||||
|
||||
return (void *)local_addr;
|
||||
|
||||
} else {
|
||||
|
||||
if (is_sub_rm_session(ds)) {
|
||||
|
||||
Dataspace *ds_if = Dataspace_capability::deref(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();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve local address range that can hold the entire sub RM
|
||||
* session.
|
||||
*/
|
||||
rm->_base = _reserve_local(use_local_addr, local_addr, region_size);
|
||||
|
||||
_add_to_rmap(Region(rm->_base, offset, ds, 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 and map
|
||||
* each of them.
|
||||
*/
|
||||
for (int i = 0; i < Region_map::MAX_REGIONS; i++) {
|
||||
Region region = rm->_rmap.region(i);
|
||||
if (!region.used())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We have to enforce the mapping via the 'overmap' argument as
|
||||
* the region was reserved by a PROT_NONE mapping.
|
||||
*/
|
||||
_map_local(region.dataspace(), region.size(), region.offset(),
|
||||
true, rm->_base + region.start() + region.offset(),
|
||||
executable, true);
|
||||
}
|
||||
|
||||
return rm->_base;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Case 1
|
||||
*
|
||||
* Boring, a plain dataspace is attached to a root RM session.
|
||||
* Note, we do not overmap.
|
||||
*/
|
||||
void *addr = _map_local(ds, region_size, offset, use_local_addr,
|
||||
local_addr, executable);
|
||||
|
||||
_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_munmap((void *)((addr_t)local_addr + _base), region.size());
|
||||
_reserve_local(true, (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 = Dataspace_capability::deref(region.dataspace());
|
||||
Rm_session_mmap *rm = dynamic_cast<Rm_session_mmap *>(ds_if);
|
||||
if (rm)
|
||||
rm->_base = 0;
|
||||
}
|
||||
}
|
661
repos/base-linux/src/base/ipc/ipc.cc
Normal file
661
repos/base-linux/src/base/ipc/ipc.cc
Normal file
@ -0,0 +1,661 @@
|
||||
/*
|
||||
* \brief Socket-based IPC implementation for Linux
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2011-10-11
|
||||
*
|
||||
* The current request message layout is:
|
||||
*
|
||||
* long server_local_name;
|
||||
* 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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/ipc.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/blocking.h>
|
||||
#include <base/env.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
/* local includes */
|
||||
#include <socket_descriptor_registry.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_syscalls.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/*****************************
|
||||
** IPC marshalling support **
|
||||
*****************************/
|
||||
|
||||
void Ipc_ostream::_marshal_capability(Native_capability const &cap)
|
||||
{
|
||||
if (cap.valid()) {
|
||||
_write_to_buf(cap.local_name());
|
||||
|
||||
_snd_msg->append_cap(cap.dst().socket);
|
||||
} else {
|
||||
_write_to_buf(-1L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Ipc_istream::_unmarshal_capability(Native_capability &cap)
|
||||
{
|
||||
long local_name = 0;
|
||||
_read_from_buf(local_name);
|
||||
|
||||
if (local_name == -1) {
|
||||
|
||||
/* construct invalid capability */
|
||||
cap = Genode::Native_capability();
|
||||
|
||||
} else {
|
||||
|
||||
/* construct valid capability */
|
||||
int const socket = _rcv_msg->read_cap();
|
||||
cap = Native_capability(Cap_dst_policy::Dst(socket), local_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/*
|
||||
* Helper for obtaining a bound and connected socket pair
|
||||
*
|
||||
* For core, the implementation is just a wrapper around
|
||||
* 'lx_server_socket_pair()'. For all other processes, the implementation
|
||||
* requests the socket pair from the Env::CPU session interface using a
|
||||
* Linux-specific interface extension.
|
||||
*/
|
||||
Native_connection_state server_socket_pair();
|
||||
|
||||
/*
|
||||
* Helper to destroy the server socket pair
|
||||
*
|
||||
* For core, this is a no-op. For all other processes, the server and client
|
||||
* sockets are closed.
|
||||
*/
|
||||
void destroy_server_socket_pair(Native_connection_state const &ncs);
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
** File-descriptor registry **
|
||||
******************************/
|
||||
|
||||
Genode::Ep_socket_descriptor_registry *Genode::ep_sd_registry()
|
||||
{
|
||||
static Genode::Ep_socket_descriptor_registry registry;
|
||||
return ®istry;
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
** Communication over Unix-domain sockets **
|
||||
********************************************/
|
||||
|
||||
enum {
|
||||
LX_EINTR = 4,
|
||||
LX_ECONNREFUSED = 111
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Return thread ID to which the given socket is directed to
|
||||
*
|
||||
* \return -1 if the socket is pointing to a valid entrypoint
|
||||
*/
|
||||
static int lookup_tid_by_client_socket(int sd)
|
||||
{
|
||||
/*
|
||||
* Synchronize calls so that the large 'sockaddr_un' can be allocated
|
||||
* in the BSS rather than the stack.
|
||||
*/
|
||||
static Lock lock;
|
||||
Lock::Guard guard(lock);
|
||||
|
||||
static sockaddr_un name;
|
||||
socklen_t name_len = sizeof(name);
|
||||
int ret = lx_getpeername(sd, (sockaddr *)&name, &name_len);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
struct Prefix_len
|
||||
{
|
||||
typedef Genode::size_t size_t;
|
||||
|
||||
size_t const len;
|
||||
|
||||
static int _init_len(char const *s)
|
||||
{
|
||||
char const * const pattern = "/ep-";
|
||||
static size_t const pattern_len = Genode::strlen(pattern);
|
||||
|
||||
for (size_t i = 0; Genode::strlen(s + i) >= pattern_len; i++)
|
||||
if (Genode::strcmp(s + i, pattern, pattern_len) == 0)
|
||||
return i + pattern_len;
|
||||
|
||||
struct Unexpected_rpath_prefix { };
|
||||
throw Unexpected_rpath_prefix();
|
||||
}
|
||||
|
||||
Prefix_len(char const *s) : len(_init_len(s)) { }
|
||||
};
|
||||
|
||||
/*
|
||||
* The name of the Unix-domain socket has the form <rpath>-<uid>/ep-<tid>.
|
||||
* We are only interested in the <tid> part. Hence, we determine the length
|
||||
* of the <rpath>-<uid>/ep- portion only once and keep it in a static
|
||||
* variable.
|
||||
*/
|
||||
static Prefix_len prefix_len(name.sun_path);
|
||||
|
||||
unsigned tid = 0;
|
||||
if (Genode::ascii_to(name.sun_path + prefix_len.len, &tid) == 0) {
|
||||
PRAW("Error: could not parse tid number");
|
||||
return -1;
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Message object encapsulating data for sendmsg/recvmsg
|
||||
*/
|
||||
struct Message
|
||||
{
|
||||
public:
|
||||
|
||||
enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
|
||||
|
||||
private:
|
||||
|
||||
typedef Genode::size_t size_t;
|
||||
|
||||
msghdr _msg;
|
||||
sockaddr_un _addr;
|
||||
iovec _iovec;
|
||||
char _cmsg_buf[CMSG_SPACE(MAX_SDS_PER_MSG*sizeof(int))];
|
||||
|
||||
unsigned _num_sds;
|
||||
|
||||
public:
|
||||
|
||||
Message(void *buffer, size_t buffer_len) : _num_sds(0)
|
||||
{
|
||||
Genode::memset(&_msg, 0, sizeof(_msg));
|
||||
|
||||
/* initialize control message */
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
_msg.msg_control = _cmsg_buf;
|
||||
_msg.msg_controllen = sizeof(_cmsg_buf); /* buffer space available */
|
||||
_msg.msg_flags |= MSG_CMSG_CLOEXEC;
|
||||
cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(0);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
|
||||
/* initialize iovec */
|
||||
_msg.msg_iov = &_iovec;
|
||||
_msg.msg_iovlen = 1;
|
||||
|
||||
_iovec.iov_base = buffer;
|
||||
_iovec.iov_len = buffer_len;
|
||||
}
|
||||
|
||||
msghdr * msg() { return &_msg; }
|
||||
|
||||
void marshal_socket(int sd)
|
||||
{
|
||||
*((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd;
|
||||
|
||||
_num_sds++;
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(_num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
void accept_sockets(int num_sds)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
int socket_at_index(int index) const
|
||||
{
|
||||
return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index);
|
||||
}
|
||||
|
||||
unsigned num_sockets() const
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
|
||||
if (!cmsg)
|
||||
return 0;
|
||||
|
||||
return (cmsg->cmsg_len - CMSG_ALIGN(sizeof(cmsghdr)))/sizeof(int);
|
||||
}
|
||||
};
|
||||
|
||||
} /* unnamed namespace */
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf'
|
||||
*/
|
||||
static void extract_sds_from_message(unsigned start_index, Message const &msg,
|
||||
Genode::Msgbuf_base &buf)
|
||||
{
|
||||
buf.reset_caps();
|
||||
|
||||
/* start at offset 1 to skip the reply channel */
|
||||
for (unsigned i = start_index; i < msg.num_sockets(); i++) {
|
||||
|
||||
int const sd = msg.socket_at_index(i);
|
||||
int const id = lookup_tid_by_client_socket(sd);
|
||||
|
||||
int const associated_sd = Genode::ep_sd_registry()->try_associate(sd, id);
|
||||
|
||||
buf.append_cap(associated_sd);
|
||||
|
||||
if ((associated_sd >= 0) && (associated_sd != sd)) {
|
||||
|
||||
/*
|
||||
* The association already existed under a different name, use
|
||||
* already associated socket descriptor and and drop 'sd'.
|
||||
*/
|
||||
lx_close(sd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send request to server and wait for reply
|
||||
*/
|
||||
static inline void lx_call(int dst_sd,
|
||||
Genode::Msgbuf_base &send_msgbuf, Genode::size_t send_msg_len,
|
||||
Genode::Msgbuf_base &recv_msgbuf)
|
||||
{
|
||||
int ret;
|
||||
Message send_msg(send_msgbuf.buf, send_msg_len);
|
||||
|
||||
/*
|
||||
* Create reply channel
|
||||
*
|
||||
* The reply channel will be closed when leaving the scope of 'lx_call'.
|
||||
*/
|
||||
struct Reply_channel
|
||||
{
|
||||
enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 };
|
||||
int sd[2];
|
||||
|
||||
Reply_channel()
|
||||
{
|
||||
sd[LOCAL_SOCKET] = -1; sd[REMOTE_SOCKET] = -1;
|
||||
|
||||
int ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, sd);
|
||||
if (ret < 0) {
|
||||
PRAW("[%d] lx_socketpair failed with %d", lx_getpid(), ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
}
|
||||
|
||||
~Reply_channel()
|
||||
{
|
||||
if (sd[LOCAL_SOCKET] != -1) lx_close(sd[LOCAL_SOCKET]);
|
||||
if (sd[REMOTE_SOCKET] != -1) lx_close(sd[REMOTE_SOCKET]);
|
||||
}
|
||||
|
||||
int local_socket() const { return sd[LOCAL_SOCKET]; }
|
||||
int remote_socket() const { return sd[REMOTE_SOCKET]; }
|
||||
|
||||
} reply_channel;
|
||||
|
||||
/* assemble message */
|
||||
|
||||
/* marshal reply capability */
|
||||
send_msg.marshal_socket(reply_channel.remote_socket());
|
||||
|
||||
/* marshal capabilities contained in 'send_msgbuf' */
|
||||
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
|
||||
send_msg.marshal_socket(send_msgbuf.cap(i));
|
||||
|
||||
ret = lx_sendmsg(dst_sd, send_msg.msg(), 0);
|
||||
if (ret < 0) {
|
||||
PRAW("[%d] lx_sendmsg to sd %d failed with %d in lx_call()",
|
||||
lx_getpid(), dst_sd, ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
/* receive reply */
|
||||
|
||||
Message recv_msg(recv_msgbuf.buf, recv_msgbuf.size());
|
||||
recv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
|
||||
|
||||
ret = lx_recvmsg(reply_channel.local_socket(), recv_msg.msg(), 0);
|
||||
|
||||
/* system call got interrupted by a signal */
|
||||
if (ret == -LX_EINTR)
|
||||
throw Genode::Blocking_canceled();
|
||||
|
||||
if (ret < 0) {
|
||||
PRAW("[%d] lx_recvmsg failed with %d in lx_call()", lx_getpid(), ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
extract_sds_from_message(0, recv_msg, recv_msgbuf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* for request from client
|
||||
*
|
||||
* \return socket descriptor of reply capability
|
||||
*/
|
||||
static inline int lx_wait(Genode::Native_connection_state &cs,
|
||||
Genode::Msgbuf_base &recv_msgbuf)
|
||||
{
|
||||
Message msg(recv_msgbuf.buf, recv_msgbuf.size());
|
||||
|
||||
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
|
||||
|
||||
int ret = lx_recvmsg(cs.server_sd, msg.msg(), 0);
|
||||
|
||||
/* system call got interrupted by a signal */
|
||||
if (ret == -LX_EINTR)
|
||||
throw Genode::Blocking_canceled();
|
||||
|
||||
if (ret < 0) {
|
||||
PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
int const reply_socket = msg.socket_at_index(0);
|
||||
|
||||
extract_sds_from_message(1, msg, recv_msgbuf);
|
||||
|
||||
return reply_socket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send reply to client
|
||||
*/
|
||||
static inline void lx_reply(int reply_socket,
|
||||
Genode::Msgbuf_base &send_msgbuf,
|
||||
Genode::size_t msg_len)
|
||||
{
|
||||
Message msg(send_msgbuf.buf, msg_len);
|
||||
|
||||
/*
|
||||
* Marshall capabilities to be transferred to the client
|
||||
*/
|
||||
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
|
||||
msg.marshal_socket(send_msgbuf.cap(i));
|
||||
|
||||
int ret = lx_sendmsg(reply_socket, msg.msg(), 0);
|
||||
|
||||
/* ignore reply send error caused by disappearing client */
|
||||
if (ret >= 0 || ret == -LX_ECONNREFUSED) {
|
||||
lx_close(reply_socket);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
PRAW("[%d] lx_sendmsg failed with %d in lx_reply()", lx_getpid(), ret);
|
||||
}
|
||||
|
||||
|
||||
/*****************
|
||||
** 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(Dst(-1), 0),
|
||||
_rcv_msg(rcv_msg)
|
||||
{ }
|
||||
|
||||
|
||||
Ipc_istream::~Ipc_istream()
|
||||
{
|
||||
/*
|
||||
* The association of the capability (client) socket must be invalidated on
|
||||
* server destruction. We implement it here as the IPC server currently has
|
||||
* no destructor. We have the plan to remove Ipc_istream and Ipc_ostream
|
||||
* in the future and, then, move this into the server destructor.
|
||||
*
|
||||
* IPC clients have -1 as client_sd and need no disassociation.
|
||||
*/
|
||||
if (_rcv_cs.client_sd != -1) {
|
||||
Genode::ep_sd_registry()->disassociate(_rcv_cs.client_sd);
|
||||
|
||||
/*
|
||||
* Reset thread role to non-server such that we can enter 'sleep_forever'
|
||||
* without getting a warning.
|
||||
*/
|
||||
Thread_base *thread = Thread_base::myself();
|
||||
if (thread)
|
||||
thread->tid().is_ipc_server = false;
|
||||
}
|
||||
|
||||
destroy_server_socket_pair(_rcv_cs);
|
||||
_rcv_cs.client_sd = -1;
|
||||
_rcv_cs.server_sd = -1;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
** Ipc_client **
|
||||
****************/
|
||||
|
||||
void Ipc_client::_prepare_next_call()
|
||||
{
|
||||
/* prepare next request in buffer */
|
||||
long const local_name = Ipc_ostream::_dst.local_name();
|
||||
|
||||
_write_offset = 0;
|
||||
_write_to_buf(local_name);
|
||||
|
||||
/* prepare response buffer */
|
||||
_read_offset = sizeof(long);
|
||||
|
||||
_snd_msg->reset_caps();
|
||||
}
|
||||
|
||||
|
||||
void Ipc_client::_call()
|
||||
{
|
||||
if (Ipc_ostream::_dst.valid())
|
||||
lx_call(Ipc_ostream::_dst.dst().socket, *_snd_msg, _write_offset, *_rcv_msg);
|
||||
|
||||
_prepare_next_call();
|
||||
}
|
||||
|
||||
|
||||
Ipc_client::Ipc_client(Native_capability const &srv, Msgbuf_base *snd_msg,
|
||||
Msgbuf_base *rcv_msg, unsigned short)
|
||||
: Ipc_istream(rcv_msg), Ipc_ostream(srv, snd_msg), _result(0)
|
||||
{
|
||||
_prepare_next_call();
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
** Ipc_server **
|
||||
****************/
|
||||
|
||||
void Ipc_server::_prepare_next_reply_wait()
|
||||
{
|
||||
/* skip server-local name */
|
||||
_read_offset = sizeof(long);
|
||||
|
||||
/* prepare next reply */
|
||||
_write_offset = 0;
|
||||
long local_name = Ipc_ostream::_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));
|
||||
|
||||
/* reset capability slots of send message buffer */
|
||||
_snd_msg->reset_caps();
|
||||
}
|
||||
|
||||
|
||||
void Ipc_server::_wait()
|
||||
{
|
||||
_reply_needed = true;
|
||||
|
||||
/*
|
||||
* Block infinitely if called from the main thread. This may happen if the
|
||||
* main thread calls 'sleep_forever()'.
|
||||
*/
|
||||
if (!Thread_base::myself()) {
|
||||
struct timespec ts = { 1000, 0 };
|
||||
for (;;) lx_nanosleep(&ts, 0);
|
||||
}
|
||||
|
||||
try {
|
||||
int const reply_socket = lx_wait(_rcv_cs, *_rcv_msg);
|
||||
|
||||
/*
|
||||
* Remember reply capability
|
||||
*
|
||||
* The 'local_name' of a capability is meaningful for addressing server
|
||||
* objects only. Because a reply capabilities does not address a server
|
||||
* object, the 'local_name' is meaningless.
|
||||
*/
|
||||
enum { DUMMY_LOCAL_NAME = -1 };
|
||||
typedef Native_capability::Dst Dst;
|
||||
Ipc_ostream::_dst = Native_capability(Dst(reply_socket), DUMMY_LOCAL_NAME);
|
||||
|
||||
_prepare_next_reply_wait();
|
||||
} catch (Blocking_canceled) { }
|
||||
}
|
||||
|
||||
|
||||
void Ipc_server::_reply()
|
||||
{
|
||||
try {
|
||||
lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg, _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)
|
||||
lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg, _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)
|
||||
{
|
||||
Thread_base *thread = Thread_base::myself();
|
||||
|
||||
/*
|
||||
* If 'thread' is 0, the constructor was called by the main thread. By
|
||||
* definition, main is never an RPC entrypoint. However, the main thread
|
||||
* may call 'sleep_forever()', which instantiates 'Ipc_server'.
|
||||
*/
|
||||
|
||||
if (thread && thread->tid().is_ipc_server) {
|
||||
PRAW("[%d] unexpected multiple instantiation of Ipc_server by one thread",
|
||||
lx_gettid());
|
||||
struct Ipc_server_multiple_instance { };
|
||||
throw Ipc_server_multiple_instance();
|
||||
}
|
||||
|
||||
if (thread) {
|
||||
_rcv_cs = server_socket_pair();
|
||||
thread->tid().is_ipc_server = true;
|
||||
}
|
||||
|
||||
/* override capability initialization performed by 'Ipc_istream' */
|
||||
*static_cast<Native_capability *>(this) =
|
||||
Native_capability(Native_capability::Dst(_rcv_cs.client_sd), 0);
|
||||
|
||||
_prepare_next_reply_wait();
|
||||
}
|
150
repos/base-linux/src/base/ipc/socket_descriptor_registry.h
Normal file
150
repos/base-linux/src/base/ipc/socket_descriptor_registry.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* \brief Linux-specific socket-descriptor registry
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-26
|
||||
*
|
||||
* We use the names of Unix-domain sockets as keys to uniquely identify
|
||||
* entrypoints. When receiving a socket descriptor as IPC payload, we first
|
||||
* lookup the corresponding entrypoint ID. If we already possess a socket
|
||||
* descriptor pointing to the same entrypoint, we close the received one and
|
||||
* use the already known descriptor instead.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_
|
||||
#define _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_
|
||||
|
||||
#include <base/lock.h>
|
||||
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
template <unsigned MAX_FDS>
|
||||
class Socket_descriptor_registry;
|
||||
|
||||
typedef Socket_descriptor_registry<100> Ep_socket_descriptor_registry;
|
||||
|
||||
/**
|
||||
* Return singleton instance of registry for tracking entrypoint sockets
|
||||
*/
|
||||
Ep_socket_descriptor_registry *ep_sd_registry();
|
||||
}
|
||||
|
||||
|
||||
template <unsigned MAX_FDS>
|
||||
class Genode::Socket_descriptor_registry
|
||||
{
|
||||
public:
|
||||
|
||||
class Limit_reached { };
|
||||
class Aliased_global_id { };
|
||||
|
||||
private:
|
||||
|
||||
struct Entry
|
||||
{
|
||||
int fd;
|
||||
int global_id;
|
||||
|
||||
/**
|
||||
* Default constructor creates empty entry
|
||||
*/
|
||||
Entry() : fd(-1), global_id(-1) { }
|
||||
|
||||
Entry(int fd, int global_id) : fd(fd), global_id(global_id) { }
|
||||
|
||||
bool is_free() const { return fd == -1; }
|
||||
|
||||
void mark_as_free() { fd = -1; }
|
||||
};
|
||||
|
||||
Entry _entries[MAX_FDS];
|
||||
|
||||
Genode::Lock mutable _lock;
|
||||
|
||||
Entry &_find_free_entry()
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_FDS; i++)
|
||||
if (_entries[i].is_free())
|
||||
return _entries[i];
|
||||
|
||||
throw Limit_reached();
|
||||
}
|
||||
|
||||
Entry &_find_entry_by_fd(int fd)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_FDS; i++)
|
||||
if (_entries[i].fd == fd)
|
||||
return _entries[i];
|
||||
|
||||
throw Limit_reached();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup file descriptor that belongs to specified global ID
|
||||
*
|
||||
* \return file descriptor or -1 if lookup failed
|
||||
*/
|
||||
int _lookup_fd_by_global_id(int global_id) const
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_FDS; i++)
|
||||
if (_entries[i].global_id == global_id)
|
||||
return _entries[i].fd;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void disassociate(int sd)
|
||||
{
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
|
||||
for (unsigned i = 0; i < MAX_FDS; i++)
|
||||
if (_entries[i].fd == sd) {
|
||||
_entries[i].mark_as_free();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to associate socket descriptor with corresponding ID
|
||||
*
|
||||
* \return socket descriptor associated with the ID
|
||||
* \throw Limit_reached
|
||||
*
|
||||
* If the ID was already associated, the return value is the originally
|
||||
* registered socket descriptor. In this case, the caller should drop
|
||||
* the new socket descriptor and use the one returned by this function.
|
||||
*/
|
||||
int try_associate(int sd, int global_id)
|
||||
{
|
||||
/* ignore invalid capabilities */
|
||||
if (sd == -1)
|
||||
return sd;
|
||||
|
||||
/* ignore invalid capabilities */
|
||||
if (sd == -1 || global_id == -1)
|
||||
return sd;
|
||||
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
|
||||
int const existing_sd = _lookup_fd_by_global_id(global_id);
|
||||
|
||||
if (existing_sd < 0) {
|
||||
Entry &entry = _find_free_entry();
|
||||
entry = Entry(sd, global_id);
|
||||
return sd;
|
||||
} else {
|
||||
return existing_sd;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_ */
|
75
repos/base-linux/src/base/lock/lock_helper.h
Normal file
75
repos/base-linux/src/base/lock/lock_helper.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* \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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/native_types.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
|
||||
extern int main_thread_futex_counter;
|
||||
|
||||
|
||||
/**
|
||||
* 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 inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
|
||||
{
|
||||
const int *futex_counter_ptr = thread_base ?
|
||||
&thread_base->tid().futex_counter :
|
||||
&main_thread_futex_counter;
|
||||
return lx_futex(futex_counter_ptr, LX_FUTEX_WAKE, 1);
|
||||
}
|
||||
|
||||
|
||||
static inline void thread_switch_to(Genode::Thread_base *thread_base)
|
||||
{
|
||||
thread_yield();
|
||||
}
|
||||
|
||||
|
||||
static inline void thread_stop_myself()
|
||||
{
|
||||
/*
|
||||
* Just go to sleep without modifying the counter value. The
|
||||
* 'thread_check_stopped_and_restart()' function will get called
|
||||
* repeatedly until this thread has actually executed the syscall.
|
||||
*/
|
||||
Genode::Thread_base *myself = Genode::Thread_base::myself();
|
||||
const int *futex_counter_ptr = myself ?
|
||||
&myself->tid().futex_counter :
|
||||
&main_thread_futex_counter;
|
||||
lx_futex(futex_counter_ptr, LX_FUTEX_WAIT, 0);
|
||||
}
|
92
repos/base-linux/src/base/process/process.cc
Normal file
92
repos/base-linux/src/base/process/process.cc
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* \brief Implementation of process creation for Linux
|
||||
* \author Norman Feske
|
||||
* \date 2006-07-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/elf.h>
|
||||
#include <base/env.h>
|
||||
#include <base/process.h>
|
||||
#include <base/printf.h>
|
||||
#include <linux_pd_session/client.h>
|
||||
|
||||
/* framework-internal includes */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_capability Process::_dynamic_linker_cap;
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
char const *name,
|
||||
Native_pd_args const *pd_args)
|
||||
:
|
||||
_pd(name, pd_args),
|
||||
_cpu_session_client(cpu_session_cap),
|
||||
_rm_session_client(Rm_session_capability())
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
elf_data_ds_cap = _dynamic_linker_cap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register main thread at core
|
||||
*
|
||||
* At this point in time, we do not yet know the TID and PID of the new
|
||||
* thread. Those information will be provided to core by the constructor of
|
||||
* the 'Platform_env' of the new process.
|
||||
*/
|
||||
_thread0_cap = _cpu_session_client.create_thread(name);
|
||||
|
||||
Linux_pd_session_client lx_pd(static_cap_cast<Linux_pd_session>(_pd.cap()));
|
||||
|
||||
lx_pd.assign_parent(parent_cap);
|
||||
lx_pd.start(elf_data_ds_cap);
|
||||
}
|
||||
|
||||
|
||||
Process::~Process() { }
|
49
repos/base-linux/src/base/thread/thread_env.cc
Normal file
49
repos/base-linux/src/base/thread/thread_env.cc
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* \brief Thread-environment support common to all programs
|
||||
* \author Martin Stein
|
||||
* \date 2013-12-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
#include <base/env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern addr_t * __initial_sp;
|
||||
|
||||
/*
|
||||
* Define 'lx_environ' pointer.
|
||||
*/
|
||||
char **lx_environ;
|
||||
|
||||
/**
|
||||
* Natively aligned memory location used in the lock implementation
|
||||
*/
|
||||
int main_thread_futex_counter __attribute__((aligned(sizeof(addr_t))));
|
||||
|
||||
|
||||
/*****************************
|
||||
** Startup library support **
|
||||
*****************************/
|
||||
|
||||
void prepare_init_main_thread()
|
||||
{
|
||||
/*
|
||||
* Initialize the 'lx_environ' pointer
|
||||
*
|
||||
* environ = &argv[argc + 1]
|
||||
* __initial_sp[0] = argc (always 1 in Genode)
|
||||
* __initial_sp[1] = argv[0]
|
||||
* __initial_sp[2] = NULL
|
||||
* __initial_sp[3] = environ
|
||||
*/
|
||||
lx_environ = (char**)&__initial_sp[3];
|
||||
}
|
149
repos/base-linux/src/base/thread/thread_linux.cc
Normal file
149
repos/base-linux/src/base/thread/thread_linux.cc
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* \brief Implementation of the Thread API via Linux threads
|
||||
* \author Norman Feske
|
||||
* \author Martin Stein
|
||||
* \date 2006-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/env.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/snprintf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern int main_thread_futex_counter;
|
||||
|
||||
static void empty_signal_handler(int) { }
|
||||
|
||||
|
||||
static Lock &startup_lock()
|
||||
{
|
||||
static Lock lock(Lock::LOCKED);
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signal handler for killing the thread
|
||||
*/
|
||||
static void thread_exit_signal_handler(int) { lx_exit(0); }
|
||||
|
||||
|
||||
void Thread_base::_thread_start()
|
||||
{
|
||||
/*
|
||||
* 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 * const thread = Thread_base::myself();
|
||||
|
||||
/* inform core about the new thread and process ID of the new thread */
|
||||
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(thread->_cpu_session);
|
||||
if (cpu)
|
||||
cpu->thread_id(thread->cap(), thread->tid().pid, thread->tid().tid);
|
||||
|
||||
/* wakeup 'start' function */
|
||||
startup_lock().unlock();
|
||||
|
||||
thread->entry();
|
||||
|
||||
/* unblock caller of 'join()' */
|
||||
thread->_join_lock.unlock();
|
||||
|
||||
sleep_forever();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::_init_platform_thread(Type type)
|
||||
{
|
||||
/* if no cpu session is given, use it from the environment */
|
||||
if (!_cpu_session)
|
||||
_cpu_session = env()->cpu_session();
|
||||
|
||||
/* for normal threads create an object at the CPU session */
|
||||
if (type == NORMAL) {
|
||||
_thread_cap = _cpu_session->create_thread(_context->name);
|
||||
return;
|
||||
}
|
||||
/* adjust initial object state for main threads */
|
||||
tid().futex_counter = main_thread_futex_counter;
|
||||
_thread_cap = env()->parent()->main_thread_cap();
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
_cpu_session->kill_thread(_thread_cap);
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::start()
|
||||
{
|
||||
/* synchronize calls of the 'start' function */
|
||||
static Lock lock;
|
||||
Lock::Guard guard(lock);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
_tid.pid = lx_getpid();
|
||||
|
||||
/* wait until the 'thread_start' function got entered */
|
||||
startup_lock().lock();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::cancel_blocking()
|
||||
{
|
||||
_cpu_session->cancel_blocking(_thread_cap);
|
||||
}
|
119
repos/base-linux/src/core/context_area.cc
Normal file
119
repos/base-linux/src/core/context_area.cc
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* \brief Linux-specific support code for the thread API
|
||||
* \author Norman Feske
|
||||
* \date 2010-01-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <rm_session/rm_session.h>
|
||||
#include <ram_session/ram_session.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
#include <context_area.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:
|
||||
|
||||
Context_area_rm_session()
|
||||
{
|
||||
flush_context_area();
|
||||
reserve_context_area();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
bool executable)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* convert context-area-relative to absolute virtual address */
|
||||
addr_t addr = local_addr;
|
||||
addr += Native_config::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 remove_client(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, bool) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
49
repos/base-linux/src/core/cpu_session_extension.cc
Normal file
49
repos/base-linux/src/core/cpu_session_extension.cc
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* \brief Linux-specific extension of the CPU session implementation
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-09
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
void Cpu_session_component::thread_id(Thread_capability thread_cap, int pid, int tid)
|
||||
{
|
||||
Object_pool<Cpu_thread_component>::Guard
|
||||
thread(_thread_ep->lookup_and_lock(thread_cap));
|
||||
if (!thread) return;
|
||||
|
||||
thread->platform_thread()->thread_id(pid, tid);
|
||||
}
|
||||
|
||||
|
||||
Untyped_capability Cpu_session_component::server_sd(Thread_capability thread_cap)
|
||||
{
|
||||
Object_pool<Cpu_thread_component>::Guard
|
||||
thread(_thread_ep->lookup_and_lock(thread_cap));
|
||||
if (!thread) return Untyped_capability();
|
||||
|
||||
enum { DUMMY_LOCAL_NAME = 0 };
|
||||
typedef Native_capability::Dst Dst;
|
||||
return Untyped_capability(Dst(thread->platform_thread()->server_sd()),
|
||||
DUMMY_LOCAL_NAME);
|
||||
}
|
||||
|
||||
|
||||
Untyped_capability Cpu_session_component::client_sd(Thread_capability thread_cap)
|
||||
{
|
||||
Object_pool<Cpu_thread_component>::Guard
|
||||
thread(_thread_ep->lookup_and_lock(thread_cap));
|
||||
if (!thread) return Untyped_capability();
|
||||
|
||||
enum { DUMMY_LOCAL_NAME = 0 };
|
||||
typedef Native_capability::Dst Dst;
|
||||
return Untyped_capability(Dst(thread->platform_thread()->client_sd()),
|
||||
DUMMY_LOCAL_NAME);
|
||||
}
|
28
repos/base-linux/src/core/cpu_session_support.cc
Normal file
28
repos/base-linux/src/core/cpu_session_support.cc
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* \brief Platform-specific parts of cores CPU-service
|
||||
* \author Martin Stein
|
||||
* \date 2012-04-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_cap)
|
||||
{
|
||||
PERR("%s: Not implemented", __PRETTY_FUNCTION__);
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
49
repos/base-linux/src/core/include/cap_session_component.h
Normal file
49
repos/base-linux/src/core/include/cap_session_component.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* \brief Capability allocation service
|
||||
* \author Norman Feske
|
||||
* \date 2006-06-26
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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:
|
||||
|
||||
Cap_session_component(Allocator *md_alloc, const char *args) {}
|
||||
|
||||
Native_capability alloc(Native_capability ep)
|
||||
{
|
||||
Lock::Guard lock_guard(_lock());
|
||||
|
||||
return Native_capability(ep.dst(), ++_unique_id_cnt);
|
||||
}
|
||||
|
||||
void free(Native_capability cap) { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__LINUX__CAP_SESSION_COMPONENT_H_ */
|
209
repos/base-linux/src/core/include/core_env.h
Normal file
209
repos/base-linux/src/core/include/core_env.h
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* \brief Core-specific environment for Linux
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-07-28
|
||||
*
|
||||
* The Core-specific environment ensures that all sessions of Core's
|
||||
* environment a local.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__CORE_ENV_H_
|
||||
#define _CORE__INCLUDE__CORE_ENV_H_
|
||||
|
||||
/* core includes */
|
||||
#include <platform.h>
|
||||
#include <core_parent.h>
|
||||
#include <cap_session_component.h>
|
||||
#include <ram_session_component.h>
|
||||
|
||||
/* internal base includes */
|
||||
#include <platform_env.h>
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Lock-guarded version of a RAM-session implementation
|
||||
*
|
||||
* \param RAM_SESSION_IMPL non-thread-safe RAM-session class
|
||||
*
|
||||
* In contrast to normal processes, core's 'env()->ram_session()' is not
|
||||
* synchronized by an RPC interface. However, it is accessed by different
|
||||
* threads using the 'env()->heap()' and the sliced heap used for
|
||||
* allocating sessions to core's services.
|
||||
*/
|
||||
template <typename RAM_SESSION_IMPL>
|
||||
class Synchronized_ram_session : public RAM_SESSION_IMPL
|
||||
{
|
||||
private:
|
||||
|
||||
Lock _lock;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Synchronized_ram_session(Rpc_entrypoint *ds_ep,
|
||||
Rpc_entrypoint *ram_session_ep,
|
||||
Range_allocator *ram_alloc,
|
||||
Allocator *md_alloc,
|
||||
const char *args,
|
||||
size_t quota_limit = 0)
|
||||
:
|
||||
RAM_SESSION_IMPL(ds_ep, ram_session_ep, ram_alloc, md_alloc, args, quota_limit)
|
||||
{ }
|
||||
|
||||
|
||||
/***************************
|
||||
** RAM-session interface **
|
||||
***************************/
|
||||
|
||||
Ram_dataspace_capability alloc(size_t size, bool cached)
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
return RAM_SESSION_IMPL::alloc(size, cached);
|
||||
}
|
||||
|
||||
void free(Ram_dataspace_capability ds)
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
RAM_SESSION_IMPL::free(ds);
|
||||
}
|
||||
|
||||
int ref_account(Ram_session_capability session)
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
return RAM_SESSION_IMPL::ref_account(session);
|
||||
}
|
||||
|
||||
int transfer_quota(Ram_session_capability session, size_t size)
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
return RAM_SESSION_IMPL::transfer_quota(session, size);
|
||||
}
|
||||
|
||||
size_t quota()
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
return RAM_SESSION_IMPL::quota();
|
||||
}
|
||||
|
||||
size_t used()
|
||||
{
|
||||
Lock::Guard lock_guard(_lock);
|
||||
return RAM_SESSION_IMPL::used();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Core_env : public Platform_env_base
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Entrypoint with support for local object access
|
||||
*
|
||||
* Within core, there are a few cases where the RPC objects must
|
||||
* be invoked by direct function calls instead of using RPC.
|
||||
* I.e., when an entrypoint dispatch function performs a memory
|
||||
* allocation via the 'Sliced_heap', the 'attach' function of
|
||||
* 'Rm_session_mmap' tries to obtain the dataspace's size and fd.
|
||||
* Normally, this would be done by calling the entrypoint but the
|
||||
* entrypoint cannot call itself. To support this special case,
|
||||
* the 'Entrypoint' extends the 'Rpc_entrypoint' with the
|
||||
* functionality needed to lookup an RPC object by its capability.
|
||||
*/
|
||||
struct Entrypoint : Rpc_entrypoint
|
||||
{
|
||||
enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
|
||||
|
||||
Entrypoint(Cap_session *cap_session)
|
||||
:
|
||||
Rpc_entrypoint(cap_session, STACK_SIZE, "entrypoint")
|
||||
{ }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
typedef Synchronized_ram_session<Ram_session_component> Core_ram_session;
|
||||
|
||||
Core_parent _core_parent;
|
||||
Cap_session_component _cap_session;
|
||||
Entrypoint _entrypoint;
|
||||
Core_ram_session _ram_session;
|
||||
Heap _heap;
|
||||
Ram_session_capability const _ram_session_cap;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Core_env()
|
||||
:
|
||||
Platform_env_base(Ram_session_capability(),
|
||||
Cpu_session_capability(),
|
||||
Pd_session_capability()),
|
||||
_cap_session(platform()->core_mem_alloc(), "ram_quota=4K"),
|
||||
_entrypoint(&_cap_session),
|
||||
_ram_session(&_entrypoint, &_entrypoint,
|
||||
platform()->ram_alloc(), platform()->core_mem_alloc(),
|
||||
"ram_quota=4M", platform()->ram_alloc()->avail()),
|
||||
_heap(&_ram_session, Platform_env_base::rm_session()),
|
||||
_ram_session_cap(_entrypoint.manage(&_ram_session))
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Core_env() { parent()->exit(0); }
|
||||
|
||||
|
||||
/**************************************
|
||||
** Core-specific accessor functions **
|
||||
**************************************/
|
||||
|
||||
Cap_session *cap_session() { return &_cap_session; }
|
||||
Entrypoint *entrypoint() { return &_entrypoint; }
|
||||
|
||||
|
||||
/*******************
|
||||
** Env interface **
|
||||
*******************/
|
||||
|
||||
Parent *parent() { return &_core_parent; }
|
||||
Ram_session *ram_session() { return &_ram_session; }
|
||||
Ram_session_capability ram_session_cap() { return _ram_session_cap; }
|
||||
Allocator *heap() { return &_heap; }
|
||||
|
||||
Cpu_session_capability cpu_session_cap() {
|
||||
PWRN("%s:%u not implemented", __FILE__, __LINE__);
|
||||
return Cpu_session_capability();
|
||||
}
|
||||
|
||||
Pd_session *pd_session()
|
||||
{
|
||||
PWRN("%s:%u not implemented", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reload_parent_cap(Capability<Parent>::Dst, long) { }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Request pointer to static environment of Core
|
||||
*/
|
||||
extern Core_env *core_env();
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__CORE_ENV_H_ */
|
229
repos/base-linux/src/core/include/core_linux_syscalls.h
Normal file
229
repos/base-linux/src/core/include/core_linux_syscalls.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* \brief Linux system calls that are used in core only
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_
|
||||
#define _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_
|
||||
|
||||
/* basic Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** 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);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_dup(int fd)
|
||||
{
|
||||
return lx_syscall(SYS_dup, fd);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Functions used by core's rom-session support code **
|
||||
*******************************************************/
|
||||
|
||||
inline int lx_open(const char *pathname, int flags, mode_t mode = 0)
|
||||
{
|
||||
return lx_syscall(SYS_open, pathname, flags, mode);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
** Process creation and destruction **
|
||||
**************************************/
|
||||
|
||||
inline int lx_execve(const char *filename, char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
return lx_syscall(SYS_execve, filename, argv, envp);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_kill(int pid, int signal)
|
||||
{
|
||||
return lx_syscall(SYS_kill, pid, signal);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_create_process(int (*entry)(void *), void *stack, void *arg)
|
||||
{
|
||||
/*
|
||||
* The low byte of the flags denotes the signal to be sent to the parent
|
||||
* when the process terminates. We want core to receive SIGCHLD signals on
|
||||
* this condition.
|
||||
*/
|
||||
int const flags = CLONE_VFORK | LX_SIGCHLD;
|
||||
return lx_clone((int (*)(void *))entry, stack, flags, arg);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_setuid(unsigned int uid)
|
||||
{
|
||||
return lx_syscall(SYS_setuid, uid);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_setgid(unsigned int gid)
|
||||
{
|
||||
return lx_syscall(SYS_setgid, gid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query PID of any terminated child
|
||||
*
|
||||
* This function is called be core after having received a SIGCHLD signal to
|
||||
* determine the PID of a terminated Genode process.
|
||||
*
|
||||
* \return PID of terminated process or -1 if no process was terminated
|
||||
*/
|
||||
inline int lx_pollpid()
|
||||
{
|
||||
return lx_syscall(SYS_wait4, -1 /* any PID */, (int *)0, 1 /* WNOHANG */, 0);
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** Chroot handling **
|
||||
*********************/
|
||||
|
||||
inline int lx_chroot(char const *path)
|
||||
{
|
||||
return lx_syscall(SYS_chroot, path);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_chdir(char const *path)
|
||||
{
|
||||
return lx_syscall(SYS_chdir, path);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_getcwd(char *dst, size_t dst_len)
|
||||
{
|
||||
return lx_syscall(SYS_getcwd, dst, dst_len);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bindmount(char const *source, char const *target)
|
||||
{
|
||||
enum { MS_BIND = 4096 };
|
||||
return lx_syscall(SYS_mount, source, target, 0, MS_BIND, 0);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_umount(char const *target)
|
||||
{
|
||||
return lx_syscall(SYS_umount2, target, 0);
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
** Communication over Unix-domain sockets **
|
||||
********************************************/
|
||||
|
||||
#ifdef SYS_socketcall
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
long args[3] = { domain, type, protocol };
|
||||
return lx_socketcall(SYS_SOCKET, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
long args[3] = { sockfd, (long)addr, (long)addrlen };
|
||||
return lx_socketcall(SYS_BIND, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_connect(int sockfd, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
long args[3] = { sockfd, (long)serv_addr, (long)addrlen };
|
||||
return lx_socketcall(SYS_CONNECT, args);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
return lx_syscall(SYS_socket, domain, type, protocol);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
return lx_syscall(SYS_bind, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_connect(int sockfd, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
return lx_syscall(SYS_connect, sockfd, serv_addr, addrlen);
|
||||
}
|
||||
|
||||
#endif /* SYS_socketcall */
|
||||
|
||||
|
||||
/******************************
|
||||
** Linux signal dispatching **
|
||||
******************************/
|
||||
|
||||
inline int lx_pipe(int pipefd[2])
|
||||
{
|
||||
return lx_syscall(SYS_pipe, pipefd);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_read(int fd, void *buf, Genode::size_t count)
|
||||
{
|
||||
return lx_syscall(SYS_read, fd, buf, count);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_ */
|
205
repos/base-linux/src/core/include/cpu_session_component.h
Normal file
205
repos/base-linux/src/core/include/cpu_session_component.h
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* \brief Core-specific instance of the CPU session/thread interfaces
|
||||
* \author Christian Helmuth
|
||||
* \author Norman Feske
|
||||
* \date 2006-07-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_
|
||||
#define _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
#include <base/allocator_guard.h>
|
||||
#include <base/lock.h>
|
||||
#include <base/pager.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_thread_allocator.h>
|
||||
#include <platform_thread.h>
|
||||
#include <trace/control_area.h>
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* RPC interface of CPU thread
|
||||
*
|
||||
* We make 'Cpu_thread' a RPC object only to be able to lookup CPU threads
|
||||
* from thread capabilities supplied as arguments to CPU-session functions.
|
||||
* A CPU thread does not provide an actual RPC interface.
|
||||
*/
|
||||
struct Cpu_thread
|
||||
{
|
||||
GENODE_RPC_INTERFACE();
|
||||
};
|
||||
|
||||
|
||||
class Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
public List<Cpu_thread_component>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Trace::Session_label Session_label;
|
||||
typedef Trace::Thread_name Thread_name;
|
||||
|
||||
private:
|
||||
|
||||
Thread_name const _name;
|
||||
Platform_thread _platform_thread;
|
||||
bool _bound; /* pd binding flag */
|
||||
Signal_context_capability _sigh; /* exception handler */
|
||||
unsigned const _trace_control_index;
|
||||
Trace::Source _trace_source;
|
||||
|
||||
public:
|
||||
|
||||
Cpu_thread_component(Session_label const &label,
|
||||
Thread_name const &name,
|
||||
unsigned priority, addr_t utcb,
|
||||
Signal_context_capability sigh,
|
||||
unsigned trace_control_index,
|
||||
Trace::Control &trace_control)
|
||||
:
|
||||
_name(name),
|
||||
_platform_thread(name.string(), priority, utcb), _bound(false),
|
||||
_sigh(sigh), _trace_control_index(trace_control_index),
|
||||
_trace_source(label, _name, trace_control)
|
||||
{
|
||||
update_exception_sigh();
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
** Accessor functions **
|
||||
************************/
|
||||
|
||||
Platform_thread *platform_thread() { return &_platform_thread; }
|
||||
bool bound() const { return _bound; }
|
||||
void bound(bool b) { _bound = b; }
|
||||
Trace::Source *trace_source() { return &_trace_source; }
|
||||
|
||||
void sigh(Signal_context_capability sigh)
|
||||
{
|
||||
_sigh = sigh;
|
||||
update_exception_sigh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate exception handler to platform thread
|
||||
*/
|
||||
void update_exception_sigh();
|
||||
|
||||
/**
|
||||
* Return index within the CPU-session's trace control area
|
||||
*/
|
||||
unsigned trace_control_index() const { return _trace_control_index; }
|
||||
};
|
||||
|
||||
|
||||
class Cpu_session_component : public Rpc_object<Linux_cpu_session>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Cpu_thread_component::Session_label Session_label;
|
||||
|
||||
private:
|
||||
|
||||
Session_label _label;
|
||||
Rpc_entrypoint *_thread_ep;
|
||||
Pager_entrypoint *_pager_ep;
|
||||
Allocator_guard _md_alloc; /* guarded meta-data allocator */
|
||||
Cpu_thread_allocator _thread_alloc; /* meta-data allocator */
|
||||
Lock _thread_alloc_lock; /* protect allocator access */
|
||||
List<Cpu_thread_component> _thread_list;
|
||||
Lock _thread_list_lock; /* protect thread list */
|
||||
unsigned _priority; /* priority of threads
|
||||
created with this
|
||||
session */
|
||||
Affinity::Location _location; /* CPU affinity of this
|
||||
session */
|
||||
Trace::Source_registry &_trace_sources;
|
||||
Trace::Control_area _trace_control_area;
|
||||
|
||||
/**
|
||||
* Exception handler that will be invoked unless overridden by a
|
||||
* call of 'Cpu_session::exception_handler'.
|
||||
*/
|
||||
Signal_context_capability _default_exception_handler;
|
||||
|
||||
/**
|
||||
* Raw thread-killing functionality
|
||||
*
|
||||
* This function is called from the 'kill_thread' function and
|
||||
* the destructor. Each these functions grab the list lock
|
||||
* by themselves and call this function to perform the actual
|
||||
* killing.
|
||||
*/
|
||||
void _unsynchronized_kill_thread(Cpu_thread_component *thread);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Cpu_session_component(Rpc_entrypoint *thread_ep,
|
||||
Pager_entrypoint *pager_ep,
|
||||
Allocator *md_alloc,
|
||||
Trace::Source_registry &trace_sources,
|
||||
const char *args, Affinity const &affinity);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Cpu_session_component();
|
||||
|
||||
/**
|
||||
* Register quota donation at allocator guard
|
||||
*/
|
||||
void upgrade_ram_quota(size_t ram_quota) { _md_alloc.upgrade(ram_quota); }
|
||||
|
||||
|
||||
/***************************
|
||||
** CPU session interface **
|
||||
***************************/
|
||||
|
||||
Thread_capability create_thread(Name const &, addr_t);
|
||||
Ram_dataspace_capability utcb(Thread_capability thread);
|
||||
void kill_thread(Thread_capability);
|
||||
int set_pager(Thread_capability, Pager_capability);
|
||||
int start(Thread_capability, addr_t, addr_t);
|
||||
void pause(Thread_capability thread_cap);
|
||||
void resume(Thread_capability thread_cap);
|
||||
void cancel_blocking(Thread_capability);
|
||||
int name(Thread_capability, char *, size_t);
|
||||
Thread_state state(Thread_capability);
|
||||
void state(Thread_capability, Thread_state const &);
|
||||
void exception_handler(Thread_capability, Signal_context_capability);
|
||||
Affinity::Space affinity_space() const;
|
||||
void affinity(Thread_capability, Affinity::Location);
|
||||
Dataspace_capability trace_control();
|
||||
unsigned trace_control_index(Thread_capability);
|
||||
Dataspace_capability trace_buffer(Thread_capability);
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
|
||||
|
||||
/*******************************
|
||||
** Linux-specific extensions **
|
||||
*******************************/
|
||||
|
||||
void thread_id(Thread_capability, int, int);
|
||||
Untyped_capability server_sd(Thread_capability);
|
||||
Untyped_capability client_sd(Thread_capability);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_ */
|
125
repos/base-linux/src/core/include/dataspace_component.h
Normal file
125
repos/base-linux/src/core/include/dataspace_component.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* \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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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 {
|
||||
|
||||
/**
|
||||
* Deriving classes can own a dataspace to implement conditional behavior
|
||||
*/
|
||||
class Dataspace_owner { };
|
||||
|
||||
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 */
|
||||
int _fd; /* file descriptor */
|
||||
bool _writable; /* false if read-only */
|
||||
|
||||
/* Holds the dataspace owner if a distinction between owner and
|
||||
* others is necessary on the dataspace, otherwise it is 0 */
|
||||
Dataspace_owner * _owner;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Dataspace_component(size_t size, addr_t addr,
|
||||
bool /* write_combined */, bool writable,
|
||||
Dataspace_owner * owner)
|
||||
: _size(size), _addr(addr), _fd(-1), _writable(writable),
|
||||
_owner(owner) { }
|
||||
|
||||
/**
|
||||
* Default constructor returns invalid dataspace
|
||||
*/
|
||||
Dataspace_component()
|
||||
: _size(0), _addr(0), _fd(-1), _writable(false), _owner(0) { }
|
||||
|
||||
/**
|
||||
* 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, Dataspace_owner * _owner)
|
||||
:
|
||||
_size(size), _addr(phys_addr), _fd(-1), _owner(_owner)
|
||||
{
|
||||
PWRN("Should only be used for IOMEM and not within Linux.");
|
||||
_fname.buf[0] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define corresponding filename of dataspace
|
||||
*
|
||||
* The file name is only relevant for ROM dataspaces that should
|
||||
* be executed via execve.
|
||||
*/
|
||||
void fname(const char *fname) { strncpy(_fname.buf, fname, sizeof(_fname.buf)); }
|
||||
|
||||
/**
|
||||
* Assign file descriptor to dataspace
|
||||
*
|
||||
* The file descriptor assigned to the dataspace will be enable
|
||||
* processes outside of core to mmap the dataspace.
|
||||
*/
|
||||
void fd(int fd) { _fd = fd; }
|
||||
|
||||
/**
|
||||
* Check if dataspace is owned by a specified object
|
||||
*/
|
||||
bool owner(Dataspace_owner * const o) const { return _owner == o; }
|
||||
|
||||
/*************************
|
||||
** 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; }
|
||||
|
||||
Untyped_capability fd()
|
||||
{
|
||||
typedef Untyped_capability::Dst Dst;
|
||||
enum { DUMMY_LOCAL_NAME = 0 };
|
||||
return Untyped_capability(Dst(_fd), DUMMY_LOCAL_NAME);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__LINUX__DATASPACE_COMPONENT_H_ */
|
64
repos/base-linux/src/core/include/io_mem_session_component.h
Normal file
64
repos/base-linux/src/core/include/io_mem_session_component.h
Normal 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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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_ */
|
60
repos/base-linux/src/core/include/irq_session_component.h
Normal file
60
repos/base-linux/src/core/include/irq_session_component.h
Normal 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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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_ */
|
69
repos/base-linux/src/core/include/pd_session_component.h
Normal file
69
repos/base-linux/src/core/include/pd_session_component.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* \brief Linux-specific PD session
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__PD_SESSION_COMPONENT_H_
|
||||
#define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/rpc_server.h>
|
||||
#include <linux_pd_session/linux_pd_session.h>
|
||||
|
||||
/* core includes */
|
||||
#include <platform_pd.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
class Pd_session_component : public Rpc_object<Linux_pd_session, Pd_session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
enum { LABEL_MAX_LEN = 1024 };
|
||||
enum { ROOT_PATH_MAX_LEN = 512 };
|
||||
|
||||
unsigned long _pid;
|
||||
char _label[LABEL_MAX_LEN];
|
||||
char _root[ROOT_PATH_MAX_LEN];
|
||||
unsigned _uid;
|
||||
unsigned _gid;
|
||||
Parent_capability _parent;
|
||||
Rpc_entrypoint *_ds_ep;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ds_ep entrypoint where the dataspaces are managed
|
||||
*/
|
||||
Pd_session_component(Rpc_entrypoint *ds_ep, const char *args);
|
||||
|
||||
~Pd_session_component();
|
||||
|
||||
|
||||
/**************************
|
||||
** PD session interface **
|
||||
**************************/
|
||||
|
||||
int bind_thread(Thread_capability);
|
||||
int assign_parent(Parent_capability parent);
|
||||
|
||||
|
||||
/******************************
|
||||
** Linux-specific extension **
|
||||
******************************/
|
||||
|
||||
void start(Capability<Dataspace> binary);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ */
|
100
repos/base-linux/src/core/include/platform.h
Normal file
100
repos/base-linux/src/core/include/platform.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* \brief Linux platform
|
||||
* \author Christian Helmuth
|
||||
* \author Norman Feske
|
||||
* \date 2007-09-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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:
|
||||
|
||||
/**
|
||||
* Allocator for core-internal meta data
|
||||
*/
|
||||
Synchronized_range_allocator<Allocator_avl> _core_mem_alloc;
|
||||
|
||||
/**
|
||||
* Allocator for pseudo physical memory
|
||||
*/
|
||||
struct Pseudo_ram_allocator : Range_allocator
|
||||
{
|
||||
bool alloc(size_t size, void **out_addr)
|
||||
{
|
||||
*out_addr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
Alloc_return alloc_aligned(size_t, void **out_addr, int)
|
||||
{
|
||||
*out_addr = 0;
|
||||
return Alloc_return::OK;
|
||||
}
|
||||
|
||||
Alloc_return alloc_addr(size_t, addr_t)
|
||||
{
|
||||
return Alloc_return::OK;;
|
||||
}
|
||||
|
||||
int add_range(addr_t, size_t) { return 0; }
|
||||
int remove_range(addr_t, size_t) { return 0; }
|
||||
void free(void *) { }
|
||||
void free(void *, size_t) { }
|
||||
size_t avail() { return ~0; }
|
||||
bool valid_addr(addr_t) { return true; }
|
||||
size_t overhead(size_t) { return 0; }
|
||||
|
||||
bool need_size_for_free() const override { return true; }
|
||||
};
|
||||
|
||||
Pseudo_ram_allocator _ram_alloc;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform();
|
||||
|
||||
|
||||
/********************************
|
||||
** Generic platform interface **
|
||||
********************************/
|
||||
|
||||
Range_allocator *core_mem_alloc() { return &_core_mem_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_ */
|
25
repos/base-linux/src/core/include/platform_pd.h
Normal file
25
repos/base-linux/src/core/include/platform_pd.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* \brief Linux protection domain facility
|
||||
* \author Norman Feske
|
||||
* \date 2006-06-13
|
||||
*
|
||||
* Pretty dumb.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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_ */
|
159
repos/base-linux/src/core/include/platform_thread.h
Normal file
159
repos/base-linux/src/core/include/platform_thread.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* \brief Linux thread facility
|
||||
* \author Norman Feske
|
||||
* \date 2006-06-13
|
||||
*
|
||||
* Pretty dumb.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_
|
||||
#define _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_
|
||||
|
||||
#include <base/pager.h>
|
||||
#include <base/thread_state.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
class Platform_thread;
|
||||
|
||||
/*
|
||||
* We hold all Platform_thread objects in a list in order to be able to
|
||||
* reflect SIGCHLD as exception signals. When a SIGCHILD occurs, we
|
||||
* determine the PID of the terminated child process via 'wait4'. We use
|
||||
* the list to find the 'Platform_thread' matching the TID, wherei, in
|
||||
* turn, we find the exception handler's 'Signal_context_capability'.
|
||||
*/
|
||||
|
||||
class Platform_thread : public List<Platform_thread>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
struct Registry
|
||||
{
|
||||
Lock _lock;
|
||||
List<Platform_thread> _list;
|
||||
|
||||
void insert(Platform_thread *thread);
|
||||
void remove(Platform_thread *thread);
|
||||
|
||||
/**
|
||||
* Trigger exception handler for 'Platform_thread' with matching PID.
|
||||
*/
|
||||
void submit_exception(unsigned long pid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return singleton instance of 'Platform_thread::Registry'
|
||||
*/
|
||||
static Registry *_registry();
|
||||
|
||||
unsigned long _tid;
|
||||
unsigned long _pid;
|
||||
char _name[32];
|
||||
|
||||
/**
|
||||
* Unix-domain socket pair bound to the thread
|
||||
*/
|
||||
Native_connection_state _ncs;
|
||||
|
||||
/*
|
||||
* Dummy pager object that is solely used for storing the
|
||||
* 'Signal_context_capability' for the thread's exception handler.
|
||||
*/
|
||||
Pager_object _pager;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(const char *name, unsigned priority, addr_t);
|
||||
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* 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 &_pager; }
|
||||
void pager(Pager_object *) { }
|
||||
int start(void *ip, void *sp) { return 0; }
|
||||
|
||||
Thread_state state()
|
||||
{
|
||||
PDBG("Not implemented");
|
||||
throw Cpu_session::State_access_failed();
|
||||
}
|
||||
|
||||
void state(Thread_state)
|
||||
{
|
||||
PDBG("Not implemented");
|
||||
throw Cpu_session::State_access_failed();
|
||||
}
|
||||
|
||||
const char *name() { return _name; }
|
||||
|
||||
/**
|
||||
* Set the executing CPU for this thread
|
||||
*
|
||||
* SMP is currently not directly supported on Genode/Linux
|
||||
* (but indirectly by the Linux kernel).
|
||||
*/
|
||||
void affinity(Affinity::Location) { }
|
||||
|
||||
/**
|
||||
* Request the affinity of this thread
|
||||
*/
|
||||
Affinity::Location affinity() { return Affinity::Location(); }
|
||||
|
||||
/**
|
||||
* Register process ID and thread ID of thread
|
||||
*/
|
||||
void thread_id(int pid, int tid) { _pid = pid, _tid = tid; }
|
||||
|
||||
/**
|
||||
* Return client-side socket descriptor
|
||||
*
|
||||
* For more information, please refer to the comments in
|
||||
* 'linux_cpu_session/linux_cpu_session.h'.
|
||||
*/
|
||||
int client_sd();
|
||||
|
||||
/**
|
||||
* Return server-side socket descriptor
|
||||
*/
|
||||
int server_sd();
|
||||
|
||||
/**
|
||||
* Notify Genode::Signal handler about sigchld
|
||||
*/
|
||||
static void submit_exception(int pid)
|
||||
{
|
||||
_registry()->submit_exception(pid);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__LINUX__PLATFORM_THREAD_H_ */
|
44
repos/base-linux/src/core/include/resource_path.h
Normal file
44
repos/base-linux/src/core/include/resource_path.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* \brief Genode resource path
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__RPATH_H_
|
||||
#define _CORE__INCLUDE__RPATH_H_
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/**
|
||||
* Return resource path for Genode
|
||||
*
|
||||
* Genode creates files for dataspaces and endpoints under in this directory.
|
||||
*/
|
||||
static inline char const *resource_path()
|
||||
{
|
||||
struct Resource_path
|
||||
{
|
||||
char string[32];
|
||||
|
||||
Resource_path()
|
||||
{
|
||||
Genode::snprintf(string, sizeof(string), "/tmp/genode-%d", lx_getuid());
|
||||
}
|
||||
};
|
||||
|
||||
static Resource_path path;
|
||||
return path.string;
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__RPATH_H_ */
|
76
repos/base-linux/src/core/include/rm_session_component.h
Normal file
76
repos/base-linux/src/core/include/rm_session_component.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* \brief Core-specific instance of the RM session interface
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-07-17
|
||||
*
|
||||
* Dummies for Linux platform
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _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>
|
||||
{
|
||||
private:
|
||||
|
||||
class Rm_dataspace_component {
|
||||
|
||||
public:
|
||||
|
||||
void sub_rm_session(Native_capability _cap) { }
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Rm_session_component(Rpc_entrypoint *ds_ep,
|
||||
Rpc_entrypoint *thread_ep,
|
||||
Rpc_entrypoint *session_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, bool) {
|
||||
return (addr_t)0; }
|
||||
|
||||
void detach(Local_addr) { }
|
||||
|
||||
Pager_capability add_client(Thread_capability) {
|
||||
return Pager_capability(); }
|
||||
|
||||
void remove_client(Pager_capability) { }
|
||||
|
||||
void fault_handler(Signal_context_capability) { }
|
||||
|
||||
State state() { return State(); }
|
||||
|
||||
Dataspace_capability dataspace() { return Dataspace_capability(); }
|
||||
|
||||
Rm_dataspace_component *dataspace_component() { return 0; }
|
||||
};
|
||||
|
||||
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_ */
|
107
repos/base-linux/src/core/include/server_socket_pair.h
Normal file
107
repos/base-linux/src/core/include/server_socket_pair.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* \brief Support for communication over Unix domain sockets
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
|
||||
#define _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <core_linux_syscalls.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
/* include from 'src/base/ipc' */
|
||||
#include <socket_descriptor_registry.h>
|
||||
|
||||
/* core-local includes */
|
||||
#include <resource_path.h>
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Create socket address for server entrypoint at thread ID
|
||||
*/
|
||||
struct Uds_addr : sockaddr_un
|
||||
{
|
||||
Uds_addr(long thread_id)
|
||||
{
|
||||
sun_family = AF_UNIX;
|
||||
Genode::snprintf(sun_path, sizeof(sun_path), "%s/ep-%ld",
|
||||
resource_path(), thread_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Create named socket pair for given unique ID
|
||||
*/
|
||||
static inline Genode::Native_connection_state create_server_socket_pair(long id)
|
||||
{
|
||||
Genode::Native_connection_state ncs;
|
||||
|
||||
/*
|
||||
* Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for
|
||||
* binding.
|
||||
*/
|
||||
if (id == -1)
|
||||
return ncs;
|
||||
|
||||
Uds_addr addr(id);
|
||||
|
||||
/*
|
||||
* Create server-side socket
|
||||
*/
|
||||
ncs.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (ncs.server_sd < 0) {
|
||||
PRAW("Error: Could not create server-side socket (ret=%d)", ncs.server_sd);
|
||||
class Server_socket_failed { };
|
||||
throw Server_socket_failed();
|
||||
}
|
||||
|
||||
/* make sure bind succeeds */
|
||||
lx_unlink(addr.sun_path);
|
||||
|
||||
int const bind_ret = lx_bind(ncs.server_sd, (sockaddr *)&addr, sizeof(addr));
|
||||
if (bind_ret < 0) {
|
||||
PRAW("Error: Could not bind server socket (ret=%d)", bind_ret);
|
||||
class Bind_failed { };
|
||||
throw Bind_failed();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create client-side socket
|
||||
*/
|
||||
ncs.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (ncs.client_sd < 0) {
|
||||
PRAW("Error: Could not create client-side socket (ret=%d)", ncs.client_sd);
|
||||
class Client_socket_failed { };
|
||||
throw Client_socket_failed();
|
||||
}
|
||||
|
||||
int const conn_ret = lx_connect(ncs.client_sd, (sockaddr *)&addr, sizeof(addr));
|
||||
if (conn_ret < 0) {
|
||||
PRAW("Error: Could not connect client-side socket (ret=%d)", conn_ret);
|
||||
class Connect_failed { };
|
||||
throw Connect_failed();
|
||||
}
|
||||
|
||||
ncs.client_sd = Genode::ep_sd_registry()->try_associate(ncs.client_sd, id);
|
||||
|
||||
/*
|
||||
* Wipe Unix domain socket from the file system. It will live as long as
|
||||
* there exist references to it in the form of file descriptors.
|
||||
*/
|
||||
lx_unlink(addr.sun_path);
|
||||
|
||||
return ncs;
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_ */
|
22
repos/base-linux/src/core/include/util.h
Normal file
22
repos/base-linux/src/core/include/util.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* \brief Core-internal utilities
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2014-03-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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__UTIL_H_
|
||||
#define _CORE__INCLUDE__UTIL_H_
|
||||
|
||||
namespace Genode {
|
||||
constexpr size_t get_page_size_log2() { return 12; }
|
||||
constexpr size_t get_page_size() { return 1 << get_page_size_log2(); }
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
27
repos/base-linux/src/core/io_mem_session_component.cc
Normal file
27
repos/base-linux/src/core/io_mem_session_component.cc
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* \brief Linux-specific IO_MEM service
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-09-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
455
repos/base-linux/src/core/pd_session_component.cc
Normal file
455
repos/base-linux/src/core/pd_session_component.cc
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
* \brief Core implementation of the PD session interface
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/arg_string.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/* core-local includes */
|
||||
#include <pd_session_component.h>
|
||||
#include <dataspace_component.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/***********************************
|
||||
** Utilities for chroot handling **
|
||||
***********************************/
|
||||
|
||||
enum { MAX_PATH_LEN = 256 };
|
||||
|
||||
|
||||
/**
|
||||
* Return true if specified path is an existing directory
|
||||
*/
|
||||
static bool is_directory(char const *path)
|
||||
{
|
||||
struct stat64 s;
|
||||
if (lx_stat(path, &s) != 0)
|
||||
return false;
|
||||
|
||||
if (!(s.st_mode & S_IFDIR))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool is_path_delimiter(char c) { return c == '/'; }
|
||||
|
||||
|
||||
static bool has_trailing_path_delimiter(char const *path)
|
||||
{
|
||||
char last_char = 0;
|
||||
for (; *path; path++)
|
||||
last_char = *path;
|
||||
|
||||
return is_path_delimiter(last_char);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return number of path elements of given path
|
||||
*/
|
||||
static Genode::size_t num_path_elements(char const *path)
|
||||
{
|
||||
Genode::size_t count = 0;
|
||||
|
||||
/*
|
||||
* If path starts with non-slash, the first characters belongs to a path
|
||||
* element.
|
||||
*/
|
||||
if (*path && !is_path_delimiter(*path))
|
||||
count = 1;
|
||||
|
||||
/* count slashes */
|
||||
for (; *path; path++)
|
||||
if (is_path_delimiter(*path))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static bool leading_path_elements(char const *path, unsigned num,
|
||||
char *dst, Genode::size_t dst_len)
|
||||
{
|
||||
/* counter of path delimiters */
|
||||
unsigned count = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
if (is_path_delimiter(path[0]))
|
||||
num++;
|
||||
|
||||
for (; path[i] && (count < num) && (i < dst_len); i++)
|
||||
{
|
||||
if (is_path_delimiter(path[i]))
|
||||
count++;
|
||||
|
||||
if (count == num)
|
||||
break;
|
||||
|
||||
dst[i] = path[i];
|
||||
}
|
||||
|
||||
if (i + 1 < dst_len) {
|
||||
dst[i] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* string is cut, append null termination anyway */
|
||||
dst[dst_len - 1] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void mirror_path_to_chroot(char const *chroot_path, char const *path)
|
||||
{
|
||||
char target_path[MAX_PATH_LEN];
|
||||
Genode::snprintf(target_path, sizeof(target_path), "%s%s",
|
||||
chroot_path, path);
|
||||
|
||||
/*
|
||||
* Create directory hierarchy pointing to the target path except for the
|
||||
* last element. The last element will be bind-mounted to refer to the
|
||||
* original 'path'.
|
||||
*/
|
||||
for (unsigned i = 1; i <= num_path_elements(target_path); i++)
|
||||
{
|
||||
char buf[MAX_PATH_LEN];
|
||||
leading_path_elements(target_path, i, buf, sizeof(buf));
|
||||
|
||||
/* skip existing directories */
|
||||
if (is_directory(buf))
|
||||
continue;
|
||||
|
||||
/* create new directory */
|
||||
lx_mkdir(buf, 0777);
|
||||
}
|
||||
|
||||
lx_umount(target_path);
|
||||
|
||||
int ret = 0;
|
||||
if ((ret = lx_bindmount(path, target_path)))
|
||||
PERR("bind mount failed (errno=%d)", ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup content of chroot environment as prerequisite to 'execve' new
|
||||
* processes within the environment. I.e., the current working directory
|
||||
* containing the ROM modules must be mounted at the same location within the
|
||||
* chroot environment.
|
||||
*/
|
||||
static bool setup_chroot_environment(char const *chroot_path)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
static char cwd_path[MAX_PATH_LEN];
|
||||
|
||||
lx_getcwd(cwd_path, sizeof(cwd_path));
|
||||
|
||||
/*
|
||||
* Validate chroot path
|
||||
*/
|
||||
if (!is_directory(chroot_path)) {
|
||||
PERR("chroot path does not point to valid directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (has_trailing_path_delimiter(chroot_path)) {
|
||||
PERR("chroot path has trailing slash");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardlink directories needed for running Genode within the chroot
|
||||
* environment.
|
||||
*/
|
||||
mirror_path_to_chroot(chroot_path, cwd_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
** Utilities **
|
||||
***************/
|
||||
|
||||
/**
|
||||
* Argument frame for passing 'execve' paremeters through 'clone'
|
||||
*/
|
||||
struct Execve_args
|
||||
{
|
||||
char const *filename;
|
||||
char const *root;
|
||||
char * const *argv;
|
||||
char * const *envp;
|
||||
unsigned int const uid;
|
||||
unsigned int const gid;
|
||||
int const parent_sd;
|
||||
|
||||
Execve_args(char const *filename,
|
||||
char const *root,
|
||||
char * const *argv,
|
||||
char * const *envp,
|
||||
unsigned int uid,
|
||||
unsigned int gid,
|
||||
int parent_sd)
|
||||
:
|
||||
filename(filename), root(root), argv(argv), envp(envp),
|
||||
uid(uid), gid(gid), parent_sd(parent_sd)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Startup code of the new child process
|
||||
*/
|
||||
static int _exec_child(Execve_args *arg)
|
||||
{
|
||||
lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE);
|
||||
|
||||
/* change to chroot environment */
|
||||
if (arg->root && arg->root[0]) {
|
||||
char cwd[1024];
|
||||
|
||||
PDBG("arg->root='%s'", arg->root);
|
||||
|
||||
if (setup_chroot_environment(arg->root) == false) {
|
||||
PERR("Could not setup chroot environment");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!lx_getcwd(cwd, sizeof(cwd))) {
|
||||
PERR("Failed to getcwd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PLOG("changing root of %s (PID %d) to %s",
|
||||
arg->filename, lx_getpid(), arg->root);
|
||||
|
||||
int ret = lx_chroot(arg->root);
|
||||
if (ret < 0) {
|
||||
PERR("Syscall chroot failed (errno %d)", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = lx_chdir(cwd);
|
||||
if (ret < 0) {
|
||||
PERR("chdir to new chroot failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set UID and GID
|
||||
*
|
||||
* We must set the GID prior setting the UID because setting the GID won't
|
||||
* be possible anymore once we set the UID to non-root.
|
||||
*/
|
||||
if (arg->gid) {
|
||||
int const ret = lx_setgid(arg->gid);
|
||||
if (ret)
|
||||
PWRN("Could not set PID %d (%s) to GID %u (error %d)",
|
||||
lx_getpid(), arg->filename, arg->gid, ret);
|
||||
}
|
||||
if (arg->uid) {
|
||||
int const ret = lx_setuid(arg->uid);
|
||||
if (ret)
|
||||
PWRN("Could not set PID %d (%s) to UID %u (error %d)",
|
||||
lx_getpid(), arg->filename, arg->uid, ret);
|
||||
}
|
||||
|
||||
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 = Genode::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 "";
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
** PD session interface **
|
||||
**************************/
|
||||
|
||||
Pd_session_component::Pd_session_component(Rpc_entrypoint *ep, const char *args)
|
||||
:
|
||||
_pid(0), _uid(0), _gid(0), _ds_ep(ep)
|
||||
{
|
||||
Arg_string::find_arg(args, "label").string(_label, sizeof(_label),
|
||||
"<unlabeled>");
|
||||
|
||||
/*
|
||||
* Read Linux-specific session arguments
|
||||
*/
|
||||
Arg_string::find_arg(args, "root").string(_root, sizeof(_root), "");
|
||||
|
||||
_uid = Arg_string::find_arg(args, "uid").ulong_value(0);
|
||||
_gid = Arg_string::find_arg(args, "gid").ulong_value(0);
|
||||
|
||||
bool const is_chroot = (Genode::strcmp(_root, "") != 0);
|
||||
|
||||
/*
|
||||
* If a UID is specified but no GID, we use the UID as GID. This way, a
|
||||
* configuration error where the UID is defined but the GID is left
|
||||
* undefined won't result in the execution of the new process with the
|
||||
* root user's GID.
|
||||
*/
|
||||
if (_gid == 0)
|
||||
_gid = _uid;
|
||||
|
||||
/*
|
||||
* Print Linux-specific session arguments if specified
|
||||
*
|
||||
* This output used for the automated 'lx_pd_args' test.
|
||||
*/
|
||||
if (is_chroot || _uid || _gid)
|
||||
printf("PD session for '%s'\n", _label);
|
||||
|
||||
if (is_chroot) printf(" root: %s\n", _root);
|
||||
if (_uid) printf(" uid: %u\n", _uid);
|
||||
if (_gid) printf(" gid: %u\n", _gid);
|
||||
}
|
||||
|
||||
|
||||
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 parent)
|
||||
{
|
||||
_parent = parent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Pd_session_component::start(Capability<Dataspace> binary)
|
||||
{
|
||||
const char *tmp_filename = "temporary_executable_elf_dataspace_file_for_execve";
|
||||
|
||||
/* lookup binary dataspace */
|
||||
Object_pool<Dataspace_component>::Guard ds(_ds_ep->lookup_and_lock(binary));
|
||||
|
||||
if (!ds) {
|
||||
PERR("could not lookup binary, aborted PD startup");
|
||||
return; /* XXX reflect error to client */
|
||||
}
|
||||
|
||||
const char *filename = ds->fname().buf;
|
||||
|
||||
/*
|
||||
* In order to be executable via 'execve', a program must be represented as
|
||||
* a file on the Linux file system. However, this is not the case for a
|
||||
* plain RAM dataspace that contains an ELF image. In this case, we copy
|
||||
* the dataspace content into a temporary file whose path is passed to
|
||||
* 'execve()'.
|
||||
*/
|
||||
if (strcmp(filename, "") == 0) {
|
||||
|
||||
filename = tmp_filename;
|
||||
|
||||
int tmp_binary_fd = lx_open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRWXU);
|
||||
if (tmp_binary_fd < 0) {
|
||||
PERR("Could not create file '%s'", filename);
|
||||
return; /* XXX reflect error to client */
|
||||
}
|
||||
|
||||
char buf[4096];
|
||||
int num_bytes = 0;
|
||||
while ((num_bytes = lx_read(ds->fd().dst().socket, buf, sizeof(buf))) != 0)
|
||||
lx_write(tmp_binary_fd, buf, num_bytes);
|
||||
|
||||
lx_close(tmp_binary_fd);
|
||||
}
|
||||
|
||||
/* pass parent capability as environment variable to the child */
|
||||
enum { ENV_STR_LEN = 256 };
|
||||
static char envbuf[5][ENV_STR_LEN];
|
||||
Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu",
|
||||
_parent.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 };
|
||||
|
||||
/* prefix name of Linux program (helps killing some zombies) */
|
||||
char const *prefix = "[Genode] ";
|
||||
char pname_buf[sizeof(_label) + sizeof(prefix)];
|
||||
snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _label);
|
||||
char *argv_buf[2];
|
||||
argv_buf[0] = pname_buf;
|
||||
argv_buf[1] = 0;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
Execve_args arg(filename, _root, argv_buf, env, _uid, _gid,
|
||||
_parent.dst().socket);
|
||||
|
||||
_pid = lx_create_process((int (*)(void *))_exec_child,
|
||||
stack + STACK_SIZE - sizeof(umword_t), &arg);
|
||||
|
||||
if (strcmp(filename, tmp_filename) == 0)
|
||||
lx_unlink(filename);
|
||||
};
|
247
repos/base-linux/src/core/platform.cc
Normal file
247
repos/base-linux/src/core/platform.cc
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* \brief Linux platform interface implementation
|
||||
* \author Norman Feske
|
||||
* \date 2006-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/lock.h>
|
||||
#include <linux_dataspace/client.h>
|
||||
|
||||
/* local includes */
|
||||
#include "platform.h"
|
||||
#include "core_env.h"
|
||||
#include "server_socket_pair.h"
|
||||
|
||||
/* Linux includes */
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/**
|
||||
* Memory pool used for for core-local meta data
|
||||
*/
|
||||
static char _core_mem[80*1024*1024];
|
||||
|
||||
|
||||
/*
|
||||
* Basic semaphore implementation based on the 'pipe' syscall.
|
||||
*
|
||||
* This alternative implementation is needed to be able to wake up the
|
||||
* blocked main thread from a signal handler executed by the same thread.
|
||||
*/
|
||||
class Pipe_semaphore
|
||||
{
|
||||
private:
|
||||
|
||||
int _pipefd[2];
|
||||
|
||||
public:
|
||||
|
||||
Pipe_semaphore()
|
||||
{
|
||||
lx_pipe(_pipefd);
|
||||
}
|
||||
|
||||
void down()
|
||||
{
|
||||
char dummy;
|
||||
while(lx_read(_pipefd[0], &dummy, 1) != 1);
|
||||
}
|
||||
|
||||
void up()
|
||||
{
|
||||
char dummy;
|
||||
while (lx_write(_pipefd[1], &dummy, 1) != 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Pipe_semaphore _wait_for_exit_sem; /* wakeup of '_wait_for_exit' */
|
||||
static bool _do_exit = false; /* exit condition */
|
||||
|
||||
|
||||
static void sigint_handler(int signum)
|
||||
{
|
||||
_do_exit = true;
|
||||
_wait_for_exit_sem.up();
|
||||
}
|
||||
|
||||
|
||||
static void sigchld_handler(int signnum)
|
||||
{
|
||||
_wait_for_exit_sem.up();
|
||||
}
|
||||
|
||||
|
||||
Platform::Platform()
|
||||
: _core_mem_alloc(0)
|
||||
{
|
||||
/* catch control-c */
|
||||
lx_sigaction(LX_SIGINT, sigint_handler);
|
||||
|
||||
/* catch SIGCHLD */
|
||||
lx_sigaction(LX_SIGCHLD, sigchld_handler);
|
||||
|
||||
/* create resource directory under /tmp */
|
||||
lx_mkdir(resource_path(), S_IRWXU);
|
||||
|
||||
_core_mem_alloc.add_range((addr_t)_core_mem, sizeof(_core_mem));
|
||||
|
||||
/*
|
||||
* Occupy the socket handle that will be used to propagate the parent
|
||||
* capability new processes. Otherwise, there may be the chance that the
|
||||
* parent capability as supplied by the process creator will be assigned to
|
||||
* this handle, which would result in a 'dup2' syscall taking
|
||||
* PARENT_SOCKET_HANDLE as both source and target descriptor.
|
||||
*/
|
||||
lx_dup2(0, PARENT_SOCKET_HANDLE);
|
||||
}
|
||||
|
||||
|
||||
void Platform::wait_for_exit()
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/*
|
||||
* Block until a signal occurs.
|
||||
*/
|
||||
_wait_for_exit_sem.down();
|
||||
|
||||
/*
|
||||
* Each time, the '_wait_for_exit_sem' gets unlocked, we could have
|
||||
* received either a SIGINT or SIGCHLD. If a SIGINT was received, the
|
||||
* '_exit' condition will be set.
|
||||
*/
|
||||
if (_do_exit)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Reflect SIGCHLD as exception signal to the signal context of the CPU
|
||||
* session of the process. Because multiple children could have been
|
||||
* terminated, we iterate until 'pollpid' (wrapper around 'wait4')
|
||||
* returns -1.
|
||||
*/
|
||||
for (;;) {
|
||||
int const pid = lx_pollpid();
|
||||
|
||||
if (pid <= 0)
|
||||
break;
|
||||
|
||||
Platform_thread::submit_exception(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Core_parent::exit(int exit_value)
|
||||
{
|
||||
lx_exit_group(exit_value);
|
||||
}
|
||||
|
||||
|
||||
/*****************************
|
||||
** Support for IPC library **
|
||||
*****************************/
|
||||
|
||||
namespace Genode {
|
||||
|
||||
Native_connection_state server_socket_pair()
|
||||
{
|
||||
return create_server_socket_pair(Thread_base::myself()->tid().tid);
|
||||
}
|
||||
|
||||
void destroy_server_socket_pair(Native_connection_state const &ncs)
|
||||
{
|
||||
/*
|
||||
* As entrypoints in core are never destructed, this function is only
|
||||
* called on IPC-client destruction. In this case, it's a no-op in core
|
||||
* as well as in Genode processes.
|
||||
*/
|
||||
if (ncs.server_sd != -1 || ncs.client_sd != -1)
|
||||
PERR("%s called for IPC server which should never happen", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************
|
||||
** Support for Platform_env_base::Rm_session_mmap **
|
||||
****************************************************/
|
||||
|
||||
Genode::size_t
|
||||
Platform_env_base::Rm_session_mmap::_dataspace_size(Capability<Dataspace> ds_cap)
|
||||
{
|
||||
if (!ds_cap.valid())
|
||||
return Dataspace_capability::deref(ds_cap)->size();
|
||||
|
||||
/* use RPC if called from a different thread */
|
||||
if (!core_env()->entrypoint()->is_myself()) {
|
||||
/* release Rm_session_mmap::_lock during RPC */
|
||||
_lock.unlock();
|
||||
Genode::size_t size = Dataspace_client(ds_cap).size();
|
||||
_lock.lock();
|
||||
return size;
|
||||
}
|
||||
|
||||
/* use local function call if called from the entrypoint */
|
||||
Object_pool<Rpc_object_base>::Guard
|
||||
ds_rpc(core_env()->entrypoint()->lookup_and_lock(ds_cap));
|
||||
Dataspace * ds = dynamic_cast<Dataspace *>(&*ds_rpc);
|
||||
return ds ? ds->size() : 0;
|
||||
}
|
||||
|
||||
|
||||
int Platform_env_base::Rm_session_mmap::_dataspace_fd(Capability<Dataspace> ds_cap)
|
||||
{
|
||||
if (!core_env()->entrypoint()->is_myself()) {
|
||||
/* release Rm_session_mmap::_lock during RPC */
|
||||
_lock.unlock();
|
||||
int socket = Linux_dataspace_client(ds_cap).fd().dst().socket;
|
||||
_lock.lock();
|
||||
return socket;
|
||||
}
|
||||
|
||||
Capability<Linux_dataspace> lx_ds_cap = static_cap_cast<Linux_dataspace>(ds_cap);
|
||||
|
||||
Object_pool<Rpc_object_base>::Guard
|
||||
ds_rpc(core_env()->entrypoint()->lookup_and_lock(lx_ds_cap));
|
||||
Linux_dataspace * ds = dynamic_cast<Linux_dataspace *>(&*ds_rpc);
|
||||
|
||||
/*
|
||||
* Return a duplicate of the dataspace file descriptor, which will be freed
|
||||
* immediately after mmap'ing the file (see 'Rm_session_mmap').
|
||||
*
|
||||
* Handing out the original file descriptor would result in the premature
|
||||
* release of the descriptor. So the descriptor could be reused (i.e., as a
|
||||
* socket descriptor during the RPC handling). When later destroying the
|
||||
* dataspace, the descriptor would unexpectedly be closed again.
|
||||
*/
|
||||
return ds ? lx_dup(ds->fd().dst().socket) : -1;
|
||||
}
|
||||
|
||||
|
||||
bool Platform_env_base::Rm_session_mmap::_dataspace_writable(Dataspace_capability ds_cap)
|
||||
{
|
||||
if (!core_env()->entrypoint()->is_myself()) {
|
||||
/* release Rm_session_mmap::_lock during RPC */
|
||||
_lock.unlock();
|
||||
bool writable = Dataspace_client(ds_cap).writable();
|
||||
_lock.lock();
|
||||
return writable;
|
||||
}
|
||||
|
||||
Object_pool<Rpc_object_base>::Guard
|
||||
ds_rpc(core_env()->entrypoint()->lookup_and_lock(ds_cap));
|
||||
Dataspace * ds = dynamic_cast<Dataspace *>(&*ds_rpc);
|
||||
|
||||
return ds ? ds->writable() : false;
|
||||
}
|
133
repos/base-linux/src/core/platform_thread.cc
Normal file
133
repos/base-linux/src/core/platform_thread.cc
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* \brief Linux-specific platform thread implementation
|
||||
* \author Norman Feske
|
||||
* \date 2007-10-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/token.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* local includes */
|
||||
#include "platform_thread.h"
|
||||
#include "server_socket_pair.h"
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
typedef Token<Scanner_policy_identifier_with_underline> Tid_token;
|
||||
|
||||
|
||||
/*******************************
|
||||
** Platform_thread::Registry **
|
||||
*******************************/
|
||||
|
||||
void Platform_thread::Registry::insert(Platform_thread *thread)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
_list.insert(thread);
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::Registry::remove(Platform_thread *thread)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
_list.remove(thread);
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::Registry::submit_exception(unsigned long pid)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
/* traverse list to find 'Platform_thread' with matching PID */
|
||||
for (Platform_thread *curr = _list.first(); curr; curr = curr->next()) {
|
||||
|
||||
if (curr->_tid == pid) {
|
||||
Signal_context_capability sigh = curr->_pager._sigh;
|
||||
|
||||
if (sigh.valid())
|
||||
Signal_transmitter(sigh).submit();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Registry *Platform_thread::_registry()
|
||||
{
|
||||
static Platform_thread::Registry registry;
|
||||
return ®istry;
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** Platform_thread **
|
||||
*********************/
|
||||
|
||||
Platform_thread::Platform_thread(const char *name, unsigned, addr_t)
|
||||
: _tid(-1), _pid(-1)
|
||||
{
|
||||
strncpy(_name, name, min(sizeof(_name), strlen(name) + 1));
|
||||
|
||||
_registry()->insert(this);
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
ep_sd_registry()->disassociate(_ncs.client_sd);
|
||||
|
||||
if (_ncs.client_sd)
|
||||
lx_close(_ncs.client_sd);
|
||||
|
||||
if (_ncs.server_sd)
|
||||
lx_close(_ncs.server_sd);
|
||||
|
||||
_registry()->remove(this);
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
int Platform_thread::client_sd()
|
||||
{
|
||||
/* construct socket pair on first call */
|
||||
if (_ncs.client_sd == -1)
|
||||
_ncs = create_server_socket_pair(_tid);
|
||||
|
||||
return _ncs.client_sd;
|
||||
}
|
||||
|
||||
|
||||
int Platform_thread::server_sd()
|
||||
{
|
||||
client_sd();
|
||||
return _ncs.server_sd;
|
||||
}
|
64
repos/base-linux/src/core/ram_session_support.cc
Normal file
64
repos/base-linux/src/core/ram_session_support.cc
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* \brief Make dataspace accessible to other Linux processes
|
||||
* \author Norman Feske
|
||||
* \date 2006-07-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* glibc includes */
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/* local includes */
|
||||
#include <ram_session_component.h>
|
||||
#include <resource_path.h>
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <core_linux_syscalls.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[Linux_dataspace::FNAME_LEN];
|
||||
|
||||
/* create file using a unique file name in the resource path */
|
||||
snprintf(fname, sizeof(fname), "%s/ds-%d", resource_path(), ram_ds_cnt++);
|
||||
lx_unlink(fname);
|
||||
int const fd = lx_open(fname, O_CREAT|O_RDWR|O_TRUNC|LX_O_CLOEXEC, S_IRWXU);
|
||||
lx_ftruncate(fd, ds->size());
|
||||
|
||||
/* remember file descriptor in dataspace component object */
|
||||
ds->fd(fd);
|
||||
|
||||
/*
|
||||
* Wipe the file from the Linux file system. The kernel will still keep the
|
||||
* then unnamed file around until the last reference to the file will be
|
||||
* gone (i.e., an open file descriptor referring to the file). A process
|
||||
* w/o the right file descriptor won't be able to open and access the file.
|
||||
*/
|
||||
lx_unlink(fname);
|
||||
}
|
||||
|
||||
|
||||
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
|
||||
{
|
||||
int const fd = ds->fd().dst().socket;
|
||||
if (fd != -1)
|
||||
lx_close(fd);
|
||||
}
|
||||
|
||||
|
||||
void Ram_session_component::_clear_ds(Dataspace_component *ds) { }
|
84
repos/base-linux/src/core/rom_session_component.cc
Normal file
84
repos/base-linux/src/core/rom_session_component.cc
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* \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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Linux includes */
|
||||
#include <core_linux_syscalls.h>
|
||||
#include <sys/fcntl.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[Linux_dataspace::FNAME_LEN];
|
||||
Arg_string::find_arg(args, "filename").string(fname, sizeof(fname), "");
|
||||
|
||||
/* only files inside the current working directory are allowed */
|
||||
for (const char *c = fname; *c; c++)
|
||||
if (*c == '/')
|
||||
throw Root::Invalid_args();
|
||||
|
||||
Genode::size_t const fsize = file_size(fname);
|
||||
|
||||
/* use invalid capability as default value */
|
||||
_ds_cap = Rom_dataspace_capability();
|
||||
|
||||
/* ROM module not found */
|
||||
if (fsize == 0)
|
||||
throw Root::Invalid_args();
|
||||
|
||||
int const fd = lx_open(fname, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR);
|
||||
|
||||
_ds = Dataspace_component(fsize, 0, false, false, 0);
|
||||
_ds.fd(fd);
|
||||
_ds.fname(fname);
|
||||
|
||||
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);
|
||||
|
||||
int const fd = _ds.fd().dst().socket;
|
||||
if (fd != -1)
|
||||
lx_close(fd);
|
||||
}
|
60
repos/base-linux/src/core/target.mk
Normal file
60
repos/base-linux/src/core/target.mk
Normal file
@ -0,0 +1,60 @@
|
||||
TARGET = core
|
||||
REQUIRES = linux
|
||||
LIBS = cxx base-common syscall startup
|
||||
|
||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||
|
||||
SRC_CC = main.cc \
|
||||
platform.cc \
|
||||
platform_thread.cc \
|
||||
platform_services.cc \
|
||||
ram_session_component.cc \
|
||||
ram_session_support.cc \
|
||||
rom_session_component.cc \
|
||||
cpu_session_component.cc \
|
||||
cpu_session_extension.cc \
|
||||
cpu_session_support.cc \
|
||||
pd_session_component.cc \
|
||||
io_mem_session_component.cc \
|
||||
signal_session_component.cc \
|
||||
signal_source_component.cc \
|
||||
trace_session_component.cc \
|
||||
thread_linux.cc \
|
||||
context_area.cc \
|
||||
core_printf.cc \
|
||||
thread.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/core/include \
|
||||
$(GEN_CORE_DIR)/include \
|
||||
$(REP_DIR)/src/platform \
|
||||
$(REP_DIR)/src/base/ipc \
|
||||
$(REP_DIR)/src/base/env \
|
||||
$(BASE_DIR)/src/base/env \
|
||||
$(REP_DIR)/src/base/console \
|
||||
$(BASE_DIR)/src/base/thread \
|
||||
|
||||
HOST_INC_DIR += /usr/include
|
||||
|
||||
#
|
||||
# core does not use POSIX threads when built for the 'lx_hybrid_x86' platform,
|
||||
# so we need to reserve the thread-context area via a segment in the program to
|
||||
# prevent clashes with vdso and shared libraries.
|
||||
#
|
||||
ifeq ($(findstring always_hybrid, $(SPECS)), always_hybrid)
|
||||
LD_SCRIPT_STATIC = $(LD_SCRIPT_DEFAULT) \
|
||||
$(call select_from_repositories,src/platform/context_area.stdlib.ld)
|
||||
endif
|
||||
|
||||
include $(GEN_CORE_DIR)/version.inc
|
||||
|
||||
vpath main.cc $(GEN_CORE_DIR)
|
||||
vpath ram_session_component.cc $(GEN_CORE_DIR)
|
||||
vpath cpu_session_component.cc $(GEN_CORE_DIR)
|
||||
vpath platform_services.cc $(GEN_CORE_DIR)
|
||||
vpath signal_session_component.cc $(GEN_CORE_DIR)
|
||||
vpath signal_source_component.cc $(GEN_CORE_DIR)
|
||||
vpath trace_session_component.cc $(GEN_CORE_DIR)
|
||||
vpath core_printf.cc $(BASE_DIR)/src/base/console
|
||||
vpath thread.cc $(BASE_DIR)/src/base/thread
|
||||
vpath trace.cc $(BASE_DIR)/src/base/thread
|
||||
vpath %.cc $(PRG_DIR)
|
62
repos/base-linux/src/core/thread_linux.cc
Normal file
62
repos/base-linux/src/core/thread_linux.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* \brief Implementation of the core-internal Thread API via Linux threads
|
||||
* \author Norman Feske
|
||||
* \date 2006-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* 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) { }
|
||||
|
||||
|
||||
void Thread_base::_thread_start()
|
||||
{
|
||||
/*
|
||||
* Set signal handler such that canceled system calls get not transparently
|
||||
* retried after a signal gets received.
|
||||
*/
|
||||
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
||||
|
||||
/*
|
||||
* Deliver SIGCHLD signals to no thread other than the main thread. Core's
|
||||
* main thread will handle the signals while executing the 'wait_for_exit'
|
||||
* function, which is known to not hold any locks that would interfere with
|
||||
* the handling of the signal.
|
||||
*/
|
||||
lx_sigsetmask(LX_SIGCHLD, false);
|
||||
|
||||
Thread_base::myself()->entry();
|
||||
Thread_base::myself()->_join_lock.unlock();
|
||||
sleep_forever();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::_init_platform_thread(Type) { }
|
||||
|
||||
|
||||
void Thread_base::_deinit_platform_thread() { }
|
||||
|
||||
|
||||
void Thread_base::start()
|
||||
{
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
_tid.pid = lx_getpid();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::cancel_blocking() { }
|
94
repos/base-linux/src/platform/arm/lx_clone.S
Normal file
94
repos/base-linux/src/platform/arm/lx_clone.S
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* \brief Linux clone() binding
|
||||
* \author Christian Prochaska
|
||||
* \date 2012-05-05
|
||||
*
|
||||
* based on eglibc-2.11.3/ports/sysdeps/unix/sysv/linux/arm/clone.S
|
||||
*/
|
||||
|
||||
#define SYS_clone 120
|
||||
#define SYS_exit 1
|
||||
#define SYS_getpid 20
|
||||
|
||||
#define __ARM_EABI__ 1
|
||||
|
||||
#define CLONE_VM 0x00000100
|
||||
#define CLONE_THREAD 0x00010000
|
||||
|
||||
.text
|
||||
.globl lx_clone
|
||||
.type lx_clone, #function
|
||||
lx_clone:
|
||||
|
||||
@ insert the args onto the new stack
|
||||
str r3, [r1, #-4]!
|
||||
str r0, [r1, #-4]!
|
||||
|
||||
@ do the system call
|
||||
@ get flags
|
||||
mov r0, r2
|
||||
#ifdef RESET_PID
|
||||
mov ip, r2
|
||||
#endif
|
||||
@ new sp is already in r1
|
||||
#ifdef __ARM_EABI__
|
||||
stmfd sp!, {r4, r7}
|
||||
#else
|
||||
str r4, [sp, #-8]!
|
||||
#endif
|
||||
ldr r2, [sp, #8]
|
||||
ldr r3, [sp, #12]
|
||||
ldr r4, [sp, #16]
|
||||
#ifdef __ARM_EABI__
|
||||
ldr r7, =SYS_clone
|
||||
swi 0x0
|
||||
#else
|
||||
swi SYS_clone
|
||||
#endif
|
||||
cmp r0, #0
|
||||
beq 1f
|
||||
#ifdef __ARM_EABI__
|
||||
ldmfd sp!, {r4, r7}
|
||||
#else
|
||||
ldr r4, [sp], #8
|
||||
#endif
|
||||
#blt PLTJMP(C_SYMBOL_NAME(__syscall_error))
|
||||
bx lr
|
||||
|
||||
1:
|
||||
#ifdef RESET_PID
|
||||
tst ip, #CLONE_THREAD
|
||||
bne 3f
|
||||
mov r0, #0xffff0fff
|
||||
mov lr, pc
|
||||
sub pc, r0, #31
|
||||
mov r1, r0
|
||||
tst ip, #CLONE_VM
|
||||
movne r0, #-1
|
||||
#ifdef __ARM_EABI__
|
||||
ldr r7, =SYS_getpid
|
||||
swieq 0x0
|
||||
#else
|
||||
swieq SYS_getpid
|
||||
#endif
|
||||
str r0, [r1, #PID_OFFSET]
|
||||
str r0, [r1, #TID_OFFSET]
|
||||
3:
|
||||
#endif
|
||||
@ pick the function arg and call address off the stack and execute
|
||||
ldr r0, [sp, #4]
|
||||
#if defined(__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)
|
||||
ldr ip, [sp], #8
|
||||
mov lr, pc
|
||||
bx ip
|
||||
#else
|
||||
mov lr, pc
|
||||
ldr pc, [sp], #8
|
||||
#endif
|
||||
|
||||
@ and we are done, passing the return value through r0
|
||||
ldr r7, =SYS_exit
|
||||
swi 0x0
|
||||
|
||||
/* tell the linker that this code does not need an executable stack */
|
||||
.section .note.GNU-stack, "", %progbits
|
29
repos/base-linux/src/platform/arm/lx_syscall.S
Normal file
29
repos/base-linux/src/platform/arm/lx_syscall.S
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* \brief Linux syscall() binding
|
||||
* \author Christian Prochaska
|
||||
* \date 2012-05-05
|
||||
*
|
||||
* based on eglibc-2.11.3/ports/sysdeps/unix/sysv/linux/arm/syscall.S
|
||||
*
|
||||
* error case:
|
||||
* glibc's syscall() function returns -1 and sets errno
|
||||
* lx_syscall() returns -errno
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl lx_syscall
|
||||
.type lx_syscall, #function
|
||||
lx_syscall:
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
mov r7, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
ldmfd ip, {r3, r4, r5, r6}
|
||||
swi 0x0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
bx lr
|
||||
|
||||
/* tell the linker that this code does not need an executable stack */
|
||||
.section .note.GNU-stack, "", %progbits
|
64
repos/base-linux/src/platform/context_area.h
Normal file
64
repos/base-linux/src/platform/context_area.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* \brief Linux-specific utilities for context area
|
||||
* \author Christian Helmuth
|
||||
* \date 2013-09-26
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM__CONTEXT_AREA_H_
|
||||
#define _PLATFORM__CONTEXT_AREA_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <rm_session/rm_session.h>
|
||||
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
static inline void flush_context_area()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
void * const base = (void *) Native_config::context_area_virtual_base();
|
||||
size_t const size = Native_config::context_area_virtual_size();
|
||||
|
||||
int ret;
|
||||
if ((ret = lx_munmap(base, size)) < 0) {
|
||||
PERR("%s: failed ret=%d", __func__, ret);
|
||||
throw Rm_session::Region_conflict();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline Genode::addr_t reserve_context_area()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
int const flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||
int const prot = PROT_NONE;
|
||||
size_t const size = Native_config::context_area_virtual_size();
|
||||
void * const addr_in = (void *)Native_config::context_area_virtual_base();
|
||||
void * const addr_out = lx_mmap(addr_in, size, prot, flags, -1, 0);
|
||||
|
||||
/* reserve at local address failed - unmap incorrect mapping */
|
||||
if (addr_in != addr_out) {
|
||||
lx_munmap((void *)addr_out, size);
|
||||
|
||||
PERR("%s: failed addr_in=%p addr_out=%p ret=%ld)", __func__,
|
||||
addr_in, addr_out, (long)addr_out);
|
||||
throw Rm_session::Region_conflict();
|
||||
}
|
||||
|
||||
return (addr_t) addr_out;
|
||||
}
|
||||
|
||||
#endif /* _PLATFORM__CONTEXT_AREA_H_ */
|
25
repos/base-linux/src/platform/context_area.nostdlib.ld
Normal file
25
repos/base-linux/src/platform/context_area.nostdlib.ld
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* \brief Linux-specific linker script additions (STDLIB = no)
|
||||
* \author Christian Helmuth
|
||||
* \date 2010-09-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
PHDRS
|
||||
{
|
||||
context_area PT_LOAD FLAGS(0);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40000000;
|
||||
_context_area_start = .;
|
||||
.context_area : { . += 0x10000000; } : context_area
|
||||
_context_area_end = .;
|
||||
}
|
20
repos/base-linux/src/platform/context_area.stdlib.ld
Normal file
20
repos/base-linux/src/platform/context_area.stdlib.ld
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* \brief Linux-specific linker script additions (STDLIB = yes)
|
||||
* \author Christian Helmuth
|
||||
* \date 2010-09-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40000000;
|
||||
_context_area_start = .;
|
||||
.context_area : { . += 0x10000000; }
|
||||
_context_area_end = .;
|
||||
}
|
391
repos/base-linux/src/platform/linux_syscalls.h
Normal file
391
repos/base-linux/src/platform/linux_syscalls.h
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* \brief Linux system-call bindings
|
||||
* \author Norman Feske
|
||||
* \date 2008-10-22
|
||||
*
|
||||
* This file is meant to be internally used by the framework. It is not public
|
||||
* interface.
|
||||
*
|
||||
* From within the framework libraries, we have to use the Linux syscall
|
||||
* interface directly rather than relying on convenient libc functions to be
|
||||
* able to link this part of the framework to a custom libc. Otherwise, we
|
||||
* would end up with very nasty cyclic dependencies when using framework
|
||||
* functions such as IPC from the libc back end.
|
||||
*
|
||||
* The Linux syscall interface looks different for 32bit and 64bit system, in
|
||||
* particular regarding the socket interface. On 32bit systems, all socket
|
||||
* operations are invoked via the 'socketcall' syscall. On 64bit systems, the
|
||||
* different socket functions have distinct syscalls.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2008-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM__LINUX_SYSCALLS_H_
|
||||
#define _PLATFORM__LINUX_SYSCALLS_H_
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1 /* needed to enable the definition of 'stat64' */
|
||||
#endif
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux/futex.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/snprintf.h>
|
||||
|
||||
|
||||
/***********************************
|
||||
** Low-level debugging utilities **
|
||||
***********************************/
|
||||
|
||||
extern "C" void wait_for_continue(void);
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
#define PRAW(fmt, ...) \
|
||||
do { \
|
||||
char str[128]; \
|
||||
Genode::snprintf(str, sizeof(str), \
|
||||
ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \
|
||||
raw_write_str(str); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*********************************************************
|
||||
** System-call bindings implemented in syscall library **
|
||||
*********************************************************/
|
||||
|
||||
extern "C" long lx_syscall(int number, ...);
|
||||
extern "C" int lx_clone(int (*fn)(void *), void *child_stack,
|
||||
int flags, void *arg);
|
||||
|
||||
|
||||
/*****************************************
|
||||
** General syscalls used by base-linux **
|
||||
*****************************************/
|
||||
|
||||
inline int lx_write(int fd, const void *buf, Genode::size_t count)
|
||||
{
|
||||
return lx_syscall(SYS_write, fd, buf, count);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_close(int fd)
|
||||
{
|
||||
return lx_syscall(SYS_close, fd);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_dup2(int fd, int to)
|
||||
{
|
||||
return lx_syscall(SYS_dup2, fd, to);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
** Functions used by the IPC framework **
|
||||
*****************************************/
|
||||
|
||||
#include <linux/net.h>
|
||||
|
||||
#ifdef SYS_socketcall
|
||||
|
||||
inline int lx_socketcall(int call, long *args)
|
||||
{
|
||||
int res = lx_syscall(SYS_socketcall, call, args);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
|
||||
{
|
||||
long args[4] = { domain, type, protocol, (long)sd };
|
||||
return lx_socketcall(SYS_SOCKETPAIR, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags)
|
||||
{
|
||||
long args[3] = { sockfd, (long)msg, flags };
|
||||
return lx_socketcall(SYS_SENDMSG, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
long args[3] = { sockfd, (long)msg, flags };
|
||||
return lx_socketcall(SYS_RECVMSG, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
long args[3] = { sockfd, (long)name, (long)namelen };
|
||||
return lx_socketcall(SYS_GETPEERNAME, args);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
|
||||
{
|
||||
return lx_syscall(SYS_socketpair, domain, type, protocol, (unsigned long)sd);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags)
|
||||
{
|
||||
return lx_syscall(SYS_sendmsg, sockfd, msg, flags);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
return lx_syscall(SYS_recvmsg, sockfd, msg, flags);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
return lx_syscall(SYS_getpeername, sockfd, name, namelen);
|
||||
}
|
||||
|
||||
/* TODO add missing socket system calls */
|
||||
|
||||
#endif /* SYS_socketcall */
|
||||
|
||||
|
||||
/*******************************************
|
||||
** Functions used by the process library **
|
||||
*******************************************/
|
||||
|
||||
inline void lx_exit(int status)
|
||||
{
|
||||
lx_syscall(SYS_exit, status);
|
||||
}
|
||||
|
||||
|
||||
inline void lx_exit_group(int status)
|
||||
{
|
||||
lx_syscall(SYS_exit_group, status);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************
|
||||
** Functions used by the env library and local rm session **
|
||||
************************************************************/
|
||||
|
||||
/* O_CLOEXEC is a GNU extension so we provide it here */
|
||||
enum { LX_O_CLOEXEC = 02000000 };
|
||||
|
||||
inline void *lx_mmap(void *start, Genode::size_t length, int prot, int flags,
|
||||
int fd, off_t offset)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return (void *)lx_syscall(SYS_mmap, start, length, prot, flags, fd, offset);
|
||||
#else
|
||||
return (void *)lx_syscall(SYS_mmap2, start, length, prot, flags, fd, offset/4096);
|
||||
#endif /* _LP64 */
|
||||
}
|
||||
|
||||
|
||||
inline int lx_munmap(void *addr, size_t length)
|
||||
{
|
||||
return lx_syscall(SYS_munmap, addr, length);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
** Functions used by thread lib and core's cancel-blocking mechanism **
|
||||
***********************************************************************/
|
||||
|
||||
enum {
|
||||
LX_SIGINT = 2, /* used by core to catch Control-C */
|
||||
LX_SIGUSR1 = 10, /* used for cancel-blocking mechanism */
|
||||
LX_SIGCHLD = 17, /* child process changed state, i.e., terminated */
|
||||
LX_SIGCANCEL = 32, /* accoring to glibc, this equals SIGRTMIN,
|
||||
used for killing threads */
|
||||
};
|
||||
|
||||
|
||||
struct kernel_sigaction
|
||||
{
|
||||
void (*handler)(int);
|
||||
unsigned long flags;
|
||||
void (*restorer)(void);
|
||||
sigset_t mask;
|
||||
};
|
||||
|
||||
|
||||
inline int lx_sigemptyset(sigset_t *set)
|
||||
{
|
||||
if (set == 0)
|
||||
return -1;
|
||||
Genode::memset(set, 0, sizeof(sigset_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _LP64
|
||||
extern "C" void lx_restore_rt (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Simplified binding for sigaction system call
|
||||
*/
|
||||
inline int lx_sigaction(int signum, void (*handler)(int))
|
||||
{
|
||||
struct kernel_sigaction act;
|
||||
act.handler = handler;
|
||||
|
||||
#ifdef _LP64
|
||||
/*
|
||||
* The SA_RESTORER flag is not officially documented, but used internally
|
||||
* by the glibc implementation of sigaction(). Without specifying this flag
|
||||
* tgkill() does not work on x86_64. The restorer function gets called
|
||||
* when leaving the signal handler and it should call the rt_sigreturn syscall.
|
||||
*/
|
||||
enum { SA_RESTORER = 0x04000000 };
|
||||
act.flags = SA_RESTORER;
|
||||
act.restorer = lx_restore_rt;;
|
||||
#else
|
||||
act.flags = 0;
|
||||
act.restorer = 0;
|
||||
#endif
|
||||
lx_sigemptyset(&act.mask);
|
||||
|
||||
return lx_syscall(SYS_rt_sigaction, signum, &act, 0UL, _NSIG/8);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send signal to thread
|
||||
*
|
||||
* This function is used by core to cancel blocking operations of
|
||||
* threads, and by the thread library to kill threads.
|
||||
*/
|
||||
inline int lx_tgkill(int pid, int tid, int signal)
|
||||
{
|
||||
return lx_syscall(SYS_tgkill, pid, tid, signal);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_create_thread(void (*entry)(), void *stack, void *arg)
|
||||
{
|
||||
int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
|
||||
| CLONE_THREAD | CLONE_SYSVSEM;
|
||||
|
||||
/*
|
||||
* The syscall binding for clone does not exist in the FreeBSD libc, which
|
||||
* we are using as libc for Genode. In glibc, clone is implemented as a
|
||||
* assembler binding without external libc references. Hence, we are safe
|
||||
* to rely on the glibc version of 'clone' here.
|
||||
*/
|
||||
return lx_clone((int (*)(void *))entry, stack, flags, arg);
|
||||
}
|
||||
|
||||
|
||||
inline pid_t lx_getpid() { return lx_syscall(SYS_getpid); }
|
||||
inline pid_t lx_gettid() { return lx_syscall(SYS_gettid); }
|
||||
inline uid_t lx_getuid() { return lx_syscall(SYS_getuid); }
|
||||
|
||||
|
||||
/************************************
|
||||
** Functions used by lock library **
|
||||
************************************/
|
||||
|
||||
struct timespec;
|
||||
|
||||
inline int lx_nanosleep(const struct timespec *req, struct timespec *rem)
|
||||
{
|
||||
return lx_syscall(SYS_nanosleep, req, rem);
|
||||
}
|
||||
|
||||
enum {
|
||||
LX_FUTEX_WAIT = FUTEX_WAIT,
|
||||
LX_FUTEX_WAKE = FUTEX_WAKE,
|
||||
};
|
||||
|
||||
inline int lx_futex(const int *uaddr, int op, int val)
|
||||
{
|
||||
return lx_syscall(SYS_futex, uaddr, op, val, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signal set corrsponding to glibc's 'sigset_t'
|
||||
*/
|
||||
class Lx_sigset
|
||||
{
|
||||
unsigned long int _value[_SIGSET_NWORDS];
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Lx_sigset() { }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param signum set specified entry of sigset
|
||||
*/
|
||||
Lx_sigset(int signum)
|
||||
{
|
||||
|
||||
for (unsigned i = 0; i < _SIGSET_NWORDS; i++)
|
||||
_value[i] = 0;
|
||||
|
||||
/*
|
||||
* Both '__sigword' and '__sigmask' are macros, defined in the
|
||||
* glibc header file 'bits/sigset.h' and not external functions.
|
||||
* Therefore we can use them here without getting into conflicts
|
||||
* with the linkage of another libc.
|
||||
*/
|
||||
_value[__sigword(signum)] = __sigmask(signum);
|
||||
}
|
||||
|
||||
bool is_set(int signum) {
|
||||
return _value[__sigword(signum)] && __sigmask(signum); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if signal is pending
|
||||
*
|
||||
* \return true if signal is pending
|
||||
*/
|
||||
inline bool lx_sigpending(int signum)
|
||||
{
|
||||
Lx_sigset sigset;
|
||||
lx_syscall(SYS_rt_sigpending, &sigset, _NSIG/8);
|
||||
return sigset.is_set(signum);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set signal mask state
|
||||
*
|
||||
* \param signum signal to mask or unmask
|
||||
* \param state mask state for the signal,
|
||||
* true enables the signal,
|
||||
* false blocks the signal
|
||||
*/
|
||||
inline bool lx_sigsetmask(int signum, bool state)
|
||||
{
|
||||
Lx_sigset old_sigmask, sigset(signum);
|
||||
lx_syscall(SYS_rt_sigprocmask, state ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old_sigmask, _NSIG/8);
|
||||
return old_sigmask.is_set(signum);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _PLATFORM__LINUX_SYSCALLS_H_ */
|
460
repos/base-linux/src/platform/lx_hybrid.cc
Normal file
460
repos/base-linux/src/platform/lx_hybrid.cc
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
* \brief Supplemental code for hybrid Genode/Linux programs
|
||||
* \author Norman Feske
|
||||
* \date 2011-09-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/crt0.h>
|
||||
#include <base/printf.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
enum { verbose_atexit = false };
|
||||
|
||||
|
||||
/**
|
||||
* Dummy for symbol that is normally provided by '_main.cc'
|
||||
*/
|
||||
int genode___cxa_atexit(void (*func)(void*), void *arg, void *dso)
|
||||
{
|
||||
if (verbose_atexit)
|
||||
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;
|
||||
|
||||
static void empty_signal_handler(int) { }
|
||||
|
||||
/*
|
||||
* 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()
|
||||
{
|
||||
lx_environ = environ;
|
||||
|
||||
/*
|
||||
* Set signal handler such that canceled system calls get not
|
||||
* transparently retried after a signal gets received.
|
||||
*/
|
||||
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy symbols to let generic tests programs (i.e., 'test-config_args') link
|
||||
* successfully. Please note that such programs are not expected to work when
|
||||
* built as hybrid Linux/Genode programs because when using the glibc startup
|
||||
* code, we cannot manipulate argv prior executing main. However, by defining
|
||||
* these symbols, we prevent the automated build bot from stumbling over such
|
||||
* binaries.
|
||||
*/
|
||||
char **genode_argv = 0;
|
||||
int genode_argc = 1;
|
||||
|
||||
|
||||
/************
|
||||
** Thread **
|
||||
************/
|
||||
|
||||
/*
|
||||
* For hybrid Linux/Genode programs, Genode's thread API is implemented via
|
||||
* POSIX threads.
|
||||
*
|
||||
* Hybrid Linux/Genode programs are linked against the glibc along with other
|
||||
* native Linux libraries. Such libraries may use the 'pthread' API to spawn
|
||||
* threads, which then may call Genode code. Vice versa, Genode threads may
|
||||
* interact with code of a native Linux libraries. Hence, both worlds Genode
|
||||
* and native Linux libraries should use the same underlying threading API.
|
||||
* Furthermore, using the pthread API is a precondition to satisfy the glibc's
|
||||
* assumption about thread-local storage, which is particularly important
|
||||
* for the correct thread-local handling of 'errno'. As another benefit of
|
||||
* using the pthread API over the normal Genode thread implementation, hybrid
|
||||
* Linux/Genode programs comply with the GNU debugger's expectations. Such
|
||||
* programs can be debugged as normal Linux programs.
|
||||
*
|
||||
* Genode's normal thread API for Linux was introduced to decouple Genode
|
||||
* from the glibc. This is especially important when using Genode's libc
|
||||
* Mixing both Genode's libc and glibc won't work.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/env.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/**
|
||||
* Return TLS key used to storing the thread meta data
|
||||
*/
|
||||
static pthread_key_t tls_key()
|
||||
{
|
||||
struct Tls_key
|
||||
{
|
||||
pthread_key_t key;
|
||||
|
||||
Tls_key()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
};
|
||||
|
||||
static Tls_key inst;
|
||||
return inst.key;
|
||||
}
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
struct Thread_meta_data
|
||||
{
|
||||
/**
|
||||
* Filled out by 'thread_start' function in the context of the new
|
||||
* thread
|
||||
*/
|
||||
Thread_base * const thread_base;
|
||||
|
||||
/**
|
||||
* POSIX thread handle
|
||||
*/
|
||||
pthread_t pt;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param thread associated 'Thread_base' object
|
||||
*/
|
||||
Thread_meta_data(Thread_base *thread) : thread_base(thread) { }
|
||||
|
||||
/**
|
||||
* Used to block the constructor until the new thread has initialized
|
||||
* 'id'
|
||||
*/
|
||||
virtual void wait_for_construction() = 0;
|
||||
virtual void constructed() = 0;
|
||||
|
||||
/**
|
||||
* Used to block the new thread until 'start' is called
|
||||
*/
|
||||
virtual void wait_for_start() = 0;
|
||||
virtual void started() = 0;
|
||||
|
||||
/**
|
||||
* Used to block the 'join()' function until the 'entry()' is done
|
||||
*/
|
||||
virtual void wait_for_join() = 0;
|
||||
virtual void joined() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Thread meta data for a thread created by Genode
|
||||
*/
|
||||
class Thread_meta_data_created : public Thread_meta_data
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Lock with the initial state set to LOCKED
|
||||
*/
|
||||
struct Barrier : Lock { Barrier() : Lock(Lock::LOCKED) { } };
|
||||
|
||||
/**
|
||||
* Used to block the constructor until the new thread has initialized
|
||||
* 'id'
|
||||
*/
|
||||
Barrier _construct_lock;
|
||||
|
||||
/**
|
||||
* Used to block the new thread until 'start' is called
|
||||
*/
|
||||
Barrier _start_lock;
|
||||
|
||||
/**
|
||||
* Used to block the 'join()' function until the 'entry()' is done
|
||||
*/
|
||||
Barrier _join_lock;
|
||||
|
||||
public:
|
||||
|
||||
Thread_meta_data_created(Thread_base *thread) : Thread_meta_data(thread) { }
|
||||
|
||||
void wait_for_construction()
|
||||
{
|
||||
_construct_lock.lock();
|
||||
}
|
||||
|
||||
void constructed()
|
||||
{
|
||||
_construct_lock.unlock();
|
||||
}
|
||||
|
||||
void wait_for_start()
|
||||
{
|
||||
_start_lock.lock();
|
||||
}
|
||||
|
||||
void started()
|
||||
{
|
||||
_start_lock.unlock();
|
||||
}
|
||||
|
||||
void wait_for_join()
|
||||
{
|
||||
_join_lock.lock();
|
||||
}
|
||||
|
||||
void joined()
|
||||
{
|
||||
_join_lock.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Thread meta data for an adopted thread
|
||||
*/
|
||||
class Thread_meta_data_adopted : public Thread_meta_data
|
||||
{
|
||||
public:
|
||||
|
||||
Thread_meta_data_adopted(Thread_base *thread) : Thread_meta_data(thread) { }
|
||||
|
||||
void wait_for_construction()
|
||||
{
|
||||
PERR("wait_for_construction() called for an adopted thread");
|
||||
}
|
||||
|
||||
void constructed()
|
||||
{
|
||||
PERR("constructed() called for an adopted thread");
|
||||
}
|
||||
|
||||
void wait_for_start()
|
||||
{
|
||||
PERR("wait_for_start() called for an adopted thread");
|
||||
}
|
||||
|
||||
void started()
|
||||
{
|
||||
PERR("started() called for an adopted thread");
|
||||
}
|
||||
|
||||
void wait_for_join()
|
||||
{
|
||||
PERR("wait_for_join() called for an adopted thread");
|
||||
}
|
||||
|
||||
void joined()
|
||||
{
|
||||
PERR("joined() called for an adopted thread");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return Linux-specific extension of the Env::CPU session interface
|
||||
*/
|
||||
Linux_cpu_session *cpu_session(Cpu_session * cpu_session)
|
||||
{
|
||||
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(cpu_session);
|
||||
|
||||
if (!cpu) {
|
||||
PERR("could not obtain Linux extension to CPU session interface");
|
||||
struct Could_not_access_linux_cpu_session { };
|
||||
throw Could_not_access_linux_cpu_session();
|
||||
}
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
|
||||
static void adopt_thread(Thread_meta_data *meta_data)
|
||||
{
|
||||
/*
|
||||
* Set signal handler such that canceled system calls get not
|
||||
* transparently retried after a signal gets received.
|
||||
*/
|
||||
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
||||
|
||||
/*
|
||||
* Prevent children from becoming zombies. (SIG_IGN = 1)
|
||||
*/
|
||||
lx_sigaction(LX_SIGCHLD, (void (*)(int))1);
|
||||
|
||||
/* assign 'Thread_meta_data' pointer to TLS entry */
|
||||
pthread_setspecific(tls_key(), meta_data);
|
||||
|
||||
/* enable immediate cancellation when calling 'pthread_cancel' */
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
|
||||
/*
|
||||
* Initialize thread meta data
|
||||
*/
|
||||
Native_thread &native_thread = meta_data->thread_base->tid();
|
||||
native_thread.tid = lx_gettid();
|
||||
native_thread.pid = lx_getpid();
|
||||
}
|
||||
|
||||
|
||||
static void *thread_start(void *arg)
|
||||
{
|
||||
Thread_meta_data *meta_data = (Thread_meta_data *)arg;
|
||||
|
||||
adopt_thread(meta_data);
|
||||
|
||||
/* unblock 'Thread_base' constructor */
|
||||
meta_data->constructed();
|
||||
|
||||
/* block until the 'Thread_base::start' gets called */
|
||||
meta_data->wait_for_start();
|
||||
|
||||
Thread_base::myself()->entry();
|
||||
|
||||
meta_data->joined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void *malloc(::size_t size);
|
||||
|
||||
|
||||
Thread_base *Thread_base::myself()
|
||||
{
|
||||
void * const tls = pthread_getspecific(tls_key());
|
||||
|
||||
if (tls != 0)
|
||||
return ((Thread_meta_data *)tls)->thread_base;
|
||||
|
||||
bool const is_main_thread = (lx_getpid() == lx_gettid());
|
||||
if (is_main_thread)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The function was called from a thread created by other means than
|
||||
* Genode's thread API. This may happen if a native Linux library creates
|
||||
* threads via the pthread library. If such a thread calls Genode code,
|
||||
* which then tries to perform IPC, the program fails because there exists
|
||||
* no 'Thread_base' object. We recover from this unfortunate situation by
|
||||
* creating a dummy 'Thread_base' object and associate it with the calling
|
||||
* thread.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create dummy 'Thread_base' object but suppress the execution of its
|
||||
* constructor. If we called the constructor, we would create a new Genode
|
||||
* thread, which is not what we want. For the allocation, we use glibc
|
||||
* malloc because 'Genode::env()->heap()->alloc()' uses IPC.
|
||||
*
|
||||
* XXX Both the 'Thread_base' and 'Threadm_meta_data' objects are never
|
||||
* freed.
|
||||
*/
|
||||
Thread_base *thread = (Thread_base *)malloc(sizeof(Thread_base));
|
||||
memset(thread, 0, sizeof(*thread));
|
||||
Thread_meta_data *meta_data = new Thread_meta_data_adopted(thread);
|
||||
|
||||
/*
|
||||
* Initialize 'Thread_base::_tid' using the default constructor of
|
||||
* 'Native_thread'. This marks the client and server sockets as
|
||||
* uninitialized and prompts the IPC framework to create those as needed.
|
||||
*/
|
||||
meta_data->thread_base->tid() = Native_thread();
|
||||
adopt_thread(meta_data);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::start()
|
||||
{
|
||||
/*
|
||||
* Unblock thread that is supposed to slumber in 'thread_start'.
|
||||
*/
|
||||
_tid.meta_data->started();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::join()
|
||||
{
|
||||
_tid.meta_data->wait_for_join();
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(const char *name, size_t stack_size, Type type,
|
||||
Cpu_session * cpu_sess)
|
||||
: _cpu_session(cpu_sess)
|
||||
{
|
||||
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
|
||||
|
||||
int const ret = pthread_create(&_tid.meta_data->pt, 0, thread_start,
|
||||
_tid.meta_data);
|
||||
if (ret) {
|
||||
PERR("pthread_create failed (returned %d, errno=%d)",
|
||||
ret, errno);
|
||||
destroy(env()->heap(), _tid.meta_data);
|
||||
throw Context_alloc_failed();
|
||||
}
|
||||
|
||||
_tid.meta_data->wait_for_construction();
|
||||
|
||||
Linux_cpu_session *cpu = cpu_session(_cpu_session);
|
||||
|
||||
_thread_cap = cpu->create_thread(name);
|
||||
cpu->thread_id(_thread_cap, _tid.pid, _tid.tid);
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
|
||||
: Thread_base(name, stack_size, type, env()->cpu_session()) { }
|
||||
|
||||
void Thread_base::cancel_blocking()
|
||||
{
|
||||
/*
|
||||
* XXX implement interaction with CPU session
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
Thread_base::~Thread_base()
|
||||
{
|
||||
bool const needs_join = (pthread_cancel(_tid.meta_data->pt) == 0);
|
||||
|
||||
if (needs_join) {
|
||||
int const ret = pthread_join(_tid.meta_data->pt, 0);
|
||||
if (ret)
|
||||
PWRN("pthread_join unexpectedly returned with %d (errno=%d)",
|
||||
ret, errno);
|
||||
}
|
||||
|
||||
Thread_meta_data_created *meta_data =
|
||||
dynamic_cast<Thread_meta_data_created *>(_tid.meta_data);
|
||||
|
||||
if (meta_data)
|
||||
destroy(env()->heap(), meta_data);
|
||||
|
||||
_tid.meta_data = 0;
|
||||
|
||||
/* inform core about the killed thread */
|
||||
cpu_session(_cpu_session)->kill_thread(_thread_cap);
|
||||
}
|
108
repos/base-linux/src/platform/x86_32/lx_clone.S
Normal file
108
repos/base-linux/src/platform/x86_32/lx_clone.S
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* \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;
|
||||
xorl %ebp,%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
|
||||
|
83
repos/base-linux/src/platform/x86_32/lx_syscall.S
Normal file
83
repos/base-linux/src/platform/x86_32/lx_syscall.S
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* \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
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
74
repos/base-linux/src/platform/x86_64/lx_clone.S
Normal file
74
repos/base-linux/src/platform/x86_64/lx_clone.S
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* \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
|
||||
|
||||
/* Align the new stack pointer to 16 bytes. */
|
||||
andq $0xfffffffffffffff0, %rsi
|
||||
|
||||
/* 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. */
|
||||
xorq %rbp, %rbp
|
||||
|
||||
/* 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
|
||||
|
23
repos/base-linux/src/platform/x86_64/lx_restore_rt.S
Normal file
23
repos/base-linux/src/platform/x86_64/lx_restore_rt.S
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* \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
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
36
repos/base-linux/src/platform/x86_64/lx_syscall.S
Normal file
36
repos/base-linux/src/platform/x86_64/lx_syscall.S
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* \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. */
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
52
repos/base-linux/src/test/lx_hybrid_ctors/main.cc
Normal file
52
repos/base-linux/src/test/lx_hybrid_ctors/main.cc
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* \brief Test if global static constructors in hybrid applications get called
|
||||
* \author Christian Prochaska
|
||||
* \date 2011-11-24
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
|
||||
#include <base/printf.h>
|
||||
|
||||
#include "testlib.h"
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
struct Testapp_testclass
|
||||
{
|
||||
Testapp_testclass()
|
||||
{
|
||||
Genode::printf("Global static constructor of Genode application called\n");
|
||||
}
|
||||
|
||||
void dummy() { }
|
||||
};
|
||||
|
||||
|
||||
extern Testlib_testclass testlib_testobject;
|
||||
|
||||
Testapp_testclass testapp_testobject;
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("--- lx_hybrid global static constructor test ---\n");
|
||||
|
||||
/*
|
||||
* Call a dummy function on each test object to make sure that the
|
||||
objects don't get optimized out.
|
||||
*/
|
||||
testlib_testobject.dummy();
|
||||
testapp_testobject.dummy();
|
||||
|
||||
printf("--- returning from main ---\n");
|
||||
|
||||
return 0;
|
||||
}
|
22
repos/base-linux/src/test/lx_hybrid_ctors/target.mk
Normal file
22
repos/base-linux/src/test/lx_hybrid_ctors/target.mk
Normal file
@ -0,0 +1,22 @@
|
||||
TARGET = test-lx_hybrid_ctors
|
||||
SRC_CC = main.cc
|
||||
LIBS = lx_hybrid
|
||||
|
||||
TESTLIB_SO = libtestlib.so
|
||||
TESTLIB_SRC_CC = testlib.cc
|
||||
|
||||
EXT_OBJECTS += $(BUILD_BASE_DIR)/test/lx_hybrid_ctors/$(TESTLIB_SO)
|
||||
|
||||
$(TARGET): $(TESTLIB_SO)
|
||||
|
||||
$(TESTLIB_SO): $(TESTLIB_SRC_CC)
|
||||
$(MSG_BUILD)$(TESTLIB_SO)
|
||||
$(VERBOSE)g++ $(CC_MARCH) -fPIC -c $^
|
||||
$(VERBOSE)g++ $(CC_MARCH) -shared -o $@ $(notdir $(^:.cc=.o))
|
||||
|
||||
clean_libtestlib:
|
||||
$(VERBOSE)rm -f $(TESTLIB_SO) $(TESTLIB_SRC_CC:.cc=.o)
|
||||
|
||||
clean: clean_libtestlib
|
||||
|
||||
vpath testlib.cc $(PRG_DIR)
|
28
repos/base-linux/src/test/lx_hybrid_ctors/testlib.cc
Normal file
28
repos/base-linux/src/test/lx_hybrid_ctors/testlib.cc
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* \brief Test if global static constructors in host shared libs get called
|
||||
* \author Christian Prochaska
|
||||
* \date 2011-11-24
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "testlib.h"
|
||||
|
||||
|
||||
Testlib_testclass::Testlib_testclass()
|
||||
{
|
||||
printf("[init -> test-lx_hybrid_ctors] Global static constructor of host library called.\n");
|
||||
}
|
||||
|
||||
|
||||
void Testlib_testclass::dummy() { }
|
||||
|
||||
|
||||
Testlib_testclass testlib_testobject;
|
18
repos/base-linux/src/test/lx_hybrid_ctors/testlib.h
Normal file
18
repos/base-linux/src/test/lx_hybrid_ctors/testlib.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* \brief Test if global static constructors in host shared libs get called
|
||||
* \author Christian Prochaska
|
||||
* \date 2011-11-24
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
struct Testlib_testclass
|
||||
{
|
||||
Testlib_testclass();
|
||||
void dummy();
|
||||
};
|
68
repos/base-linux/src/test/lx_hybrid_errno/main.cc
Normal file
68
repos/base-linux/src/test/lx_hybrid_errno/main.cc
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* \brief Test for thread-local errno handling of hybrid Linux/Genode programs
|
||||
* \author Norman Feske
|
||||
* \date 2011-12-05
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
enum { STACK_SIZE = 4096 };
|
||||
|
||||
struct Thread : Genode::Thread<STACK_SIZE>
|
||||
{
|
||||
Genode::Lock &_barrier;
|
||||
|
||||
Thread(Genode::Lock &barrier)
|
||||
: Genode::Thread<STACK_SIZE>("stat"), _barrier(barrier) { start(); }
|
||||
|
||||
void entry()
|
||||
{
|
||||
/*
|
||||
* Stat syscall should return with errno ENOENT
|
||||
*/
|
||||
struct stat buf;
|
||||
int ret = stat("", &buf);
|
||||
|
||||
Genode::printf("thread: stat returned %d, errno=%d\n", ret, errno);
|
||||
|
||||
/*
|
||||
* Let main thread procees
|
||||
*/
|
||||
_barrier.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
Genode::printf("--- thread-local errno test ---\n");
|
||||
|
||||
static Genode::Lock barrier(Genode::Lock::LOCKED);
|
||||
|
||||
int const orig_errno = errno;
|
||||
|
||||
Genode::printf("main: before thread creation, errno=%d\n", orig_errno);
|
||||
|
||||
/* create thread, which modifies its thread-local errno value */
|
||||
static Thread thread(barrier);
|
||||
|
||||
/* block until the thread performed a 'stat' syscall */
|
||||
barrier.lock();
|
||||
|
||||
Genode::printf("main: after thread completed, errno=%d\n", errno);
|
||||
|
||||
if (orig_errno != errno) {
|
||||
PERR("unexpected change of main thread's errno value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Genode::printf("--- finished thread-local errno test ---\n");
|
||||
return 0;
|
||||
}
|
3
repos/base-linux/src/test/lx_hybrid_errno/target.mk
Normal file
3
repos/base-linux/src/test/lx_hybrid_errno/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-lx_hybrid_errno
|
||||
SRC_CC = main.c
|
||||
LIBS = lx_hybrid
|
37
repos/base-linux/src/test/lx_hybrid_exception/main.cc
Normal file
37
repos/base-linux/src/test/lx_hybrid_exception/main.cc
Normal 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-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
3
repos/base-linux/src/test/lx_hybrid_exception/target.mk
Normal file
3
repos/base-linux/src/test/lx_hybrid_exception/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-lx_hybrid_exception
|
||||
SRC_CC = main.cc
|
||||
LIBS = lx_hybrid
|
62
repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc
Normal file
62
repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* \brief Test for performing IPC from a pthread created outside of Genode
|
||||
* \author Norman Feske
|
||||
* \date 2011-12-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
static Genode::Lock *main_wait_lock()
|
||||
{
|
||||
static Genode::Lock inst(Genode::Lock::LOCKED);
|
||||
return &inst;
|
||||
}
|
||||
|
||||
|
||||
static void *pthread_entry(void *)
|
||||
{
|
||||
PINF("first message");
|
||||
|
||||
/*
|
||||
* Without the lazy initialization of 'Thread_base' objects for threads
|
||||
* created w/o Genode's Thread API, the printing of the first message will
|
||||
* never return because the IPC reply could not be delivered.
|
||||
*
|
||||
* With the on-demand creation of 'Thread_base' objects, the second message
|
||||
* will appear in the LOG output.
|
||||
*/
|
||||
|
||||
PINF("second message");
|
||||
|
||||
main_wait_lock()->unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
Genode::printf("--- pthread IPC test ---\n");
|
||||
|
||||
/* create thread w/o Genode's thread API */
|
||||
pthread_t pth;
|
||||
pthread_create(&pth, 0, pthread_entry, 0);
|
||||
|
||||
/* wait until 'pthread_entry' finished */
|
||||
main_wait_lock()->lock();
|
||||
|
||||
Genode::printf("--- finished pthread IPC test ---\n");
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
TARGET = test-lx_hybrid_pthread_ipc
|
||||
SRC_CC = main.c
|
||||
LIBS = lx_hybrid
|
10
repos/base-linux/src/test/lx_rmap/dynamic/target.mk
Normal file
10
repos/base-linux/src/test/lx_rmap/dynamic/target.mk
Normal file
@ -0,0 +1,10 @@
|
||||
# dynamic variant is not supported in hybrid mode
|
||||
ifeq ($(filter-out $(SPECS),always_hybrid),)
|
||||
REQUIRES = plain_linux
|
||||
endif
|
||||
|
||||
TARGET = test-lx_rmap_dynamic
|
||||
SRC_CC = main.cc
|
||||
LIBS = base ld
|
||||
|
||||
vpath main.cc $(PRG_DIR)/..
|
105
repos/base-linux/src/test/lx_rmap/main.cc
Normal file
105
repos/base-linux/src/test/lx_rmap/main.cc
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* \brief Linux region-map test
|
||||
* \author Christian Helmuth
|
||||
* \date 2013-09-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
#include <base/crt0.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/thread.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <rm_session/connection.h>
|
||||
|
||||
|
||||
|
||||
static void blob() __attribute__((used));
|
||||
static void blob()
|
||||
{
|
||||
asm volatile (
|
||||
".balign 4096, -1\n"
|
||||
"blob_beg:\n"
|
||||
".space 16*4096, -2\n"
|
||||
"blob_end:\n"
|
||||
".global blob_beg\n"
|
||||
".global blob_end\n"
|
||||
: : : );
|
||||
}
|
||||
|
||||
|
||||
extern unsigned long blob_beg;
|
||||
extern unsigned long blob_end;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* activate for early printf in Rm_session_mmap::attach() etc. */
|
||||
if (0) Thread_base::trace("FOO");
|
||||
|
||||
/* induce initial heap expansion to remove RM noise */
|
||||
if (1) {
|
||||
void *addr(env()->heap()->alloc(0x100000));
|
||||
env()->heap()->free(addr, 0);
|
||||
}
|
||||
|
||||
addr_t beg((addr_t)&blob_beg);
|
||||
addr_t end(align_addr((addr_t)&blob_end, 12));
|
||||
|
||||
size_t size(end - beg);
|
||||
|
||||
PLOG("blob region region [%016lx,%016lx) size=%zx", beg, end, size);
|
||||
|
||||
/* RAM dataspace attachment overlapping binary */
|
||||
try {
|
||||
Ram_dataspace_capability ds(env()->ram_session()->alloc(size));
|
||||
|
||||
PLOG("before RAM dataspace attach");
|
||||
env()->rm_session()->attach_at(ds, beg);
|
||||
PERR("after RAM dataspace attach -- ERROR");
|
||||
} catch (Rm_session::Region_conflict) {
|
||||
PLOG("OK caught Region_conflict exception");
|
||||
}
|
||||
|
||||
/* empty managed dataspace overlapping binary */
|
||||
try {
|
||||
Rm_connection rm(0, size);
|
||||
Dataspace_capability ds(rm.dataspace());
|
||||
|
||||
PLOG("before sub-RM dataspace attach");
|
||||
env()->rm_session()->attach_at(ds, beg);
|
||||
PERR("after sub-RM dataspace attach -- ERROR");
|
||||
} catch (Rm_session::Region_conflict) {
|
||||
PLOG("OK caught Region_conflict exception");
|
||||
}
|
||||
|
||||
/* sparsely populated managed dataspace in free VM area */
|
||||
try {
|
||||
Rm_connection rm(0, 0x100000);
|
||||
|
||||
rm.attach_at(env()->ram_session()->alloc(0x1000), 0x1000);
|
||||
|
||||
Dataspace_capability ds(rm.dataspace());
|
||||
|
||||
PLOG("before populated sub-RM dataspace attach");
|
||||
char *addr = (char *)env()->rm_session()->attach(ds) + 0x1000;
|
||||
PLOG("after populated sub-RM dataspace attach / before touch");
|
||||
char const val = *addr;
|
||||
*addr = 0x55;
|
||||
PLOG("after touch (%x/%x)", val, *addr);
|
||||
} catch (Rm_session::Region_conflict) {
|
||||
PLOG("OK caught Region_conflict exception -- ERROR");
|
||||
}
|
||||
|
||||
sleep_forever();
|
||||
}
|
5
repos/base-linux/src/test/lx_rmap/static/target.mk
Normal file
5
repos/base-linux/src/test/lx_rmap/static/target.mk
Normal file
@ -0,0 +1,5 @@
|
||||
TARGET = test-lx_rmap_static
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
||||
|
||||
vpath main.cc $(PRG_DIR)/..
|
53
repos/base-linux/src/test/rm_session_mmap/main.cc
Normal file
53
repos/base-linux/src/test/rm_session_mmap/main.cc
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* \brief Linux: Test bug in rm_session_mmap.cc
|
||||
* \author Christian Helmuth
|
||||
* \date 2012-12-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <ram_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
|
||||
static void test_linux_rmmap_bug()
|
||||
{
|
||||
enum { QUOTA = 1*1024*1024, CHUNK = 0x1000, ROUNDS = 0x10 };
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
PLOG("line: %d", __LINE__);
|
||||
Ram_connection ram;
|
||||
|
||||
#if 1 /* transfer quota */
|
||||
PLOG("line: %d", __LINE__);
|
||||
ram.ref_account(env()->ram_session_cap());
|
||||
env()->ram_session()->transfer_quota(ram.cap(), QUOTA);
|
||||
#endif
|
||||
|
||||
PLOG("line: %d", __LINE__);
|
||||
for (unsigned i = 0; i < ROUNDS; ++i) {
|
||||
Ram_dataspace_capability ds(ram.alloc(CHUNK));
|
||||
PLOG("%d of %d pages allocated", (i + 1), ROUNDS);
|
||||
}
|
||||
|
||||
PLOG("Done.");
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Genode::printf("--- test-rm_session_mmap started ---\n");
|
||||
|
||||
// Timer::Connection timer;
|
||||
// timer.msleep(1000);
|
||||
|
||||
test_linux_rmmap_bug();
|
||||
}
|
3
repos/base-linux/src/test/rm_session_mmap/target.mk
Normal file
3
repos/base-linux/src/test/rm_session_mmap/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-rm_session_mmap
|
||||
LIBS = base
|
||||
SRC_CC = main.cc
|
22
repos/base-linux/src/test/sub_rm/config.h
Normal file
22
repos/base-linux/src/test/sub_rm/config.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* \brief Linux-specific policy for sub_rm test
|
||||
* \author Norman Feske
|
||||
* \date 2011-11-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 };
|
||||
|
Reference in New Issue
Block a user