Clean up base-library structure

This patch moves the base library from src/base to src/lib/base,
flattens the library-internal directory structure, and moves the common
parts of the library-description files to base/lib/mk/base.inc and
base/lib/mk/base-common.inc.

Furthermore, the patch fixes a few cosmetic issues (whitespace and
comments only) that I encountered while browsing the result.

Fixes #1952
This commit is contained in:
Norman Feske
2016-04-29 13:23:19 +02:00
parent 52cc50174f
commit 40a5af42eb
134 changed files with 183 additions and 458 deletions

View File

@ -0,0 +1,23 @@
/*
* \brief Implementation of the cache operations
* \author Christian Prochaska
* \date 2014-05-13
*/
/*
* 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.
*/
namespace Fiasco {
#include <l4/sys/cache.h>
}
#include <cpu/cache.h>
void Genode::cache_coherent(Genode::addr_t addr, Genode::size_t size)
{
Fiasco::l4_cache_coherent(addr, addr + size);
}

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-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/cap_alloc.h>
Genode::Cap_index_allocator* Genode::cap_idx_alloc()
{
static Genode::Cap_index_allocator_tpl<Cap_index,4096> alloc;
return &alloc;
}

View File

@ -0,0 +1,183 @@
/*
* \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-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/cap_map.h>
#include <base/native_types.h>
#include <util/assert.h>
/* base-internal includes */
#include <base/internal/spin_lock.h>
/* kernel includes */
namespace Fiasco {
#include <l4/sys/consts.h>
#include <l4/sys/task.h>
}
/***********************
** Cap_index class **
***********************/
static volatile int _cap_index_spinlock = SPINLOCK_UNLOCKED;
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::uint8_t Genode::Cap_index::inc()
{
/* con't ref-count index that are controlled by core */
if (cap_idx_alloc()->static_idx(this))
return 1;
spinlock_lock(&_cap_index_spinlock);
Genode::uint8_t ret = ++_ref_cnt;
spinlock_unlock(&_cap_index_spinlock);
return ret;
}
Genode::uint8_t Genode::Cap_index::dec()
{
/* con't ref-count index that are controlled by core */
if (cap_idx_alloc()->static_idx(this))
return 1;
spinlock_lock(&_cap_index_spinlock);
Genode::uint8_t ret = --_ref_cnt;
spinlock_unlock(&_cap_index_spinlock);
return ret;
}
/****************************
** Capability_map class **
****************************/
Genode::Cap_index* Genode::Capability_map::find(int id)
{
Genode::Lock_guard<Spin_lock> guard(_lock);
return _tree.first() ? _tree.first()->find_by_id(id) : 0;
}
Genode::Cap_index* Genode::Capability_map::insert(int id)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
ASSERT(!_tree.first() || !_tree.first()->find_by_id(id),
"Double insertion in cap_map()!");
Cap_index *i = cap_idx_alloc()->alloc_range(1);
if (i) {
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);
/* remove potentially existent entry */
Cap_index *i = _tree.first() ? _tree.first()->find_by_id(id) : 0;
if (i)
_tree.remove(i);
i = cap_idx_alloc()->alloc(kcap);
if (i) {
i->id(id);
_tree.insert(i);
}
return i;
}
Genode::Cap_index* Genode::Capability_map::insert_map(int id, addr_t kcap)
{
using namespace Genode;
using namespace Fiasco;
Lock_guard<Spin_lock> guard(_lock);
/* check whether capability id exists */
Cap_index *i = _tree.first() ? _tree.first()->find_by_id(id) : 0;
/* if we own the capability already check whether it's the same */
if (i) {
l4_msgtag_t tag = l4_task_cap_equal(L4_BASE_TASK_CAP, i->kcap(), kcap);
if (!l4_msgtag_label(tag)) {
/*
* they aren't equal, possibly an already revoked cap,
* otherwise it's a fake capability and we return an invalid one
*/
tag = l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap());
if (l4_msgtag_label(tag))
return 0;
else
/* it's invalid so remove it from the tree */
_tree.remove(i);
} else
/* they are equal so just return the one in the map */
return i;
}
/* the capability doesn't exists in the map so allocate a new one */
i = cap_idx_alloc()->alloc_range(1);
if (!i)
return 0;
/* set it's id and insert it into the tree */
i->id(id);
_tree.insert(i);
/* map the given cap to our registry entry */
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP,
l4_obj_fpage(kcap, 0, L4_FPAGE_RWX),
i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT);
return i;
}
Genode::Capability_map* Genode::cap_map()
{
static Genode::Capability_map map;
return &map;
}

View File

