Fiasco.OC: introduce Cap_index (fixes #149, #112)

This commit introduces a Cap_index class for Fiasco.OC's capabilities.
A Cap_index is a combination of the global capability id, that is used by Genode
to correctly identify a kernel-object, and a corresponding entry in a
protection-domain's (kernel-)capability-space. The cap-indices are non-copyable,
unique objects, that are held in a Cap_map. The Cap_map is used to re-find
capabilities already present in the protection-domain, when a capability is
received via IPC. The retrieval of capabilities effectively fixes issue #112,
meaning the waste of capability-space entries.
Because Cap_index objects are non-copyable (their address indicates the position
in the capability-space of the pd), they are inappropriate to use as
Native_capability. Therefore, Native_capability is implemented as a reference
to Cap_index objects. This design seems to be a good pre-condition to implement
smart-pointers for entries in the capability-space, and thereby closing existing
leaks (please refer to issue #32).

Cap_index, Cap_map, and the allocator for Cap_index objects are designed in a way,
that it should be relatively easy to apply the same concept to NOVA also. By now,
these classes are located in the `base-foc` repository, but they intentionally
contain no Fiasco.OC specific elements.

The previously explained changes had extensive impact on the whole Fiasco.OC
platform implementation, due to various dependencies. The following things had to
be changed:

* The Thread object's startup and destruction routine is re-arranged, to
  enable another thread (that calls the Thread destructor) gaining the
  capability id of the thread's gate to remove it from the Cap_map, the
  thread's UTCB had to be made available to the caller, because there
  is the current location of that id. After having the UTCB available
  in the Thread object for that reason, the whole thread bootstrapping
  could be simplified.
* In the course of changing the Native_capability's semantic, a new Cap_mapping
  class was introduced in core, that facilitates the establishment and
  destruction of capability mappings between core and it's client's, especially
  mappings related to Platform_thread and Platform_task, that are relevant to
  task and thread creation and destruction. Thereby, the destruction of
  threads had to be reworked, which effectively removed a bug (issue #149)
  where some threads weren't destroyed properly.
* In the quick fix for issue #112, something similar to the Cap_map was
  introduced available in all processes. Moreover, some kind of a capability
  map already existed in core, to handle cap-session request properly. The
  introduction of the Cap_map unified both structures, so that the
  cap-session component code in core had to be reworked too.
* The platform initialization code had to be changed sligthly due to the
  changes in Native_capability
* The vcpu initialization in the L4Linux support library had to be adapted
  according to the already mentioned changes in the Thread object's bootstrap
  code.
This commit is contained in:
Stefan Kalkowski 2012-03-15 12:41:24 +01:00 committed by Norman Feske
parent 12e1ae9d72
commit d287b9d893
47 changed files with 1225 additions and 934 deletions

View File

@ -0,0 +1,127 @@
/*
* \brief Capability index allocator for Fiasco.OC.
* \author Stefan Kalkowski
* \date 2012-02-16
*/
/*
* Copyright (C) 2012 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 _INCLUDE__BASE__CAP_ALLOC_H_
#define _INCLUDE__BASE__CAP_ALLOC_H_
#include <base/cap_map.h>
#include <base/native_types.h>
namespace Genode {
/**
* Cap_index_allocator_tpl implements the Cap_index_allocator for Fiasco.OC.
*
* It's designed as a template because we need two distinguished versions
* for core and non-core processes with respect to dimensioning. Moreover,
* core needs more information within a Cap_index object, than the base
* class provides.
*
* \param T Cap_index specialization to use
* \param SZ size of Cap_index array used by the allocator
*/
template <typename T, unsigned SZ>
class Cap_index_allocator_tpl : public Cap_index_allocator
{
private:
Spin_lock _lock; /* used very early in initialization,
where normal lock isn't feasible */
enum {
/* everything above START_IDX is managed by core */
START_IDX = Fiasco::USER_BASE_CAP >> Fiasco::L4_CAP_SHIFT
};
protected:
unsigned char _data[SZ*sizeof(T)];
T* _indices;
public:
Cap_index_allocator_tpl() : _indices(reinterpret_cast<T*>(&_data)) {
memset(&_data, 0, sizeof(_data)); }
/***********************************
** Cap_index_allocator interface **
***********************************/
Cap_index* alloc(size_t cnt)
{
Lock_guard<Spin_lock> guard(_lock);
/*
* iterate through array and find unused, consecutive entries
*/
for (unsigned i = START_IDX, j = 0; (i+cnt) < SZ; i+=j+1, j=0) {
for (; j < cnt; j++)
if (_indices[i+j].used())
break;
/* if we found a fitting hole, initialize the objects */
if (j == cnt) {
for (j = 0; j < cnt; j++)
new (&_indices[i+j]) T();
return &_indices[i];
}
}
return 0;
}
Cap_index* alloc(addr_t addr, size_t cnt)
{
Lock_guard<Spin_lock> guard(_lock);
/*
* construct the Cap_index pointer from the given
* address in capability space
*/
T* obj = reinterpret_cast<T*>(kcap_to_idx(addr));
T* ret = obj;
/* check whether the consecutive entries are in range and unused */
for (size_t i = 0; i < cnt; i++, obj++) {
if (obj < &_indices[0] || obj >= &_indices[SZ])
throw Index_out_of_bounds();
if (obj->used())
throw Region_conflict();
new (obj) T();
}
return ret;
}
void free(Cap_index* idx, size_t cnt)
{
Lock_guard<Spin_lock> guard(_lock);
T* obj = static_cast<T*>(idx);
for (size_t i = 0; i < cnt; obj++, i++) {
/* range check given pointer address */
if (obj < &_indices[0] || obj >= &_indices[SZ])
throw Index_out_of_bounds();
delete obj;
}
}
addr_t idx_to_kcap(Cap_index *idx) {
return ((T*)idx - &_indices[0]) << Fiasco::L4_CAP_SHIFT;
}
Cap_index* kcap_to_idx(addr_t kcap) {
return &_indices[kcap >> Fiasco::L4_CAP_SHIFT]; }
};
}
#endif /* _INCLUDE__BASE__CAP_ALLOC_H_ */

View File

@ -0,0 +1,252 @@
/*
* \brief Mapping of Genode's capability names to kernel capabilities.
* \author Stefan Kalkowski
* \date 2012-02-16
*
* Although kernels like Fiasco.OC and NOVA provide capability mechanisms
* to us, which should prevent the usage of global names, there is no
* efficient way to retrieve a capability a process owns, when it gets the
* same capability delivered again via IPC from another thread. But in some
* use-cases in Genode this is essential (e.g. parent getting a close-session
* request from a child). Moreover, we waste a lot of slots in the
* capability-space of the process for one and the same kernel-object.
* That's why we introduce a map of Genode's global capability names to the
* process-local addresses in the capability-space.
*
* TODO: should be moved to the generic part of the framework, and used by
* NOVA too.
*/
/*
* Copyright (C) 2012 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 _INCLUDE__BASE__CAP_MAP_H_
#define _INCLUDE__BASE__CAP_MAP_H_
/* Genode includes */
#include <base/exception.h>
#include <base/stdint.h>
#include <base/lock_guard.h>
#include <util/avl_tree.h>
#include <util/noncopyable.h>
#include <util/string.h>
namespace Genode
{
/**
* A Cap_index represents a single mapping of the global capability id
* to the address in the local capability space.
*
* The address of the Cap_index determines the location in the
* (platform-specific) capability space of the process. Therefore it
* shouldn't be copied around, but only referenced by
* e.g. Native_capability.
*/
class Cap_index : public Avl_node<Cap_index>,
Noncopyable
{
private:
enum { INVALID_ID = -1, UNUSED = 0 };
uint16_t _id; /* global capability id */
public:
Cap_index() : _id(INVALID_ID) { }
bool valid() const { return _id != INVALID_ID; }
bool used() const { return _id != UNUSED; }
uint16_t id() const { return _id; }
void id(uint16_t id) { _id = id; }
addr_t kcap();
void* operator new (size_t size, Cap_index* idx) { return idx; }
void operator delete (void* idx) { memset(idx, 0, sizeof(Cap_index)); }
/************************
** Avl node interface **
************************/
bool higher(Cap_index *n);
Cap_index *find_by_id(uint16_t id);
};
/**
* Allocator for Cap_index objects.
*
* This is just an interface, as the real allocator has to be
* implemented platform-specific.
*/
class Cap_index_allocator: Noncopyable
{
public:
class Index_out_of_bounds : public Exception { };
class Region_conflict : public Exception { };
virtual ~Cap_index_allocator() {}
/**
* Allocate a range of Cap_index objects
*
* \param cnt number of objects to allocate
* \return pointer to first allocated object, or zero if
* out of entries
*/
virtual Cap_index* alloc(size_t cnt) = 0;
/**
* Allocate a range of Cap_index objects at a specific
* point in the capability space
*
* \param kcap address in capability space
* \param cnt number of objects to allocate
* \throw Index_out_of_bounds if address is out of scope
* \throw Region_conflict if capability space entry is used
* \return pointer to first allocated object,
* or zero if out of entries
*/
virtual Cap_index* alloc(addr_t kcap, size_t cnt) = 0;
/**
* Free a range of Cap_index objects
*
* \param idx pointer to first object in range
* \param cnt number of objects to free
* \throw Index_out_of_bounds if address is out of scope
*/
virtual void free(Cap_index *idx, size_t cnt) = 0;
/**
* Get the Cap_index object's address in capability space
*
* \param idx pointer to the Cap_index object in question
*/
virtual addr_t idx_to_kcap(Cap_index *idx) = 0;
/**
* Get the Cap_index object of a specific location
* in the capability space
*
* \param kcap the address in the capability space
*/
virtual Cap_index* kcap_to_idx(addr_t kcap) = 0;
};
/**
* Get the global Cap_index_allocator of the process.
*/
Cap_index_allocator *cap_idx_alloc();
/**
* Low-level spin-lock to protect Cap_index_allocator and the Cap_map
*
* We cannot use a normal Genode lock because this lock is used by code
* executed prior the initialization of Genode
*/
class Spin_lock
{
private:
volatile int _spinlock;
public:
/**
* Constructor
*/
Spin_lock();
void lock();
void unlock();
/**
* Lock guard
*/
typedef Genode::Lock_guard<Spin_lock> Guard;
};
class Native_capability;
/**
* The Capability_map is an AVL-tree of Cap_index objects that can be
* found via the global capability id
*
* It is used to re-find capabilities whenever a capability gets
* transfered to a process, so that we can re-use an existing one
* to save entries in the capability space, and prevent leaks of
* them.
*/
class Capability_map : Noncopyable
{
private:
Avl_tree<Cap_index> _tree;
Spin_lock _lock;
public:
/**
* Find an existing Cap_index via a capability id
*
* \param id the global capability id
* \return pointer of Cap_index when found, otherwise zero
*/
Cap_index* find(int id);
/**
* Create and insert a new Cap_index with a specific capability id
*
* Allocation of the Cap_index is done via the global
* Cap_index_allocator, which might throw exceptions that aren't
* caught by this method
*
* \param id the global capability id
* \return pointer to the new Cap_index object, or zero
* when allocation failed
*/
Cap_index* insert(int id);
/**
* Create and insert a new Cap_index with a specific capability id,
* and location in capability space
*
* Allocation of the Cap_index is done via the global
* Cap_index_allocator, which might throw exceptions that aren't
* caught by this method
*
* \param id the global capability id
* \param kcap address in capability space
* \return pointer to the new Cap_index object, or zero
* when allocation failed
*/
Cap_index* insert(int id, addr_t kcap);
/**
* Remove a Cap_index object
*
* \param i pointer to Cap_index object to remove
*/
void remove(Cap_index* i);
};
/**
* Get the global Capability_map of the process.
*/
Capability_map *cap_map();
}
#endif /* _INCLUDE__BASE__CAP_MAP_H_ */

View File

@ -1,224 +0,0 @@
/*
* \brief Interface for process-local capability-selector allocation
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2010-01-19
*
* This interface is Fiasco-specific and not part of the Genode API. It should
* only be used internally by the framework or by Fiasco-specific code. The
* implementation of the interface is part of the environment library.
*
* This implementation is borrowed by the nova-platform equivalent.
* (TODO: merge it)
*/
/*
* Copyright (C) 2010-2012 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 _INCLUDE__BASE__CAP_SEL_ALLOC_H_
#define _INCLUDE__BASE__CAP_SEL_ALLOC_H_
/* Genode includes */
#include <base/stdint.h>
#include <util/avl_tree.h>
#include <base/native_types.h>
#include <base/printf.h>
#include <base/lock_guard.h>
#include <cpu/atomic.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/ipc.h>
#include <l4/sys/consts.h>
}
namespace Genode
{
class Capability_allocator
{
protected:
Capability_allocator() {}
virtual ~Capability_allocator() {}
public:
/**
* Allocate range of capability selectors
*
* \param num_caps_log2 number of capability selectors. By default,
* the function returns a single capability selector.
* \return first capability selector of allocated range,
* or 0 if allocation failed
*/
virtual addr_t alloc(size_t num_caps = 1) = 0;
/**
* Allocate or find a capability selector
*
* \param id Genode's global capability id we're looking for
* \return return a previously allocated cap-selector associated
* with the given id, or a new one, that is associated
* with the id from now on.
*/
virtual addr_t alloc_id(unsigned id) = 0;
/**
* Release range of capability selectors
*
* \param cap first capability selector of range
* \param num_caps_log2 number of capability selectors to free.
*/
virtual void free(addr_t cap, size_t num_caps = 1) = 0;
};
Capability_allocator* cap_alloc();
/**
* Low-level spin-lock to protect the allocator
*
* We cannot use a normal Genode lock because this lock is used by code
* executed prior the initialization of Genode.
*/
class Spin_lock
{
private:
volatile int _spinlock;
public:
/**
* Constructor
*/
Spin_lock();
void lock();
void unlock();
/**
* Lock guard
*/
typedef Genode::Lock_guard<Spin_lock> Guard;
};
template <unsigned SZ>
class Capability_allocator_tpl : public Capability_allocator
{
private:
/**
* Node in the capability cache,
* associates global cap ids with kernel-capabilities.
*/
class Cap_node : public Avl_node<Cap_node>
{
private:
friend class Capability_allocator_tpl<SZ>;
unsigned long _id;
addr_t _kcap;
public:
Cap_node() : _id(0), _kcap(0) {}
Cap_node(unsigned long id, addr_t kcap)
: _id(id), _kcap(kcap) {}
bool higher(Cap_node *n) {
return n->_id > _id; }
Cap_node *find_by_id(unsigned long id)
{
if (_id == id) return this;
Cap_node *n = Avl_node<Cap_node>::child(id > _id);
return n ? n->find_by_id(id) : 0;
}
unsigned long id() const { return _id; }
addr_t kcap() const { return _kcap; }
bool valid() const { return _id || _kcap; }
};
addr_t _cap_idx; /* start cap-selector */
Cap_node _data[SZ]; /* cache-nodes backing store */
Avl_tree<Cap_node> _tree; /* cap cache */
Spin_lock _lock;
public:
/**
* Constructor
*/
Capability_allocator_tpl() : _cap_idx(Fiasco::USER_BASE_CAP) { }
/************************************
** Capability_allocator interface **
************************************/
addr_t alloc(size_t num_caps)
{
Spin_lock::Guard guard(_lock);
int ret_base = _cap_idx;
_cap_idx += num_caps * Fiasco::L4_CAP_SIZE;
return ret_base;
}
addr_t alloc_id(unsigned id)
{
_lock.lock();
Cap_node *n = _tree.first();
if (n)
n = n->find_by_id(id);
_lock.unlock();
if (n) {
return n->kcap();
}
addr_t kcap = alloc(1);
_lock.lock();
for (unsigned i = 0; i < SZ; i++)
if (!_data[i].valid()) {
_data[i]._id = id;
_data[i]._kcap = kcap;
_tree.insert(&_data[i]);
break;
}
_lock.unlock();
return kcap;
}
void free(addr_t cap, size_t num_caps)
{
Spin_lock::Guard guard(_lock);
for (unsigned i = 0; i < SZ; i++)
if (!_data[i]._kcap == cap) {
_tree.remove(&_data[i]);
_data[i]._kcap = 0;
_data[i]._id = 0;
break;
}
}
};
}
#endif /* _INCLUDE__BASE__CAP_SEL_ALLOC_H_ */

View File

@ -24,9 +24,14 @@ namespace Fiasco {
inline void Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
{
long unique_id = cap.local_name();
_write_to_buf(unique_id);
if (unique_id)
bool local = cap.local();
long id = local ? (long)cap.local() : cap.local_name();
_write_to_buf(local);
_write_to_buf(id);
/* only transfer kernel-capability if it's no local capability and valid */
if (!local && id)
_snd_msg->snd_append_cap_sel(cap.dst());
}
@ -35,24 +40,48 @@ inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability
{
using namespace Fiasco;
/* extract Genode internal capability label from message buffer */
long unique_id = 0;
_read_from_buf(unique_id);
bool local = false;
long id = 0;
if (!unique_id) {
/* extract capability id from message buffer, and whether it's a local cap */
_read_from_buf(local);
_read_from_buf(id);
/* if it's a local capability, the pointer is marshalled in the id */
if (local) {
cap = Capability<Native_capability>::local_cap((Native_capability*)id);
return;
}
/* if id is zero an invalid capability was tranfered */
if (!id) {
cap = Native_capability();
return;
}
/* allocate new cap slot and grant cap to it out of receive window */
Genode::addr_t cap_sel = cap_alloc()->alloc_id(unique_id);
l4_msgtag_t tag = l4_task_cap_valid(L4_BASE_TASK_CAP, cap_sel);
if (!tag.label()) {
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP,
l4_obj_fpage(_rcv_msg->rcv_cap_sel(), 0, L4_FPAGE_RWX),
cap_sel | L4_ITEM_MAP | L4_MAP_ITEM_GRANT);
/* we received a valid, non-local capability, maybe we already own it? */
Cap_index *i = cap_map()->find(id);
bool map = false;
if (i) {
/**
* If we've a dead capability in our database, which is already
* revoked, its id might be reused.
*/
l4_msgtag_t tag = Fiasco::l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap());
if (!tag.label())
map = true;
} else {
/* insert the new capability in the map */
i = cap_map()->insert(id);
map = true;
}
cap = Native_capability(cap_sel, unique_id);
/* map the received capability from the receive-buffer if necessary */
if (map)
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP,
l4_obj_fpage(_rcv_msg->rcv_cap_sel(), 0, L4_FPAGE_RWX),
i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT);
cap = Native_capability(i);
}
#endif /* _INCLUDE__BASE__IPC_H_ */

View File

@ -18,7 +18,7 @@
#define _INCLUDE__BASE__IPC_MSGBUF_H_
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/cap_map.h>
/* Fiasco.OC includes */
namespace Fiasco {
@ -51,7 +51,7 @@ namespace Genode {
/**
* Base of capability receive window.
*/
addr_t _rcv_cap_sel_base;
Cap_index* _rcv_idx_base;
/**
* Read counter for unmarshalling portal capability selectors
@ -65,13 +65,15 @@ namespace Genode {
/**
* Constructor
*/
Msgbuf_base()
: _rcv_cap_sel_base(cap_alloc()->alloc(MAX_CAP_ARGS))
Msgbuf_base() : _rcv_idx_base(cap_idx_alloc()->alloc(MAX_CAP_ARGS))
{
rcv_reset();
snd_reset();
}
~Msgbuf_base() {
cap_idx_alloc()->free(_rcv_idx_base, MAX_CAP_ARGS); }
/*
* Begin of actual message buffer
*/
@ -121,7 +123,7 @@ namespace Genode {
/**
* Return address of capability receive window.
*/
addr_t rcv_cap_sel_base() { return _rcv_cap_sel_base; }
addr_t rcv_cap_sel_base() { return _rcv_idx_base->kcap(); }
/**
* Reset capability receive window
@ -134,7 +136,7 @@ namespace Genode {
* \return capability selector, or 0 if index is invalid
*/
addr_t rcv_cap_sel() {
return _rcv_cap_sel_base + _rcv_cap_sel_cnt++ * Fiasco::L4_CAP_SIZE; }
return rcv_cap_sel_base() + _rcv_cap_sel_cnt++ * Fiasco::L4_CAP_SIZE; }
};

View File

@ -153,8 +153,8 @@ namespace Genode {
/**
* Set destination for next reply
*/
void set_reply_dst(Native_capability pager_object) {
_last = pager_object.dst(); }
void set_reply_dst(Native_thread t) {
_last = t; }
/**
* Answer call without sending a flex-page mapping

View File

@ -1,12 +1,13 @@
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
#define _INCLUDE__BASE__NATIVE_TYPES_H_
#include <base/native_capability.h>
#include <base/cap_map.h>
namespace Fiasco {
#include <l4/sys/consts.h>
#include <l4/sys/types.h>
#include <l4/sys/utcb.h>
#include <l4/sys/task.h>
enum Cap_selectors {
TASK_CAP = L4_BASE_TASK_CAP,
@ -24,29 +25,92 @@ namespace Fiasco {
UTCB_TCR_BADGE = 1,
UTCB_TCR_THREAD_OBJ = 2
};
struct Capability
{
static bool valid(l4_cap_idx_t idx) {
return !(idx & L4_INVALID_CAP_BIT) && idx != 0; }
};
}
namespace Genode {
struct Cap_dst_policy
{
typedef Fiasco::l4_cap_idx_t Dst;
static bool valid(Dst idx) {
return !(idx & Fiasco::L4_INVALID_CAP_BIT) && idx != 0; }
static Dst invalid() { return Fiasco::L4_INVALID_CAP;}
static void copy(void* dst, Native_capability_tpl<Cap_dst_policy>* src);
};
typedef volatile int Native_lock;
typedef Fiasco::l4_cap_idx_t Native_thread_id;
typedef Fiasco::l4_cap_idx_t Native_thread;
typedef Fiasco::l4_cap_idx_t Native_task;
typedef Fiasco::l4_utcb_t* Native_utcb;
typedef int Native_connection_state;
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
/**
* Native_capability in Fiasco.OC is just a reference to a Cap_index.
*
* As Cap_index objects cannot be copied around, but Native_capability
* have to, we have to use this indirection. Moreover, it might instead
* of a Cap_index reference some process-local object, and thereby
* implements a local capability.
*/
class Native_capability
{
private:
Cap_index* _idx;
void* _ptr;
inline Native_thread_id _cap_sel() const
{
return _idx ? Native_thread_id(_idx->kcap())
: Native_thread_id();
}
protected:
/**
* Constructs a local capability, used by derived Capability
* class only
*
* \param ptr pointer to process-local object
*/
Native_capability(void* ptr) : _idx(0), _ptr(ptr) { }
public:
/**
* Default constructor creates an invalid capability
*/
Native_capability() : _idx(0), _ptr(0) { }
/**
* Construct capability manually
*/
Native_capability(Cap_index* idx) : _idx(idx), _ptr(0) { }
/**
* Return Cap_index object referenced by this object
*/
Cap_index* idx() const { return _idx; }
/**
* Overloaded comparision operator
*/
bool operator==(const Native_capability &o) const {
return (_ptr) ? _ptr == o._ptr : _idx == o._idx; }
/*******************************************
** Interface provided by all platforms **
*******************************************/
int local_name() const { return _idx ? _idx->id() : 0; }
Native_thread dst() const { return _cap_sel(); }
bool valid() const { return (_idx != 0) && _idx->valid(); }
void* local() const { return _ptr; }
void copy_to(void* dst) { *((int*)dst) = local_name(); }
};
typedef int Native_connection_state;
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -24,16 +24,20 @@ namespace Genode {
struct Thread_state : public Cpu_state
{
Native_capability cap; /* capability selector with thread cap */
Native_thread kcap; /* thread's gate cap in its pd */
int id; /* id of gate capability */
Native_utcb utcb; /* thread's utcb in its pd */
unsigned exceptions; /* counts exceptions raised by the thread */
bool paused; /* indicates whether thread is stopped */
bool in_exception; /* true if thread is currently in exception */
bool in_exception; /* true if thread is in exception */
Lock lock;
/**
* Constructor
*/
Thread_state() : cap(), exceptions(0), paused(false) { }
Thread_state()
: kcap(Fiasco::L4_INVALID_CAP), id(0), utcb(0), exceptions(0),
paused(false), in_exception(false) { }
};
}

View File

@ -32,6 +32,9 @@ namespace Genode {
public:
Signal_source_rpc_object(Native_capability cap)
: _blocking_semaphore(cap) {}
Native_capability _request_semaphore() { return _blocking_semaphore; }
};
}

View File

View File

@ -1,10 +1,11 @@
SRC_CC = env.cc context_area.cc cap_sel_alloc.cc \
SRC_CC = env.cc context_area.cc cap_map.cc cap_alloc.cc \
reload_parent_cap.cc spin_lock.cc
LIBS = ipc heap log_console lock
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
vpath env.cc $(BASE_DIR)/src/base/env
vpath context_area.cc $(BASE_DIR)/src/base/env
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath reload_parent_cap.cc $(BASE_DIR)/src/base/env
vpath cap_map.cc $(REP_DIR)/src/base/env
vpath cap_alloc.cc $(REP_DIR)/src/base/env
vpath spin_lock.cc $(REP_DIR)/src/base/env
vpath reload_parent_cap.cc $(BASE_DIR)/src/base/env

View File

@ -1,4 +1,4 @@
LIBS = syscalls cap_copy
LIBS = syscalls
SRC_CC += ipc.cc pager.cc
INC_DIR += $(REP_DIR)/src/base/lock

20
base-foc/src/base/env/cap_alloc.cc vendored Normal file
View File

@ -0,0 +1,20 @@
/*
* \brief Capability index allocator for Fiasco.OC non-core processes.
* \author Stefan Kalkowski
* \date 2012-02-16
*/
/*
* Copyright (C) 2012 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/cap_alloc.h>
Genode::Cap_index_allocator* Genode::cap_idx_alloc()
{
static Genode::Cap_index_allocator_tpl<Cap_index,4096> alloc;
return &alloc;
}

102
base-foc/src/base/env/cap_map.cc vendored Normal file
View File

@ -0,0 +1,102 @@
/*
* \brief Mapping of Genode's capability names to kernel capabilities.
* \author Stefan Kalkowski
* \date 2010-12-06
*
* This is a Fiasco.OC-specific addition to the process enviroment.
*/
/*
* Copyright (C) 2010-2012 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/cap_map.h>
#include <base/native_types.h>
/***********************
** Cap_index class **
***********************/
bool Genode::Cap_index::higher(Genode::Cap_index *n) { return n->_id > _id; }
Genode::Cap_index* Genode::Cap_index::find_by_id(Genode::uint16_t id)
{
using namespace Genode;
if (_id == id) return this;
Cap_index *n = Avl_node<Cap_index>::child(id > _id);
return n ? n->find_by_id(id) : 0;
}
Genode::addr_t Genode::Cap_index::kcap() {
return cap_idx_alloc()->idx_to_kcap(this); }
Genode::Cap_index* Genode::Capability_map::find(int id)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
Cap_index* i = 0;
if (_tree.first())
i = _tree.first()->find_by_id(id);
return i;
}
/****************************
** Capability_map class **
****************************/
Genode::Cap_index* Genode::Capability_map::insert(int id)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
Cap_index *i = cap_idx_alloc()->alloc(1);
i->id(id);
_tree.insert(i);
return i;
}
Genode::Cap_index* Genode::Capability_map::insert(int id, addr_t kcap)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
Cap_index *i = cap_idx_alloc()->alloc(kcap, 1);
i->id(id);
_tree.insert(i);
return i;
}
void Genode::Capability_map::remove(Genode::Cap_index* i)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
if (i) {
_tree.remove(i);
cap_idx_alloc()->free(i,1);
}
}
Genode::Capability_map* Genode::cap_map()
{
static Genode::Capability_map map;
return &map;
}