@ -0,0 +1,30 @@
/*
* \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-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/cap_map.h>
void Genode::Capability_map::remove(Genode::Cap_index* i)
{
using namespace Genode;
Lock_guard<Spin_lock> guard(_lock);
if (i) {
Cap_index* e = _tree.first() ? _tree.first()->find_by_id(i->id()) : 0;
if (e == i)
_tree.remove(i);
cap_idx_alloc()->free(i, 1);
}
}

View File

@ -0,0 +1,378 @@
/*
* \brief Implementation of the IPC API for Fiasco.OC
* \author Stefan Kalkowski
* \author Norman Feske
* \date 2009-12-03
*/
/*
* 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.
*/
/*
* l4_msgtag_t (size == 1 mword) format:
*
* --------------------------------------------------------------
* | label | 4 Bit flags | 6 Bit items | 6 Bit word count |
* --------------------------------------------------------------
*/
/* Genode includes */
#include <base/blocking.h>
#include <base/ipc.h>
#include <base/ipc_msgbuf.h>
#include <base/thread.h>
#include <util/assert.h>
/* base-internal includes */
#include <base/internal/lock_helper.h> /* for 'thread_get_my_native_id()' */
#include <base/internal/ipc_server.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/consts.h>
#include <l4/sys/ipc.h>
#include <l4/sys/types.h>
#include <l4/sys/utcb.h>
#include <l4/sys/kdebug.h>
}
using namespace Genode;
using namespace Fiasco;
/***************
** Utilities **
***************/
enum Debug { DEBUG_MSG = 1, HALT_ON_ERROR = 0 };
static inline bool ipc_error(l4_msgtag_t tag, bool print)
{
int ipc_error = l4_ipc_error(tag, l4_utcb());
if (ipc_error) {
if (print) {
outstring("Ipc error: ");
outhex32(ipc_error);
outstring(" occurred!\n");
}
if (HALT_ON_ERROR)
enter_kdebug("Ipc error");
return true;
}
return false;
}
enum { INVALID_BADGE = ~0UL };
/**
* Representation of a capability during UTCB marshalling/unmarshalling
*/
struct Cap_info
{
bool valid = false;
unsigned long sel = 0;
unsigned long badge = 0;
};
/**
* Copy message registers from UTCB to destination message buffer
*
* \return protocol word (local name or exception code)
*/
static unsigned long extract_msg_from_utcb(l4_msgtag_t tag,
Receive_window &rcv_window,
Msgbuf_base &rcv_msg)
{
unsigned num_msg_words = l4_msgtag_words(tag);
l4_mword_t const *msg_words = (l4_mword_t const *)l4_utcb_mr();
/* each message has at least the protocol word and the capability count */
if (num_msg_words < 2)
return 0;
/* read badge / exception code from first message word */
unsigned long const protocol_word = *msg_words++;
/* read number of capability arguments from second message word */
unsigned long const num_caps = min(*msg_words, Msgbuf_base::MAX_CAPS_PER_MSG);
msg_words++;
num_msg_words -= 2;
if (num_caps > 0 && num_msg_words < num_caps) {
outstring("unexpected end of message, capability info missing\n");
return 0;
}
/*
* Extract capabilities
*
* The badges are stored in the subsequent message registers. For each
* valid badge, we expect one capability selector to be present in the
* receive window. The content of the receive window is tracked via
* 'sel_idx'. If we encounter an invalid badge, the sender specified
* an invalid capabilty as argument.
*/
unsigned const num_cap_sel = l4_msgtag_items(tag);
Cap_info caps[num_caps];
for (unsigned i = 0, sel_idx = 0; i < num_caps; i++) {
unsigned long const badge = *msg_words++;
if (badge == INVALID_BADGE)
continue;
/* received a delegated capability */
if (sel_idx == num_cap_sel) {
outstring("missing capability selector in message\n");
break;
}
caps[i].badge = badge;
caps[i].valid = true;
caps[i].sel = rcv_window.rcv_cap_sel(sel_idx++);
}
num_msg_words -= num_caps;
/* the remainder of the message contains the regular data payload */
if ((num_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) {
if (DEBUG_MSG)
outstring("receive message buffer too small\n");
num_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t);
}
/* read message payload beginning from the second UTCB message register */
l4_mword_t *dst = (l4_mword_t *)rcv_msg.data();
for (unsigned i = 0; i < num_msg_words; i++)
*dst++ = *msg_words++;
rcv_msg.data_size(sizeof(l4_mword_t)*num_msg_words);
/*
* Insert received capability selectors into cap map.
*
* Note that this operation pollutes the UTCB. Therefore we must perform
* it not before the entire message content is extracted.
*/
for (unsigned i = 0; i < num_caps; i++) {
if (caps[i].valid) {
rcv_msg.insert(Native_capability(cap_map()->insert_map(caps[i].badge,
caps[i].sel)));
} else {
rcv_msg.insert(Native_capability());
}
}
return protocol_word;
}
/**
* Copy message registers from message buffer to UTCB and create message tag.
*
* \param protocol_word badge of invoked object (when a client calls a server)
* or the exception code (when a server replies to a
* client)
*/
static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg,
unsigned long protocol_word)
{
unsigned const num_data_words = snd_msg.data_size() / sizeof(l4_mword_t);
unsigned const num_caps = snd_msg.used_caps();
/* validate capabilities present in the message buffer */
for (unsigned i = 0; i < num_caps; i++) {
Native_capability &cap = snd_msg.cap(i);
if (!cap.valid())
continue;
if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())))
cap = Native_capability();
}
/*
* Obtain capability info from message buffer
*
* This step must be performed prior any write operation to the UTCB
* because the 'Genode::Capability' operations may indirectly trigger
* system calls, which pollute the UTCB.
*/
Cap_info caps[num_caps];
for (unsigned i = 0; i < num_caps; i++) {
Native_capability const &cap = snd_msg.cap(i);
if (cap.valid()) {
caps[i].valid = true;
caps[i].badge = cap.local_name();
caps[i].sel = cap.dst();
}
}
/*
* The message consists of a protocol word, the capability count, one badge
* value per capability, and the data payload.
*/
unsigned const num_msg_words = 2 + num_caps + num_data_words;
if (num_msg_words > L4_UTCB_GENERIC_DATA_SIZE) {
outstring("receive message buffer too small\n");
throw Ipc_error();
}
l4_mword_t *msg_words = (l4_mword_t *)l4_utcb_mr();
*msg_words++ = protocol_word;
*msg_words++ = num_caps;
unsigned num_cap_sel = 0;
for (unsigned i = 0; i < num_caps; i++) {
Native_capability const &cap = snd_msg.cap(i);
/* store badge as normal message word */
*msg_words++ = caps[i].valid ? caps[i].badge : INVALID_BADGE;
/* setup flexpage for valid capability to delegate */
if (caps[i].valid) {
unsigned const idx = num_msg_words + 2*num_cap_sel;
l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/;
l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(caps[i].sel,
0, L4_FPAGE_RWX).raw;
num_cap_sel++;
}
}
/* store message data into UTCB message registers */
for (unsigned i = 0; i < num_data_words; i++)
*msg_words++ = snd_msg.word(i);
return l4_msgtag(0, num_msg_words, num_cap_sel, 0);
}
/****************
** IPC client **
****************/
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
Receive_window rcv_window;
rcv_window.init();
rcv_msg.reset();
/* copy call message to the UTCBs message registers */
l4_msgtag_t const call_tag = copy_msgbuf_to_utcb(snd_msg, dst.local_name());
addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) {
l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP;
rcv_cap_sel += L4_CAP_SIZE;
}
l4_msgtag_t const reply_tag =
l4_ipc_call(dst.dst(), l4_utcb(), call_tag, L4_IPC_NEVER);
if (l4_ipc_error(reply_tag, l4_utcb()) == L4_IPC_RECANCELED)
throw Genode::Blocking_canceled();
if (ipc_error(reply_tag, DEBUG_MSG))
throw Genode::Ipc_error();
return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_window, rcv_msg));
}
/****************
** IPC server **
****************/
static bool badge_matches_label(unsigned long badge, unsigned long label)
{
return badge == (label & (~0UL << 2));
}
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
l4_msgtag_t tag = copy_msgbuf_to_utcb(snd_msg, exc.value);
tag = l4_ipc_send(L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_SEND_TIMEOUT_0);
ipc_error(tag, DEBUG_MSG);
}
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
Receive_window &rcv_window = Thread_base::myself()->native_thread().rcv_window;
for (;;) {
request_msg.reset();
/* prepare receive window in UTCB */
addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) {
l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP;
rcv_cap_sel += L4_CAP_SIZE;
}
l4_utcb_br()->bdr &= ~L4_BDR_OFFSET_MASK;
l4_msgtag_t request_tag;
l4_umword_t label = 0; /* kernel-protected label of invoked capability */
if (exc.value != Rpc_exception_code::INVALID_OBJECT) {
l4_msgtag_t const reply_tag = copy_msgbuf_to_utcb(reply_msg, exc.value);
request_tag = l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, L4_IPC_SEND_TIMEOUT_0);
} else {
request_tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER);
}
if (ipc_error(request_tag, false))
continue;
/* copy request message from the UTCBs message registers */
unsigned long const badge =
extract_msg_from_utcb(request_tag, rcv_window, request_msg);
/* ignore request if we detect a forged badge */
if (!badge_matches_label(badge, label)) {
outstring("badge does not match label, ignoring request\n");
continue;
}
return Rpc_request(Native_capability(), badge);
}
}
Ipc_server::Ipc_server()
:
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE])
{
Thread_base::myself()->native_thread().rcv_window.init();
}
Ipc_server::~Ipc_server() { }