View File

@ -1,24 +0,0 @@
/*
* \brief Capability-selector allocator for non-core tasks.
* \author Stefan Kalkowski
* \date 2010-12-06
*
* This is a Fiasco.OC-specific addition to the process enviroment.
*/
/*
* Copyright (C) 2010-2012 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/cap_sel_alloc.h>
Genode::Capability_allocator* Genode::cap_alloc()
{
static Genode::Capability_allocator_tpl<4096> _alloc;
return &_alloc;
}

View File

@ -14,7 +14,7 @@
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/cap_map.h>
/* Lock implementation local include */
#include <spin_lock.h>

View File

@ -52,7 +52,7 @@ enum Debug {
};
static bool ipc_error(l4_msgtag_t tag, bool print)
static inline bool ipc_error(l4_msgtag_t tag, bool print)
{
int ipc_error = l4_ipc_error(tag, l4_utcb());
if (ipc_error) {
@ -189,8 +189,7 @@ void Ipc_istream::_wait()
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
:
Ipc_unmarshaller(&rcv_msg->buf[0], rcv_msg->size()),
Native_capability(thread_get_my_native_id(),
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]),
Native_capability(cap_map()->find(Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE])),
_rcv_msg(rcv_msg)
{
_read_offset = sizeof(l4_mword_t);
@ -266,8 +265,7 @@ void Ipc_server::_reply()
{
l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _write_offset, _dst);
tag = l4_ipc_send(L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_SEND_TIMEOUT_0);
if (ipc_error(tag, DEBUG_MSG))
throw Ipc_error();
ipc_error(tag, DEBUG_MSG);
}