View File

@ -0,0 +1,29 @@
/*
* \brief Spin-lock implementation for environment's capability -allocator.
* \author Stefan Kalkowski
* \date 2012-02-29
*
* This is a Fiasco.OC-specific addition to the process enviroment.
*/
/*
* 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 <base/cap_map.h>
/* base-internal includes */
#include <base/internal/spin_lock.h>
Genode::Spin_lock::Spin_lock() : _spinlock(SPINLOCK_UNLOCKED) {}
void Genode::Spin_lock::lock() { spinlock_lock(&_spinlock); }
void Genode::Spin_lock::unlock() { spinlock_unlock(&_spinlock); }

View File

@ -0,0 +1,59 @@
/*
* \brief Fiasco.OC specific thread bootstrap code
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2011-01-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 <util/construct_at.h>
#include <base/thread.h>
#include <base/sleep.h>
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
using namespace Genode;
enum { THREAD_CAP_ID = 1 };
Cap_index * ci(cap_map()->insert(THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP));
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = (unsigned long)ci;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
}
void prepare_reinit_main_thread()
{
using namespace Genode;
construct_at<Capability_map>(cap_map());
cap_idx_alloc()->reinit();
prepare_init_main_thread();
}
/*****************
** Thread_base **
*****************/
void Genode::Thread_base::_thread_bootstrap() { }
void Genode::Thread_base::_thread_start()
{
using namespace Genode;
Thread_base::myself()->_thread_bootstrap();
Thread_base::myself()->entry();
Thread_base::myself()->_join_lock.unlock();
sleep_forever();
}

View File

@ -0,0 +1,24 @@
/*
* \brief Implementation of the Thread API (foc-specific myself())
* \author Norman Feske
* \date 2015-04-28
*/
/*
* Copyright (C) 2015 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/thread.h>
Genode::Thread_base *Genode::Thread_base::myself()
{
using namespace Fiasco;
return reinterpret_cast<Thread_base*>(l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ]);
}

View File

@ -0,0 +1,104 @@
/*
* \brief Fiasco-specific implementation of the non-core startup Thread API
* \author Norman Feske
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2010-01-19
*/
/*
* 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 <base/thread.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/env.h>
/* base-internal includes */
#include <base/internal/stack.h>
namespace Fiasco {
#include <l4/sys/utcb.h>
}
using namespace Genode;
void Thread_base::_deinit_platform_thread()
{
using namespace Fiasco;
if (native_thread().kcap && _thread_cap.valid()) {
Cap_index *i = (Cap_index*)l4_utcb_tcr_u(utcb()->foc_utcb)->user[UTCB_TCR_BADGE];
cap_map()->remove(i);
_cpu_session->kill_thread(_thread_cap);
}
}
void Thread_base::_init_platform_thread(size_t weight, Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
if (type == NORMAL)
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(env()->pd_session_cap(),
weight, buf);
/* assign thread to protection domain */
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
return;
}
/* adjust values whose computation differs for a main thread */
native_thread().kcap = Fiasco::MAIN_THREAD_CAP;
_thread_cap = env()->parent()->main_thread_cap();
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
/* make thread object known to the Fiasco environment */
addr_t const t = (addr_t)this;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = t;
}
void Thread_base::start()
{
using namespace Fiasco;
/* get gate-capability and badge of new thread */
Thread_state state;
try { state = _cpu_session->state(_thread_cap); }
catch (...) { throw Cpu_session::Thread_creation_failed(); }
/* remember UTCB of the new thread */
Fiasco::l4_utcb_t * const foc_utcb = (Fiasco::l4_utcb_t *)state.utcb;
utcb()->foc_utcb = foc_utcb;
native_thread() = Native_thread(state.kcap);
Cap_index *i = cap_map()->insert(state.id, state.kcap);
l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) i;
l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
/* register initial IP and SP at core */
_cpu_session->start(_thread_cap, (addr_t)_thread_start, _stack->top());
}
void Thread_base::cancel_blocking()
{
_cpu_session->cancel_blocking(_thread_cap);
}