View File

@ -98,7 +98,7 @@ void Ipc_pager::reply_and_wait_for_fault()
void Ipc_pager::acknowledge_wakeup()
{
l4_cap_idx_t dst = Cap_dst_policy::valid(_last) ? _last : L4_SYSF_REPLY;
l4_cap_idx_t dst = Fiasco::Capability::valid(_last) ? _last : L4_SYSF_REPLY;
/* answer wakeup call from one of core's region-manager sessions */
l4_ipc_send(dst, l4_utcb(), l4_msgtag(0, 0, 0, 0), L4_IPC_SEND_TIMEOUT_0);
@ -106,5 +106,5 @@ void Ipc_pager::acknowledge_wakeup()
Ipc_pager::Ipc_pager()
: Native_capability(Thread_base::myself()->tid(), 0), _badge(0) { }
: Native_capability(cap_map()->find(Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE])), _badge(0) { }

View File

@ -81,7 +81,7 @@ static inline Genode::Native_thread_id thread_invalid_id()
*/
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return Genode::Cap_dst_policy::valid(tid);
return Fiasco::Capability::valid(tid);
}

View File

@ -78,7 +78,7 @@ void Pager_activation_base::entry()
PDBG("Could not resolve pf=%p ip=%p",
(void*)pager.fault_addr(), (void*)pager.fault_ip());
} else {
pager.set_reply_dst(Native_capability(obj->badge(),0));
pager.set_reply_dst(obj->badge());
reply_pending = true;
continue;
}
@ -101,7 +101,7 @@ void Pager_activation_base::entry()
}
/* send reply to the caller */
pager.set_reply_dst(Native_capability());
pager.set_reply_dst(Native_thread());
pager.acknowledge_wakeup();
/* revert exception flag */
@ -111,7 +111,7 @@ void Pager_activation_base::entry()
}
/* send wake up message to requested thread */
pager.set_reply_dst(Native_capability(obj->badge(),0));
pager.set_reply_dst(obj->badge());
pager.acknowledge_wakeup();
break;
}
@ -131,12 +131,12 @@ void Pager_activation_base::entry()
obj->state.in_exception = true;
/*
* It might occur, that the thread raises an exception,
* It might occur that the thread raises an exception,
* after it already got resumed by the cpu_session, in
* that case we unblock it immediately.
*/
if (!obj->state.paused) {
pager.set_reply_dst(Native_capability(obj->badge(),0));
pager.set_reply_dst(obj->badge());
reply_pending = true;
}
break;

View File

@ -11,31 +11,11 @@
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/ipc.h>
#include <base/sleep.h>
#include <base/thread.h>
namespace Fiasco {
#include <l4/sys/utcb.h>
}
void Genode::Thread_base::_thread_bootstrap()
{
using namespace Genode;
using namespace Fiasco;
/* first, receive my own gate-capability and badge from starter thread */
addr_t thread_base = 0;
unsigned long my_badge = 0;
Msgbuf<128> snd_msg, rcv_msg;
Ipc_server srv(&snd_msg, &rcv_msg);
srv >> IPC_WAIT >> thread_base >> my_badge << IPC_REPLY;
/* store both values in user-defined section of the UTCB */
l4_utcb_tcr()->user[UTCB_TCR_BADGE] = my_badge;
l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ] = thread_base;
}
void Genode::Thread_base::_thread_bootstrap() { }
void Genode::Thread_base::_thread_start()

View File

@ -18,17 +18,27 @@
#include <base/sleep.h>
#include <base/env.h>
namespace Fiasco {
#include <l4/sys/utcb.h>
}
using namespace Genode;
void Thread_base::_deinit_platform_thread()
{
using namespace Fiasco;
int id = l4_utcb_tcr_u(_context->utcb)->user[UTCB_TCR_BADGE];
env()->cpu_session()->kill_thread(_thread_cap);
cap_map()->remove(cap_map()->find(id));
}
void Thread_base::start()
{
using namespace Fiasco;
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
@ -41,23 +51,20 @@ void Thread_base::start()
Pager_capability pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
/* get gate-capability and badge of new thread */
Thread_state state;
env()->cpu_session()->state(_thread_cap, &state);
_tid = state.kcap;
_context->utcb = state.utcb;
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_BADGE] = state.id;
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
cap_map()->insert(state.id, state.kcap);
/* register initial IP and SP at core */
addr_t thread_sp = (addr_t)&_context->stack[-4];
thread_sp &= ~0xf; /* align initial stack to 16 byte boundary */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, thread_sp);
/* get gate-capability and badge of new thread */
Thread_state state;
env()->cpu_session()->state(_thread_cap, &state);
_tid = state.cap.dst();
/*
* send newly constructed thread, pointer to its Thread_base object,
* and its badge
*/
Msgbuf<128> snd_msg, rcv_msg;
Ipc_client cli(state.cap, &snd_msg, &rcv_msg);
cli << (addr_t)this << state.cap.local_name() << IPC_CALL;
}

View File

@ -13,21 +13,88 @@
/* Genode includes */
#include <base/capability.h>
#include <base/cap_alloc.h>
#include <util/misc_math.h>
/* core includes */
#include <cap_session_component.h>
#include <cap_id_alloc.h>
#include <cap_index.h>
#include <platform.h>
namespace Fiasco {
#include <l4/sys/consts.h>
#include <l4/sys/debugger.h>
#include <l4/sys/factory.h>
#include <l4/sys/task.h>
#include <l4/sys/types.h>
}
using namespace Genode;
/***************************
** Cap_index_allocator **
***************************/
Genode::Cap_index_allocator* Genode::cap_idx_alloc()
{
static Genode::Cap_index_allocator_tpl<Core_cap_index,10*1024> alloc;
return &alloc;
}
/*******************
** Cap_mapping **
*******************/
Core_cap_index* Cap_mapping::_get_cap()
{
int id = platform_specific()->cap_id_alloc()->alloc();
return reinterpret_cast<Core_cap_index*>(cap_map()->insert(id));
}
void Cap_mapping::map(Native_thread_id task)
{
using namespace Fiasco;
if (!local || !Fiasco::Capability::valid(remote))
return;
l4_msgtag_t tag = l4_task_map(task, L4_BASE_TASK_CAP,
l4_obj_fpage(local->kcap(), 0, L4_FPAGE_RWX),
((l4_cap_idx_t)remote) | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PERR("mapping cap failed");
}
void Cap_mapping::unmap()
{
using namespace Fiasco;
l4_msgtag_t tag = l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(local->kcap(), 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
if (l4_msgtag_has_error(tag))
PERR("unmapping cap failed");
}
Cap_mapping::Cap_mapping(bool alloc, Native_thread_id r)
: local(alloc ? _get_cap() : 0), remote(r) { }
Cap_mapping::Cap_mapping(Core_cap_index* i, Native_thread_id r)
: local(i), remote(r) { }
Cap_mapping::~Cap_mapping()
{
unmap();
cap_map()->remove(cap_map()->find(local->id()));
}
/*****************************
** Cap_session_component **
@ -40,55 +107,38 @@ Native_capability Cap_session_component::alloc(Cap_session_component *session,
if (!ep.valid()) {
PWRN("Invalid cap!");
return Native_capability();
}
/*
* maybe someone tries to fool us, proof whether cap exists in cap tree.
*
* Actually we should proof whether both capability selectors
* point to the same object, but this isn't possible in fiasco.oc.
*/
Capability_node *n = Capability_tree::tree()->find_by_badge(ep.local_name());
if (!n) {
PWRN("Unknown capability!");
return cap;
}
try {
using namespace Fiasco;
Core_cap_index* ref = reinterpret_cast<Core_cap_index*>(ep.idx());
/*
* Allocate new badge, and ipc-gate and set badge as gate-label
* Allocate new id, and ipc-gate and set id as gate-label
*/
unsigned long badge = Badge_allocator::allocator()->alloc();
Native_thread gate = cap_alloc()->alloc_id(badge);
l4_msgtag_t tag = l4_factory_create_gate(L4_BASE_FACTORY_CAP,
gate,
n->pt()->native_thread(),
badge);
unsigned long id = platform_specific()->cap_id_alloc()->alloc();
Core_cap_index* idx =
reinterpret_cast<Core_cap_index*>(cap_map()->insert(id));
l4_msgtag_t tag = l4_factory_create_gate(L4_BASE_FACTORY_CAP,
idx->kcap(),
ref->pt()->thread().local->kcap(), id);
if (l4_msgtag_has_error(tag)) {
PERR("l4_factory_create_gate failed!");
cap_alloc()->free(gate);
Badge_allocator::allocator()->free(badge);
cap_map()->remove(idx);
platform_specific()->cap_id_alloc()->free(id);
return cap;
} else
/* set debugger-name of ipc-gate to thread's name */
Fiasco::l4_debugger_set_object_name(gate, n->pt()->name());
/*
* Create new node in capability tree.
*
* TODO: don't use core_mem_alloc, but a session-specific allocator
*/
Capability_node *new_node = new (platform()->core_mem_alloc())
Capability_node(badge, session, n->pt(), gate);
Capability_tree::tree()->insert(new_node);
cap = Native_capability(gate, badge);
} catch (Badge_allocator::Out_of_badges) {}
Fiasco::l4_debugger_set_object_name(idx->kcap(), ref->pt()->name());
idx->session(session);
idx->pt(ref->pt());
cap = Native_capability(idx);
} catch (Cap_id_allocator::Out_of_ids) {
PERR("Out of IDs");
}
return cap;
}
@ -103,137 +153,62 @@ void Cap_session_component::free(Native_capability cap)
{
using namespace Fiasco;
Capability_node *n = Capability_tree::tree()->find_by_badge(cap.local_name());
if (!n)
if (!cap.valid())
return;
Core_cap_index* idx = reinterpret_cast<Core_cap_index*>(cap.idx());
/*
* check whether this cap_session has created the capability to delete.
*
* Actually we should proof whether both capability selectors
* point to the same object, but this isn't possible in fiasco.oc.
*/
if (n->cap_session() != this)
if (idx->session() != this)
return;
Capability_tree::tree()->remove(n);
l4_msgtag_t tag = l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(cap.dst(), 0, L4_FPAGE_RWX),
l4_obj_fpage(idx->kcap(), 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
if (l4_msgtag_has_error(tag))
PERR("destruction of ipc-gate %lx failed!", (unsigned long) cap.dst());
PERR("destruction of ipc-gate %lx failed!", (unsigned long) idx->kcap());
/* free badge _after_ invalidating all caps */
Badge_allocator::allocator()->free(n->badge());
/* free explicilty allocated cap-selector */
cap_alloc()->free(n->gate());
destroy(platform_specific()->core_mem_alloc(), n);
unsigned long id = idx->id();
cap_map()->remove(idx);
platform_specific()->cap_id_alloc()->free(id);
}
/***********************
** Badge Allocator **
***********************/
/*******************************
** Capability ID Allocator **
*******************************/
Badge_allocator::Badge_allocator()
: _id_alloc(platform_specific()->core_mem_alloc())
Cap_id_allocator::Cap_id_allocator(Allocator* alloc)
: _id_alloc(alloc)
{
_id_alloc.add_range(BADGE_OFFSET, BADGE_RANGE);
_id_alloc.add_range(CAP_ID_OFFSET, CAP_ID_RANGE);
}
unsigned long Badge_allocator::alloc()
unsigned long Cap_id_allocator::alloc()
{
Lock::Guard lock_guard(_lock);
void *badge;
if (_id_alloc.alloc(BADGE_OFFSET, &badge))
return (unsigned long) badge;
throw Out_of_badges();
void *id;
if (_id_alloc.alloc(CAP_ID_OFFSET, &id))
return (unsigned long) id;
throw Out_of_ids();
}
void Badge_allocator::free(unsigned long badge)
void Cap_id_allocator::free(unsigned long id)
{
Lock::Guard lock_guard(_lock);
if (badge < BADGE_RANGE)
_id_alloc.free((void*)(badge & BADGE_MASK), BADGE_OFFSET);
if (id < CAP_ID_RANGE)
_id_alloc.free((void*)(id & CAP_ID_MASK), CAP_ID_OFFSET);
}
Badge_allocator* Badge_allocator::allocator()
Genode::Cap_index_allocator* cap_idx_alloc()
{
static Badge_allocator alloc;
return &alloc;
}
/***********************
** Capability_node **
***********************/
Capability_node::Capability_node(unsigned long badge,
Cap_session_component *cap_session,
Platform_thread *pt,
Native_thread gate)
: _badge(badge), _cap_session(cap_session), _pt(pt), _gate(gate) {}
bool Capability_node::higher(Capability_node *n)
{
return n->_badge > _badge;
}
Capability_node* Capability_node::find_by_badge(unsigned long badge)
{
if (_badge == badge) return this;
Capability_node *n = Avl_node<Capability_node>::child(badge > _badge);
return n ? n->find_by_badge(badge) : 0;
}
/***********************
** Capability_tree **
***********************/
void Capability_tree::insert(Avl_node<Capability_node> *node)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Capability_node>::insert(node);
}
void Capability_tree::remove(Avl_node<Capability_node> *node)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Capability_node>::remove(node);
}
Capability_node* Capability_tree::find_by_badge(unsigned long badge)
{
Lock::Guard lock_guard(_lock);
return first()->find_by_badge(badge);
}
Capability_tree* Capability_tree::tree()
{
static Capability_tree _tree;
return &_tree;
}
Genode::Capability_allocator* Genode::cap_alloc()
{
static Genode::Capability_allocator_tpl<20*1024> _alloc;
static Genode::Cap_index_allocator_tpl<Core_cap_index, 20*1024> _alloc;
return &_alloc;
}

View File

@ -16,6 +16,7 @@
/* Core includes */
#include <cpu_session_component.h>
#include <platform.h>
/* Fiasco.OC includes */
namespace Fiasco {
@ -35,7 +36,7 @@ void Genode::Cpu_session_component::enable_vcpu(Genode::Thread_capability thread
Cpu_thread_component *thread = _lookup_thread(thread_cap);
if (!thread) return;
Native_thread tid = thread->platform_thread()->native_thread();
Native_thread tid = thread->platform_thread()->thread().local->kcap();
l4_msgtag_t tag = l4_thread_vcpu_control(tid, vcpu_state);
if (l4_msgtag_has_error(tag))
@ -53,7 +54,7 @@ Genode::Cpu_session_component::native_cap(Genode::Thread_capability cap)
Cpu_thread_component *thread = _lookup_thread(cap);
if (!thread) return Native_capability();
return thread->platform_thread()->thread_cap();
return Native_capability(thread->platform_thread()->thread().local);
}
@ -61,11 +62,11 @@ Genode::Native_capability Genode::Cpu_session_component::alloc_irq()
{
using namespace Fiasco;
Native_thread_id irq_cap(Genode::cap_alloc()->alloc());
l4_msgtag_t res = l4_factory_create_irq(L4_BASE_FACTORY_CAP, irq_cap);
Cap_index* i = cap_map()->insert(platform_specific()->cap_id_alloc()->alloc());
l4_msgtag_t res = l4_factory_create_irq(L4_BASE_FACTORY_CAP, i->kcap());
if (l4_error(res))
PWRN("Allocation of irq object failed!");
return Genode::Native_capability(irq_cap, Badge_allocator::allocator()->alloc());
return Genode::Native_capability(i);
}
@ -78,7 +79,7 @@ void Genode::Cpu_session_component::single_step(Genode::Thread_capability thread
Cpu_thread_component *thread = _lookup_thread(thread_cap);
if (!thread) return;
Native_thread tid = thread->platform_thread()->native_thread();
Native_thread tid = thread->platform_thread()->thread().local->kcap();
enum { THREAD_SINGLE_STEP = 0x40000 };
int flags = enable ? THREAD_SINGLE_STEP : 0;

View File

@ -0,0 +1,51 @@
/*
* \brief Capability IDs allocation service
* \author Stefan Kalkowski
* \date 2012-02-22
*/
/*
* Copyright (C) 2012 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__CAP_IP_ALLOC_H_
#define _CORE__INCLUDE__CAP_IP_ALLOC_H_
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/exception.h>
#include <base/lock.h>
#include <base/sync_allocator.h>
namespace Genode {
class Cap_id_allocator
{
private:
enum {
CAP_ID_RANGE = ~0UL,
CAP_ID_MASK = ~3UL,
CAP_ID_NUM_MAX = CAP_ID_MASK >> 2,
CAP_ID_OFFSET = 1 << 2
};
Synchronized_range_allocator<Allocator_avl> _id_alloc;
Lock _lock;
public:
class Out_of_ids : Exception {};
Cap_id_allocator(Allocator*);
unsigned long alloc();
void free(unsigned long id);
};
}
#endif /* _CORE__INCLUDE__CAP_IP_ALLOC_H_ */

View File

@ -0,0 +1,50 @@
/*
* \brief Core-specific capability index.
* \author Stefan Kalkowski
* \date 2012-02-22
*/
/*
* Copyright (C) 2012 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__CAP_INDEX_H_
#define _CORE__INCLUDE__CAP_INDEX_H_
/* Genode includes */
#include <base/cap_map.h>
/* Core includes */
#include <cap_session_component.h>
namespace Genode {
class Platform_thread;
class Core_cap_index : public Cap_index
{
private:
Cap_session_component *_session;
Platform_thread *_pt;
Native_thread _gate;
public:
Core_cap_index(Cap_session_component *session = 0,
Platform_thread *pt = 0,
Native_thread gate = Native_thread() )
: _session(session), _pt(pt), _gate(gate) {}
Cap_session_component *session() { return _session; }
Platform_thread *pt() { return _pt; }
Native_thread gate() { return _gate; }
void session(Cap_session_component* c) { _session = c; }
void pt(Platform_thread* t) { _pt = t; }
};
}
#endif /* _CORE__INCLUDE__CAP_INDEX_H_ */

View File

@ -0,0 +1,66 @@
/*
* \brief Fiasco.OC specific capability mapping.
* \author Stefan Kalkowski
* \date 2012-02-22
*/
/*
* Copyright (C) 2012 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__CAP_MAPPING_H_
#define _CORE__INCLUDE__CAP_MAPPING_H_
/* core includes */
#include <cap_index.h>
#include <util/noncopyable.h>
namespace Genode {
/**
* A Cap_mapping embodies a capability of core, and its mapped
* copy in another protection domain.
*/
class Cap_mapping : Noncopyable
{
private:
/**
* Helper function for construction purposes.
*
* Allocates a new capability id and Core_cap_index and inserts
* it in the Cap_map.
*
* \return pointer to newly constructed Core_cap_index object
*/
inline Core_cap_index* _get_cap();
public:
Core_cap_index* local; /* reference to cap that is mapped */
Native_thread_id remote; /* index in cap-space of the other pd */
Cap_mapping(bool alloc=false,
Native_thread_id r = Fiasco::L4_INVALID_CAP);
Cap_mapping(Core_cap_index* i,
Native_thread_id r = Fiasco::L4_INVALID_CAP);
~Cap_mapping();
/**
* Map the cap in local to corresponding task.
*
* \param task capability of task to map to
*/
void map(Native_task task);
/**
* Unmap all child mappings
*/
void unmap();
};
}
#endif /* _CORE__INCLUDE__CAP_MAPPING_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Capability allocation service
* \brief Capability session service
* \author Stefan Kalkowski
* \date 2011-01-13
*/
@ -15,10 +15,6 @@
#define _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/exception.h>
#include <base/lock.h>
#include <base/sync_allocator.h>
#include <base/rpc_server.h>
namespace Genode {
@ -38,81 +34,6 @@ namespace Genode {
static Native_capability alloc(Cap_session_component *session,
Native_capability ep);
};
class Badge_allocator
{
private:
enum {
BADGE_RANGE = ~0UL,
BADGE_MASK = ~3UL,
BADGE_NUM_MAX = BADGE_MASK >> 2,
BADGE_OFFSET = 1 << 2
};
Synchronized_range_allocator<Allocator_avl> _id_alloc;
Lock _lock;
Badge_allocator();
public:
class Out_of_badges : Exception {};
unsigned long alloc();
void free(unsigned long badge);
static Badge_allocator* allocator();
};
class Platform_thread;
class Capability_node : public Avl_node<Capability_node>
{
private:
unsigned long _badge;
Cap_session_component *_cap_session;
Platform_thread *_pt;
Native_thread _gate;
public:
Capability_node(unsigned long badge,
Cap_session_component *cap_session,
Platform_thread *pt,
Native_thread gate);
bool higher(Capability_node *n);
Capability_node *find_by_badge(unsigned long badge);
unsigned long badge() { return _badge; }
Cap_session_component *cap_session() { return _cap_session; }
Platform_thread *pt() { return _pt; }
Native_thread gate() { return _gate; }
};
class Capability_tree : public Avl_tree<Capability_node>
{
private:
Lock _lock;
Capability_tree() {}
public:
void insert(Avl_node<Capability_node> *node);
void remove(Avl_node<Capability_node> *node);
Capability_node *find_by_badge(unsigned long badge);
static Capability_tree* tree();
};
}
#endif /* _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_ */

View File

@ -32,8 +32,8 @@ namespace Genode {
{
private:
Native_thread _cap;
Semaphore _sem;
Cap_index* _cap;
Semaphore _sem;
public:
@ -44,8 +44,8 @@ namespace Genode {
bool higher(Interrupt *n);
Interrupt* find_by_num(unsigned num);
Native_thread capability() { return _cap; }
Semaphore* semaphore() { return &_sem; }
Native_thread capability() { return _cap->kcap(); }
Semaphore* semaphore() { return &_sem; }
};

View File

@ -1,7 +1,8 @@
/*
* \brief Fiasco platform
* \brief Fiasco.OC platform
* \author Christian Helmuth
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2007-09-10
*/
@ -15,13 +16,17 @@
#ifndef _CORE__INCLUDE__PLATFORM_H_
#define _CORE__INCLUDE__PLATFORM_H_
/* Genode includes */
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <base/pager.h>
#include "platform_generic.h"
#include "platform_thread.h"
#include "platform_pd.h"
#include "multiboot.h"
/* Core includes */
#include <cap_id_alloc.h>
#include <platform_generic.h>
#include <platform_thread.h>
#include <platform_pd.h>
#include <multiboot.h>
namespace Genode {
@ -30,6 +35,19 @@ namespace Genode {
{
private:
/**
* Pager object representing the pager of core namely sigma0
*/
struct Sigma0 : public Pager_object
{
/**
* Constructor
*/
Sigma0(Cap_index*);
int pager(Ipc_pager &ps) { /* never called */ return -1; }
};
/*
* Shortcut for the type of allocator instances for physical resources
*/
@ -41,13 +59,16 @@ namespace Genode {
Phys_allocator _io_port_alloc; /* I/O port allocator */
Phys_allocator _irq_alloc; /* IRQ allocator */
Phys_allocator _region_alloc; /* virtual memory allocator for core */
Cap_id_allocator _cap_id_alloc; /* capability id allocator */
Multiboot_info _mb_info; /* multiboot information */
Rom_fs _rom_fs; /* ROM file system */
Rom_module _kip_rom; /* ROM module for Fiasco KIP */
Sigma0 _sigma0;
addr_t _vm_start; /* begin of virtual memory */
size_t _vm_size; /* size of virtual memory */
/*
* We do not export any boot module loaded before FIRST_ROM.
*/
@ -89,24 +110,6 @@ namespace Genode {
public:
/**
* Pager object representing the pager of core namely sigma0
*/
struct Sigma0 : public Pager_object
{
/**
* Constructor
*/
Sigma0();
int pager(Ipc_pager &ps) { /* never called */ return -1; }
};
/**
* Return singleton instance of Sigma0 pager object
*/
static Sigma0 *sigma0();
/**
* Core pager thread that handles core-internal page-faults
*/
@ -115,7 +118,7 @@ namespace Genode {
/**
* Constructor
*/
Core_pager(Platform_pd *core_pd);
Core_pager(Platform_pd *core_pd, Sigma0*);
int pager(Ipc_pager &ps) { /* never called */ return -1; }
};
@ -145,15 +148,16 @@ namespace Genode {
** Generic platform interface **
********************************/
Allocator *core_mem_alloc() { return &_ram_alloc; }
Range_allocator *ram_alloc() { return &_ram_alloc; }
Range_allocator *io_mem_alloc() { return &_io_mem_alloc; }
Range_allocator *io_port_alloc() { return &_io_port_alloc; }
Range_allocator *irq_alloc() { return &_irq_alloc; }
Range_allocator *region_alloc() { return &_region_alloc; }
addr_t vm_start() const { return _vm_start; }
size_t vm_size() const { return _vm_size; }
Rom_fs *rom_fs() { return &_rom_fs; }
Allocator *core_mem_alloc() { return &_ram_alloc; }
Range_allocator *ram_alloc() { return &_ram_alloc; }
Range_allocator *io_mem_alloc() { return &_io_mem_alloc; }
Range_allocator *io_port_alloc() { return &_io_port_alloc; }
Range_allocator *irq_alloc() { return &_irq_alloc; }
Range_allocator *region_alloc() { return &_region_alloc; }
Cap_id_allocator *cap_id_alloc() { return &_cap_id_alloc; }
addr_t vm_start() const { return _vm_start; }
size_t vm_size() const { return _vm_size; }
Rom_fs *rom_fs() { return &_rom_fs; }
void wait_for_exit();
};

View File

@ -18,12 +18,17 @@
#ifndef _CORE__INCLUDE__PLATFORM_PD_H_
#define _CORE__INCLUDE__PLATFORM_PD_H_
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/exception.h>
#include <base/sync_allocator.h>
#include <platform_thread.h>
#include <base/thread.h>
/* core includes */
#include <cap_mapping.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/consts.h>
}
@ -42,38 +47,24 @@ namespace Genode {
THREAD_MAX * Thread_base::CONTEXT_VIRTUAL_SIZE)
};
Native_task _l4_task_cap; /* L4 task capability slot */
unsigned _badge;
Native_capability _parent;
bool _parent_cap_mapped;
bool _task_cap_mapped;
Cap_mapping _task;
Cap_mapping _parent;
Platform_thread *_threads[THREAD_MAX];
/**
* Protection-domain creation
*
* The syscall parameter propagates if any L4 kernel function
* should be used. We need the special case for the Core startup.
*/
void _create_pd(bool syscall);
/**
* Protection domain destruction
*
* No special case for Core here - we just never call it.
*/
void _destroy_pd();
public:
class Threads_exhausted : Exception {};
/**
* Constructor
* Constructor for core.
*/
Platform_pd(bool create = true,
Native_task task_cap = Native_task());
Platform_pd(Core_cap_index*);
/**
* Constructor for all tasks except core.
*/
Platform_pd();
/**
* Destructor
@ -102,16 +93,12 @@ namespace Genode {
*/
int assign_parent(Native_capability parent);
void map_task_cap();
void map_parent_cap();
/*******************************
** Fiasco-specific Accessors **
*******************************/
Native_task native_task() { return _l4_task_cap; }
unsigned badge() { return _badge; }
Native_thread parent_cap() { return _parent.dst(); }
Native_capability native_task() const {
return Native_capability(_task.local); }
};
}

View File

@ -23,11 +23,7 @@
/* core includes */
#include <platform_pd.h>
#include <cap_session_component.h>
/* Fiasco includes */
namespace Fiasco {
#include <l4/sys/types.h>
}
#include <cap_mapping.h>
namespace Genode {
@ -38,22 +34,18 @@ namespace Genode {
friend class Platform_pd;
bool _core_thread;
unsigned _badge;
Native_capability _thread_cap;
Native_capability _gate_cap;
Native_capability _remote_gate_cap;
Native_thread _remote_pager_cap;
Native_thread _irq_cap;
Native_thread _remote_irq_cap;
Capability_node _node;
Native_utcb _utcb;
char _name[32]; /* thread name that will be
registered at the kernel
debugger */
Platform_pd *_platform_pd; /* protection domain thread
is bound to */
Pager_object *_pager;
bool _core_thread;
Cap_mapping _thread;
Cap_mapping _gate;
Cap_mapping _pager;
Cap_mapping _irq;
Native_utcb _utcb;
char _name[32]; /* thread name that will be
registered at the kernel
debugger */
Platform_pd *_platform_pd; /* protection domain thread
is bound to */
Pager_object *_pager_obj;
void _create_thread(void);
void _finalize_construction(const char *name, unsigned prio);
@ -71,7 +63,8 @@ namespace Genode {
/**
* Constructor for core main-thread
*/
Platform_thread(Native_thread cap, const char *name);
Platform_thread(Core_cap_index* thread,
Core_cap_index* irq, const char *name);
/**
* Constructor for core threads
@ -112,10 +105,9 @@ namespace Genode {
/**
* This thread is about to be bound
*
* \param cap final capability index
* \param pd platform pd, thread is bound to
*/
void bind(/*Native_thread_id cap, */Platform_pd *pd);
void bind(Platform_pd *pd);
/**
* Unbind this thread
@ -140,25 +132,25 @@ namespace Genode {
/**
* Return/set pager
*/
Pager_object *pager() const { return _pager; }
Pager_object *pager() const { return _pager_obj; }
void pager(Pager_object *pager);
/**
* Return identification of thread when faulting
*/
unsigned long pager_object_badge() {
return (unsigned long) _thread_cap.dst(); }
return (unsigned long) _thread.local->kcap(); }
/*******************************
** Fiasco-specific Accessors **
*******************************/
Native_thread native_thread() const { return _thread_cap.dst(); }
Native_capability thread_cap() const { return _thread_cap; }
Native_capability gate() const { return _remote_gate_cap; }
const char *name() const { return _name; }
bool core_thread() const { return _core_thread; }
Cap_mapping& thread() { return _thread; }
Cap_mapping& gate() { return _gate; }
const char *name() const { return _name; }
bool core_thread() const { return _core_thread; }
Native_utcb utcb() const { return _utcb; }
};
}

View File

@ -1,6 +1,7 @@
/*
* \brief Core implementation of IRQ sessions
* \brief Fiasco.OC-specific core implementation of IRQ sessions
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2007-09-13
*
* FIXME ram quota missing
@ -51,7 +52,8 @@ bool Irq_session_component::Interrupt::higher(Irq_session_component::Interrupt *
Irq_session_component::Interrupt::Interrupt()
: _cap(cap_alloc()->alloc()), _sem(), number(0) {}
: _cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
_sem(), number(0) {}
Native_thread Irq_session_component::Interrupt_handler::handler_cap()

View File

@ -19,4 +19,4 @@
Genode::Native_capability Genode::Pd_session_component::task_cap() {
return Native_capability(_pd.native_task(), _pd.badge()); }
return _pd.native_task(); }

View File

@ -120,30 +120,23 @@ static void _core_pager_loop()
}
Platform::Sigma0::Sigma0() : Pager_object(0)
Platform::Sigma0::Sigma0(Cap_index* i) : Pager_object(0)
{
/*
* We use the Pager_object here in a slightly different manner,
* just to tunnel the pager cap to the Platform_thread::start method.
*/
cap(reinterpret_cap_cast<Thread_capability>(Native_capability(Fiasco::L4_BASE_PAGER_CAP, 0)));
cap(reinterpret_cap_cast<Thread_capability>(Native_capability(i)));
}
Platform::Sigma0 *Platform::sigma0()
{
static Sigma0 _sigma0;
return &_sigma0;
}
Platform::Core_pager::Core_pager(Platform_pd *core_pd)
Platform::Core_pager::Core_pager(Platform_pd *core_pd, Sigma0 *sigma0)
: Platform_thread("core.pager"), Pager_object(0)
{
Platform_thread::pager(sigma0());
Platform_thread::pager(sigma0);
core_pd->bind_thread(this);
cap(Native_capability(native_thread(), 0));
cap(thread().local);
/* stack begins at the top end of the '_core_pager_stack' array */
void *sp = (void *)&_core_pager_stack[PAGER_STACK_ELEMENTS - 1];
@ -152,8 +145,8 @@ Platform::Core_pager::Core_pager(Platform_pd *core_pd)
using namespace Fiasco;
l4_thread_control_start();
l4_thread_control_pager(native_thread());
l4_thread_control_exc_handler(native_thread());
l4_thread_control_pager(thread().local->kcap());
l4_thread_control_exc_handler(thread().local->kcap());
l4_msgtag_t tag = l4_thread_control_commit(L4_BASE_THREAD_CAP);
if (l4_msgtag_has_error(tag))
PWRN("l4_thread_control_commit failed!");
@ -162,7 +155,7 @@ Platform::Core_pager::Core_pager(Platform_pd *core_pd)
Platform::Core_pager *Platform::core_pager()
{
static Core_pager _core_pager(core_pd());
static Core_pager _core_pager(core_pd(), &_sigma0);
return &_core_pager;
}
@ -447,7 +440,8 @@ void Platform::_setup_rom()
Platform::Platform() :
_ram_alloc(0), _io_mem_alloc(core_mem_alloc()),
_io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()),
_region_alloc(core_mem_alloc())
_region_alloc(core_mem_alloc()), _cap_id_alloc(core_mem_alloc()),
_sigma0(cap_map()->insert(_cap_id_alloc.alloc(), Fiasco::L4_BASE_PAGER_CAP))
{
/*
* We must be single-threaded at this stage and so this is safe.
@ -472,17 +466,25 @@ Platform::Platform() :
printf(":core ranges: "); _core_address_ranges().raw()->dump_addr_tree();
}
Core_cap_index* pdi =
reinterpret_cast<Core_cap_index*>(cap_map()->insert(_cap_id_alloc.alloc(), Fiasco::L4_BASE_TASK_CAP));
Core_cap_index* thi =
reinterpret_cast<Core_cap_index*>(cap_map()->insert(_cap_id_alloc.alloc(), Fiasco::L4_BASE_THREAD_CAP));
Core_cap_index* irqi =
reinterpret_cast<Core_cap_index*>(cap_map()->insert(_cap_id_alloc.alloc()));
/* setup pd object for core pd */
_core_pd = new(core_mem_alloc()) Platform_pd(false, Fiasco::L4_BASE_TASK_CAP);
_core_pd = new(core_mem_alloc())
Platform_pd(reinterpret_cast<Core_cap_index*>(pdi));
/*
* We setup the thread object for thread0 in core pd using a special
* interface that allows us to specify the capability slot.
*/
Platform_thread *core_thread = new(core_mem_alloc())
Platform_thread(Fiasco::L4_BASE_THREAD_CAP, "core.main");
Platform_thread(thi, irqi, "core.main");
core_thread->pager(sigma0());
core_thread->pager(&_sigma0);
_core_pd->bind_thread(core_thread);
}

View File

@ -37,38 +37,6 @@ static addr_t core_utcb_base() {
}
/****************************
** Private object members **
****************************/
void Platform_pd::_create_pd(bool syscall)
{
if (!Cap_dst_policy::valid(_l4_task_cap))
_l4_task_cap = cap_alloc()->alloc();
if (syscall) {
if (!_l4_task_cap)
panic("no cap slot for pd creation available!");
l4_fpage_t utcb_area = l4_fpage(UTCB_AREA_START,
log2<unsigned>(UTCB_AREA_SIZE), 0);
l4_msgtag_t tag = l4_factory_create_task(L4_BASE_FACTORY_CAP,
_l4_task_cap, utcb_area);
if (l4_msgtag_has_error(tag))
panic("pd creation failed");
}
}
void Platform_pd::_destroy_pd()
{
l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(_l4_task_cap, 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
}
/***************************
** Public object members **
***************************/
@ -86,10 +54,15 @@ int Platform_pd::bind_thread(Platform_thread *thread)
thread->_utcb =
reinterpret_cast<l4_utcb_t*>(UTCB_AREA_START + i * L4_UTCB_OFFSET);
Native_thread cap_offset = THREADS_BASE_CAP + i * THREAD_CAP_SLOT;
thread->_remote_gate_cap = Native_capability(cap_offset + THREAD_GATE_CAP,
thread->_gate_cap.local_name());
thread->_remote_pager_cap = cap_offset + THREAD_PAGER_CAP;
thread->_remote_irq_cap = cap_offset + THREAD_IRQ_CAP;
thread->_gate.remote = cap_offset + THREAD_GATE_CAP;
thread->_pager.remote = cap_offset + THREAD_PAGER_CAP;
thread->_irq.remote = cap_offset + THREAD_IRQ_CAP;
/* if it's no core-thread we have to map parent and pager gate cap */
if (!thread->core_thread()) {
_task.map(_task.local->kcap());
_parent.map(_task.local->kcap());
}
/* inform thread about binding */
thread->bind(this);
@ -116,49 +89,33 @@ void Platform_pd::unbind_thread(Platform_thread *thread)
int Platform_pd::assign_parent(Native_capability parent)
{
if (_parent.valid()) return -1;
_parent = parent;
if (!parent.valid()) return -1;
_parent.local = reinterpret_cast<Core_cap_index*>(parent.idx());
_parent.remote = PARENT_CAP;
return 0;
}
void Platform_pd::map_parent_cap()
Platform_pd::Platform_pd(Core_cap_index* i)
: _task(i, TASK_CAP)
{
if (!_parent_cap_mapped) {
l4_msgtag_t tag = l4_task_map(_l4_task_cap, L4_BASE_TASK_CAP,
l4_obj_fpage(_parent.dst(), 0, L4_FPAGE_RWX),
PARENT_CAP | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PWRN("mapping parent cap failed");
_parent_cap_mapped = true;
}
for (unsigned i = 0; i < THREAD_MAX; i++)
_threads[i] = (Platform_thread*) 0;
}
void Platform_pd::map_task_cap()
{
if (!_task_cap_mapped) {
l4_msgtag_t tag = l4_task_map(_l4_task_cap, L4_BASE_TASK_CAP,
l4_obj_fpage(_l4_task_cap, 0, L4_FPAGE_RWX),
TASK_CAP | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PWRN("mapping task cap failed");
_task_cap_mapped = true;
}
}
Platform_pd::Platform_pd(bool create, Native_task task_cap)
: _l4_task_cap(task_cap),
_badge(create ? Badge_allocator::allocator()->alloc() : 0),
_parent_cap_mapped(false),
_task_cap_mapped(false)
Platform_pd::Platform_pd()
: _task(true, TASK_CAP)
{
for (unsigned i = 0; i < THREAD_MAX; i++)
_threads[i] = (Platform_thread*) 0;
_create_pd(create);
l4_fpage_t utcb_area = l4_fpage(UTCB_AREA_START,
log2<unsigned>(UTCB_AREA_SIZE), 0);
l4_msgtag_t tag = l4_factory_create_task(L4_BASE_FACTORY_CAP,
_task.local->kcap(), utcb_area);
if (l4_msgtag_has_error(tag))
PERR("pd creation failed");
}
@ -168,7 +125,4 @@ Platform_pd::~Platform_pd()
if (_threads[i])
_threads[i]->unbind();
}
_destroy_pd();
Badge_allocator::allocator()->free(_badge);
}

View File

@ -38,30 +38,25 @@ using namespace Fiasco;
int Platform_thread::start(void *ip, void *sp)
{
if (_pager && _platform_pd) {
/* map pager cap */
l4_msgtag_t tag = l4_task_map(_platform_pd->native_task(), L4_BASE_TASK_CAP,
l4_obj_fpage(_pager->cap().dst(), 0, L4_FPAGE_RWX),
_remote_pager_cap | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PWRN("mapping pager cap failed");
}
/* map the pager cap */
if (_platform_pd)
_pager.map(_platform_pd->native_task().dst());
/* reserve utcb area and associate thread with this task */
l4_thread_control_start();
l4_thread_control_pager(_remote_pager_cap);
l4_thread_control_exc_handler(_remote_pager_cap);
l4_thread_control_bind(_utcb, _platform_pd->native_task());
l4_msgtag_t tag = l4_thread_control_commit(_thread_cap.dst());
l4_thread_control_pager(_pager.remote);
l4_thread_control_exc_handler(_pager.remote);
l4_thread_control_bind(_utcb, _platform_pd->native_task().dst());
l4_msgtag_t tag = l4_thread_control_commit(_thread.local->kcap());
if (l4_msgtag_has_error(tag)) {
PWRN("l4_thread_control_commit for %lx failed!",
(unsigned long) _thread_cap.dst());
(unsigned long) _thread.local->kcap());
return -1;
}
/* set ip and sp and run the thread */
tag = l4_thread_ex_regs(_thread_cap.dst(), (l4_addr_t) ip, (l4_addr_t) sp, 0);
tag = l4_thread_ex_regs(_thread.local->kcap(), (l4_addr_t) ip,
(l4_addr_t) sp, 0);
if (l4_msgtag_has_error(tag)) {
PWRN("l4_thread_ex_regs failed!");
return -1;
@ -73,33 +68,33 @@ int Platform_thread::start(void *ip, void *sp)
void Platform_thread::pause()
{
if (!_pager)
if (!_pager_obj)
return;
_pager->state.lock.lock();
_pager_obj->state.lock.lock();
if (_pager->state.paused == true) {
_pager->state.lock.unlock();
if (_pager_obj->state.paused == true) {
_pager_obj->state.lock.unlock();
return;
}
unsigned exc = _pager->state.exceptions;
_pager->state.ip = ~0UL;
_pager->state.sp = ~0UL;
unsigned exc = _pager_obj->state.exceptions;
_pager_obj->state.ip = ~0UL;
_pager_obj->state.sp = ~0UL;
l4_umword_t flags = L4_THREAD_EX_REGS_TRIGGER_EXCEPTION;
/* Mark thread to be stopped */
_pager->state.paused = true;
_pager_obj->state.paused = true;
/*
* Force the thread to be paused to trigger an exception.
* The pager thread, which also acts as exception handler, will
* leave the thread in exception state until, it gets woken again
*/
l4_thread_ex_regs_ret(_thread_cap.dst(), &_pager->state.ip,
&_pager->state.sp, &flags);
l4_thread_ex_regs_ret(_thread.local->kcap(), &_pager_obj->state.ip,
&_pager_obj->state.sp, &flags);
bool in_syscall = flags == 0;
_pager->state.lock.unlock();
_pager_obj->state.lock.unlock();
/**
* Check whether the thread was in ongoing ipc, if so it won't raise
@ -110,185 +105,157 @@ void Platform_thread::pause()
* Wait until the pager thread got an exception from
* the requested thread, and stored its thread state
*/
while (exc == _pager->state.exceptions && !_pager->state.in_exception)
l4_thread_switch(_thread_cap.dst());
while (exc == _pager_obj->state.exceptions && !_pager_obj->state.in_exception)
l4_thread_switch(_thread.local->kcap());
}
}
void Platform_thread::resume()
{
if (!_pager)
if (!_pager_obj)
return;
_pager->state.lock.lock();
_pager_obj->state.lock.lock();
/* Mark thread to be runable again */
_pager->state.paused = false;
_pager->state.lock.unlock();
_pager_obj->state.paused = false;
_pager_obj->state.lock.unlock();
/* Send a message to the exception handler, to unblock the client */
Msgbuf<16> snd, rcv;
Ipc_client ipc_client(_pager->cap(), &snd, &rcv);
ipc_client << _pager << IPC_CALL;
Ipc_client ipc_client(_pager_obj->cap(), &snd, &rcv);
ipc_client << _pager_obj << IPC_CALL;
}
void Platform_thread::bind(Platform_pd *pd)
{
l4_msgtag_t tag;
Native_task task = pd->native_task();
_platform_pd = pd;
if (!_core_thread) {
/* map parent and task cap if it doesn't happen already */
_platform_pd->map_task_cap();
_platform_pd->map_parent_cap();
}
if (_gate_cap.valid()) {
/* map thread's gate cap */
tag = l4_task_map(task, L4_BASE_TASK_CAP,
l4_obj_fpage(_gate_cap.dst(), 0, L4_FPAGE_RWX),
_remote_gate_cap.dst() | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PWRN("mapping thread's gate cap failed");
}
/* map thread's irq cap */
tag = l4_task_map(task, L4_BASE_TASK_CAP,
l4_obj_fpage(_irq_cap, 0, L4_FPAGE_RWX),
_remote_irq_cap | L4_ITEM_MAP);
if (l4_msgtag_has_error(tag))
PWRN("mapping thread's irq cap failed");
_gate.map(pd->native_task().dst());
_irq.map(pd->native_task().dst());
}
void Platform_thread::unbind()
{
l4_thread_ex_regs(_thread_cap.dst(), 0, 0, 0);
l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(_gate_cap.dst(), 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(_thread_cap.dst(), 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
/* first set the thread as its own pager */
l4_thread_control_start();
l4_thread_control_pager(_gate.remote);
l4_thread_control_exc_handler(_gate.remote);
if (l4_msgtag_has_error(l4_thread_control_commit(_thread.local->kcap())))
PWRN("l4_thread_control_commit for %lx failed!",
(unsigned long) _thread.local->kcap());
/* now force it into a pagefault */
l4_thread_ex_regs(_thread.local->kcap(), 0, 0, L4_THREAD_EX_REGS_CANCEL);
_platform_pd = (Platform_pd*) 0;
}
void Platform_thread::pager(Pager_object *pager)
void Platform_thread::pager(Pager_object *pager_obj)
{
_pager = pager;
_pager_obj = pager_obj;
_pager.local = reinterpret_cast<Core_cap_index*>(pager_obj->cap().idx());
}
int Platform_thread::state(Thread_state *state_dst)
{
if (_pager)
*state_dst = _pager->state;
if (_pager_obj)
*state_dst = _pager_obj->state;
state_dst->kcap = _gate.remote;
state_dst->id = _gate.local->id();
state_dst->utcb = _utcb;
state_dst->cap = _remote_gate_cap;
return 0;
}
void Platform_thread::cancel_blocking()
{
l4_irq_trigger(_irq_cap);
l4_irq_trigger(_irq.local->kcap());
}
void Platform_thread::_create_thread()
{
l4_msgtag_t tag = l4_factory_create_thread(L4_BASE_FACTORY_CAP,
_thread_cap.dst());
_thread.local->kcap());
if (l4_msgtag_has_error(tag))
PERR("cannot create more thread kernel-objects!");
/* create initial gate for thread */
_gate.local = reinterpret_cast<Core_cap_index*>(Cap_session_component::alloc(0, _thread.local).idx());
}
void Platform_thread::_finalize_construction(const char *name, unsigned prio)
{
/* create irq for new thread */
_irq_cap = cap_alloc()->alloc();
l4_msgtag_t tag = l4_factory_create_irq(L4_BASE_FACTORY_CAP, _irq_cap);
l4_msgtag_t tag = l4_factory_create_irq(L4_BASE_FACTORY_CAP,
_irq.local->kcap());
if (l4_msgtag_has_error(tag))
PWRN("creating thread's irq failed");
/* attach thread to irq */
tag = l4_irq_attach(_irq_cap, 0, _thread_cap.dst());
tag = l4_irq_attach(_irq.local->kcap(), 0, _thread.local->kcap());
if (l4_msgtag_has_error(tag))
PWRN("attaching thread's irq failed");
/* set human readable name in kernel debugger */
strncpy(_name, name, sizeof(_name));
Fiasco::l4_debugger_set_object_name(_thread_cap.dst(), name);
Fiasco::l4_debugger_set_object_name(_thread.local->kcap(), name);
/* set priority of thread */
prio = Cpu_session::scale_priority(DEFAULT_PRIORITY, prio);
l4_sched_param_t params = l4_sched_param(prio);
l4_scheduler_run_thread(L4_BASE_SCHEDULER_CAP, _thread_cap.dst(), &params);
l4_scheduler_run_thread(L4_BASE_SCHEDULER_CAP, _thread.local->kcap(),
&params);
}
Platform_thread::Platform_thread(const char *name,
unsigned prio)
: _core_thread(false),
_badge(Badge_allocator::allocator()->alloc()),
_thread_cap(cap_alloc()->alloc_id(_badge),
_badge),
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
_thread(true),
_irq(true),
_utcb(0),
_platform_pd(0),
_pager(0)
_pager_obj(0)
{
/* register the thread capability */
Capability_tree::tree()->insert(&_node);
_thread.local->pt(this);
_create_thread();
/* create gate for new thread */
_gate_cap = core_env()->cap_session()->alloc(_thread_cap);
_finalize_construction(name, prio);
}
Platform_thread::Platform_thread(Native_thread cap, const char *name)
Platform_thread::Platform_thread(Core_cap_index* thread,
Core_cap_index* irq, const char *name)
: _core_thread(true),
_thread_cap(cap, -1),
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
_thread(thread, L4_BASE_THREAD_CAP),
_irq(irq),
_utcb(0),
_platform_pd(0),
_pager(0)
_pager_obj(0)
{
/* register the thread capability */
Capability_tree::tree()->insert(&_node);
_thread.local->pt(this);
_finalize_construction(name, 0);
}
Platform_thread::Platform_thread(const char *name)
: _core_thread(true),
_badge(Badge_allocator::allocator()->alloc()),
_thread_cap(cap_alloc()->alloc_id(_badge),
_badge),
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
_thread(true),
_irq(true),
_utcb(0),
_platform_pd(0),
_pager(0)
_pager_obj(0)
{
/* register the thread capability */
Capability_tree::tree()->insert(&_node);
_thread.local->pt(this);
_create_thread();
/* create gate for new thread */
_gate_cap = Cap_session_component::alloc(0, _thread_cap);
_finalize_construction(name, 0);
}
@ -301,9 +268,4 @@ Platform_thread::~Platform_thread()
*/
if (_platform_pd)
_platform_pd->unbind_thread(this);
/* remove the thread capability */
Capability_tree::tree()->remove(&_node);
cap_alloc()->free(_thread_cap.dst());
Badge_allocator::allocator()->free(_badge);
}

View File

@ -14,12 +14,11 @@
/* Genode includes */
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
#include <base/native_types.h>
/* core includes */
#include <signal_session_component.h>
#include <cap_session_component.h>
#include <platform.h>
namespace Fiasco {
#include <l4/sys/factory.h>
@ -65,15 +64,13 @@ Signal_source::Signal Signal_source_component::wait_for_signal()
Signal_source_component::Signal_source_component(Rpc_entrypoint *ep)
: _entrypoint(ep)
: Signal_source_rpc_object(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
_entrypoint(ep)
{
using namespace Fiasco;
unsigned long badge = Badge_allocator::allocator()->alloc();
Native_thread_id irq = cap_alloc()->alloc_id(badge);
l4_msgtag_t res = l4_factory_create_irq(L4_BASE_FACTORY_CAP, irq);
l4_msgtag_t res = l4_factory_create_irq(L4_BASE_FACTORY_CAP,
_blocking_semaphore.dst());
if (l4_error(res))
PERR("Allocation of irq object failed!");
_blocking_semaphore = Native_capability(irq, badge);
}

View File

@ -30,6 +30,7 @@ SRC_CC = main.cc \
signal_source_component.cc \
dump_alloc.cc \
context_area.cc \
cap_map.cc \
cap_session_component.cc \
cpu_session_extension.cc \
pd_session_extension.cc \
@ -55,5 +56,6 @@ vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath thread.cc $(REP_DIR)/src/base/thread
vpath thread_bootstrap.cc $(REP_DIR)/src/base/thread
vpath cap_map.cc $(REP_DIR)/src/base/env
vpath spin_lock.cc $(REP_DIR)/src/base/env
vpath %.cc $(REP_DIR)/src/core

View File

@ -44,19 +44,16 @@ void Thread_base::start()
new(platform()->core_mem_alloc()) Platform_thread(_context->name);
platform_specific()->core_pd()->bind_thread(pt);
_tid = pt->gate().dst();
_thread_cap = reinterpret_cap_cast<Cpu_thread>(pt->thread_cap());
_tid = pt->gate().remote;
_thread_cap =
reinterpret_cap_cast<Cpu_thread>(Native_capability(pt->thread().local));
pt->pager(platform_specific()->core_pager());
pt->start((void *)_thread_start, _context->stack);
/*
* send newly constructed thread, pointer to its Thread_base object,
* and its badge
*/
Msgbuf<128> snd_msg, rcv_msg;
Ipc_client cli(_thread_cap, &snd_msg, &rcv_msg);
cli << (addr_t)this << pt->gate().local_name() << IPC_CALL;
_context->utcb = pt->utcb();
l4_utcb_tcr_u(pt->utcb())->user[UTCB_TCR_BADGE] = pt->gate().local->id();
l4_utcb_tcr_u(pt->utcb())->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
pt->start((void *)_thread_start, _context->stack);
}

View File

@ -16,14 +16,21 @@
/* Genode includes */
#include <base/stdint.h>
#include <base/native_types.h>
#include <base/cap_map.h>
namespace Fiasco {
#include <l4/sys/utcb.h>
#include <l4/sys/kdebug.h>
}
enum { MAIN_THREAD_CAP_ID = 1 };
static void main_thread_bootstrap() {
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = MAIN_THREAD_CAP_ID;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
Genode::cap_map()->insert(MAIN_THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP);
}
static void main_thread_bootstrap() {
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0; }
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@ -21,15 +21,10 @@ namespace Genode {
/**
* Return constructed parent capability
*/
Parent_capability parent_cap()
{
Native_capability cap;
memcpy(&cap, (void *)&_parent_cap, sizeof(cap));
/* assemble parent capability from object ID and Fiasco cap */
return reinterpret_cap_cast<Parent>(
Native_capability(Fiasco::PARENT_CAP, cap.local_name()));
}
Parent_capability parent_cap() {
static Cap_index* i = cap_map()->insert(*((int*)&_parent_cap),
Fiasco::PARENT_CAP);
return reinterpret_cap_cast<Parent>(Native_capability(i)); }
}
#endif /* _PLATFORM__MAIN_PARENT_CAP_H_ */

View File

@ -16,7 +16,7 @@
/* Genode includes */
#include <dataspace/client.h>
#include <base/cap_sel_alloc.h>
#include <base/cap_map.h>
#include <util/avl_tree.h>
namespace Fiasco {
@ -50,7 +50,7 @@ namespace L4lx {
Genode::size_t size,
Genode::Dataspace_capability ds)
: _name(name), _size(size), _cap(ds),
_ref(Genode::cap_alloc()->alloc()) {}
_ref(Genode::cap_idx_alloc()->alloc(1)->kcap()) {}
/***************

View File

@ -18,6 +18,7 @@
#include <base/ipc.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <base/cap_map.h>
#include <foc_cpu_session/connection.h>
namespace Fiasco {
@ -35,30 +36,12 @@ namespace L4lx {
void (*_func)(void *data);
void *_data;
Fiasco::l4_utcb_t *_utcb;
Genode::addr_t _vcpu_state;
static void _startup()
{
using namespace Genode;
using namespace Fiasco;
/* receive thread_base object pointer, and store it in TLS */
addr_t thread_base = 0;
Msgbuf<128> snd_msg, rcv_msg;
Ipc_server srv(&snd_msg, &rcv_msg);
srv >> IPC_WAIT >> thread_base;
l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ] = thread_base;
Vcpu* me = dynamic_cast<Vcpu*>(Thread_base::myself());
me->_utcb = l4_utcb();
l4_utcb_tcr()->user[0] = me->tid(); /* L4X_UTCB_TCR_ID */
srv << IPC_REPLY;
/* start thread function */
Vcpu* vcpu = reinterpret_cast<Vcpu*>(thread_base);
Vcpu* vcpu = reinterpret_cast<Vcpu*>(Genode::Thread_base::myself());
vcpu->entry();
}
@ -79,12 +62,12 @@ namespace L4lx {
: Genode::Thread_base(name, stack_size),
_func(func),
_data(data),
_utcb(0),
_vcpu_state(vcpu_state) { start(); }
void start()
{
using namespace Genode;
using namespace Fiasco;
/* create thread at core */
char buf[48];
@ -99,6 +82,17 @@ namespace L4lx {
env()->rm_session()->add_client(_thread_cap);
vcpu_connection()->set_pager(_thread_cap, pager_cap);
/* get gate-capability and badge of new thread */
Thread_state state;
vcpu_connection()->state(_thread_cap, &state);
_tid = state.kcap;
_context->utcb = state.utcb;
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_BADGE] = state.id;
l4_utcb_tcr_u(state.utcb)->user[0] = state.kcap; /* L4X_UTCB_TCR_ID */
cap_map()->insert(state.id, state.kcap);
/* register initial IP and SP at core */
addr_t stack = (addr_t)&_context->stack[-4];
stack &= ~0xf; /* align initial stack to 16 byte boundary */
@ -106,18 +100,9 @@ namespace L4lx {
if (_vcpu_state)
vcpu_connection()->enable_vcpu(_thread_cap, _vcpu_state);
/* get gate-capability and badge of new thread */
Thread_state state;
vcpu_connection()->state(_thread_cap, &state);
_tid = state.cap.dst();
Msgbuf<128> snd_msg, rcv_msg;
Ipc_client cli(state.cap, &snd_msg, &rcv_msg);
cli << (addr_t)this << IPC_CALL;
}
Fiasco::l4_utcb_t *utcb() { return _utcb; };
Fiasco::l4_utcb_t *utcb() { return _context->utcb; };
};
}

View File

@ -13,7 +13,7 @@
/* Genode includes */
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
#include <base/cap_map.h>
namespace Fiasco {
#include <l4/re/c/util/cap.h>
@ -28,7 +28,7 @@ extern "C" {
l4_cap_idx_t l4re_util_cap_alloc(void)
{
l4_cap_idx_t ret = Genode::cap_alloc()->alloc();
l4_cap_idx_t ret = Genode::cap_idx_alloc()->alloc(1)->kcap();
if (DEBUG)
PDBG("ret=%lx", ret);

View File

@ -14,7 +14,6 @@
/* Genode includes */
#include <base/printf.h>
#include <base/snprintf.h>
#include <base/cap_sel_alloc.h>
#include <env.h>
#include <l4lx_irq.h>

View File

@ -13,7 +13,7 @@
/* Genode includes */
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
#include <base/cap_map.h>
#include <env.h>
#include <l4lx_task.h>
@ -65,7 +65,8 @@ l4_cap_idx_t l4lx_task_number_allocate(void)
*/
int l4lx_task_number_free(l4_cap_idx_t task)
{
Genode::cap_alloc()->free(task);
Genode::Cap_index* idx = Genode::cap_idx_alloc()->kcap_to_idx(task);
Genode::cap_idx_alloc()->free(idx, 1);
return 0;
}
@ -84,7 +85,7 @@ int l4lx_task_number_free(l4_cap_idx_t task)
int l4lx_task_get_new_task(l4_cap_idx_t parent_id,
l4_cap_idx_t *id)
{
*id = Genode::cap_alloc()->alloc();
*id = Genode::cap_idx_alloc()->alloc(1)->kcap();
return 0;
}