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,188 @@
/*
* \brief Mapping of Genode's capability names to kernel capabilities.
* \author Alexander Boettcher
* \date 2013-08-26
*/
/*
* Copyright (C) 2013-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>
#include <base/printf.h>
/* base-nova specific include */
#include <nova/syscalls.h>
using namespace Genode;
Capability_map *Genode::cap_map()
{
static Genode::Capability_map map;
return &map;
}
/***********************
** Cap_index class **
***********************/
Cap_range *Cap_range::find_by_id(addr_t id)
{
if (_match(id)) return this;
Cap_range *obj = this->child(id > _base);
return obj ? obj->find_by_id(id) : 0;
}
void Cap_range::inc(unsigned id, bool inc_if_one)
{
bool failure = false;
{
Lock::Guard guard(_lock);
if (inc_if_one && _cap_array[id] != 1)
return;
if (_cap_array[id] + 1 == 0)
failure = true;
else
_cap_array[id]++;
}
if (failure)
PERR("cap reference counting error - reference overflow of cap=%lx",
_base + id);
}
void Cap_range::dec(unsigned const id_start, bool revoke, unsigned num_log_2)
{
bool failure = false;
{
unsigned const end = min(id_start + (1U << num_log_2), elements());
Lock::Guard guard(_lock);
for (unsigned id = id_start; id < end; id++) {
if (_cap_array[id] == 0) {
failure = true;
continue;
}
if (revoke && _cap_array[id] == 1)
Nova::revoke(Nova::Obj_crd(_base + id, 0));
_cap_array[id]--;
}
}
if (failure)
PERR("cap reference counting error - one counter of cap range %lx+%x "
"has been already zero", _base + id_start, 1 << num_log_2);
}
addr_t Cap_range::alloc(size_t const num_log2)
{
addr_t const step = 1UL << num_log2;
{
Lock::Guard guard(_lock);
unsigned max = elements();
addr_t last = _last;
do {
/* align i to num_log2 */
unsigned i = ((_base + last + step - 1) & ~(step - 1)) - _base;
unsigned j;
for (; i + step < max; i += step) {
for (j = 0; j < step; j++)
if (_cap_array[i+j])
break;
if (j < step)
continue;
for (j = 0; j < step; j++)
_cap_array[i+j] = 1;
_last = i;
return _base + i;
}
max = last;
last = 0;
} while (max);
}
Cap_range *child = this->child(LEFT);
if (child) {
addr_t res = child->alloc(num_log2);
if (res != ~0UL)
return res;
}
child = this->child(RIGHT);
if (child) {
addr_t res = child->alloc(num_log2);
return res;
}
return ~0UL;
}
/****************************
** Capability_map class **
****************************/
Cap_index Capability_map::find(Genode::addr_t id) {
return Cap_index(_tree.first() ? _tree.first()->find_by_id(id) : 0, id); }
addr_t Capability_map::insert(size_t const num_log_2, addr_t const sel)
{
if (sel == ~0UL)
return _tree.first() ? _tree.first()->alloc(num_log_2) : ~0UL;
Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0;
if (!range)
return ~0UL;
for (unsigned i = 0; i < 1UL << num_log_2; i++)
range->inc(sel + i - range->base());
return sel;
}
void Capability_map::remove(Genode::addr_t const sel, uint8_t num_log_2,
bool revoke)
{
Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0;
if (!range)
return;
range->dec(sel - range->base(), revoke, num_log_2);
Genode::addr_t last_sel = sel + (1UL << num_log_2);
Genode::addr_t last_range = range->base() + range->elements();
while (last_sel > last_range) {
uint8_t left_log2 = log2(last_sel - last_range);
remove(last_range, left_log2, revoke);
last_range += 1UL << left_log2;
}
}

View File

@ -0,0 +1,74 @@
/*
* \brief Implementation of the IPC API for NOVA
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/ipc.h>
#include <base/thread.h>
#include <base/printf.h>
/* base-internal includes */
#include <base/internal/ipc.h>
using namespace Genode;
/****************
** 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_msg.reset();
/* update receive window for capability selectors if needed */
if (rcv_caps != ~0UL) {
/* calculate max order of caps to be received during reply */
unsigned short log2_max = rcv_caps ? log2(rcv_caps) : 0;
if ((1U << log2_max) < rcv_caps) log2_max ++;
rcv_window.rcv_wnd(log2_max);
}
Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb();
/* the protocol value is unused as the badge is delivered by the kernel */
if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) {
PERR("could not setup IPC");
throw Ipc_error();
}
/* if we can't setup receive window, die in order to recognize the issue */
if (!rcv_window.prepare_rcv_window(utcb, dst.rcv_window()))
/* printf doesn't work here since for IPC also rcv_prepare* is used */
nova_die();
/* establish the mapping via a portal traversal */
uint8_t res = Nova::call(dst.local_name());
if (res != Nova::NOVA_OK) {
/* If an error occurred, reset word&item count (not done by kernel). */
utcb.set_msg_word(0);
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
}
rcv_window.post_ipc(utcb, dst.rcv_window());
/* handle malformed reply from a server */
if (utcb.msg_words() < 1)
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_window, rcv_msg));
}

View File

@ -0,0 +1,52 @@
/*
* \brief Client-side region map stub
* \author Norman Feske
* \author Alexander Boettcher
* \date 2016-01-22
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <region_map/client.h>
using namespace Genode;
Region_map_client::Region_map_client(Capability<Region_map> session)
: Rpc_client<Region_map>(session) { }
Region_map::Local_addr
Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr,
bool executable)
{
return call<Rpc_attach>(ds, size, offset, use_local_addr, local_addr,
executable);
}
void Region_map_client::detach(Local_addr local_addr) {
call<Rpc_detach>(local_addr); }
void Region_map_client::fault_handler(Signal_context_capability cap) {
call<Rpc_fault_handler>(cap); }
Region_map::State Region_map_client::state() { return call<Rpc_state>(); }
Dataspace_capability Region_map_client::dataspace()
{
if (!_rm_ds_cap.valid())
_rm_ds_cap = call<Rpc_dataspace>();
return _rm_ds_cap;
}

View File

@ -0,0 +1,56 @@
/*
* \brief Core-specific back end of the RPC entrypoint
* \author Norman Feske
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <util/retry.h>
#include <base/rpc_server.h>
#include <pd_session/client.h>
/* NOVA-specific part of the PD session interface */
#include <nova_native_pd/client.h>
using namespace Genode;
Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capability ep,
addr_t entry)
{
if (!_native_pd_cap.valid())
_native_pd_cap = pd.native_pd();
Nova_native_pd_client native_pd(_native_pd_cap);
Untyped_capability new_obj_cap =
retry<Genode::Pd_session::Out_of_metadata>(
[&] () {
return native_pd.alloc_rpc_cap(ep, entry, 0);
},
[&] () {
Pd_session_client *client =
dynamic_cast<Pd_session_client*>(&pd);
if (client)
env()->parent()->upgrade(*client, "ram_quota=16K");
});
native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name());
return new_obj_cap;
}
void Rpc_entrypoint::_free_rpc_cap(Pd_session &pd, Native_capability cap)
{
return pd.free_rpc_cap(cap);
}

View File

@ -0,0 +1,263 @@
/*
* \brief NOVA-specific support code for the server-side RPC API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-13
*/
/*
* Copyright (C) 2010-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.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/rpc_server.h>
#include <base/env.h>
/* base-internal includes */
#include <base/internal/stack.h>
#include <base/internal/ipc.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
#include <nova/native_thread.h>
using namespace Genode;
/***********************
** Server entrypoint **
***********************/
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
using namespace Nova;
Untyped_capability ec_cap;
/* _ec_sel is invalid until thread gets started */
if (native_thread().ec_sel != Native_thread::INVALID_INDEX)
ec_cap = Native_capability(native_thread().ec_sel);
else
ec_cap = _thread_cap;
Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap,
(addr_t)&_activation_entry);
if (!obj_cap.valid())
return obj_cap;
/* add server object to object pool */
obj->cap(obj_cap);
insert(obj);
/* return object capability managed by entrypoint thread */
return obj_cap;
}
void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
{
/* de-announce object from cap_session */
_free_rpc_cap(_pd_session, obj->cap());
/* avoid any incoming IPC */
Nova::revoke(Nova::Obj_crd(obj->cap().local_name(), 0), true);
/* make sure nobody is able to find this object */
remove(obj);
/* effectively invalidate the capability used before */
obj->cap(Untyped_capability());
/*
* The activation may execute a blocking operation in a dispatch function.
* Before resolving the corresponding object, we need to ensure that it is
* no longer used by an activation. Therefore, we to need cancel an
* eventually blocking operation and let the activation leave the context
* of the object.
*/
using namespace Nova;
Utcb *utcb = reinterpret_cast<Utcb *>(Thread_base::myself()->utcb());
/* don't call ourself */
if (utcb == reinterpret_cast<Utcb *>(this->utcb()))
return;
/*
* Required outside of core. E.g. launchpad needs it to forcefully kill
* a client which blocks on a session opening request where the service
* is not up yet.
*/
cancel_blocking();
/* activate entrypoint now - otherwise cleanup call will block forever */
_delay_start.unlock();
/* make a IPC to ensure that cap() identifier is not used anymore */
utcb->msg[0] = 0xdead;
utcb->set_msg_word(1);
if (uint8_t res = call(_cap.local_name()))
PERR("%8p - could not clean up entry point of thread 0x%p - res %u",
utcb, this->utcb(), res);
}
static void reply(Nova::Utcb &utcb, Rpc_exception_code exc, Msgbuf_base &snd_msg)
{
copy_msgbuf_to_utcb(utcb, snd_msg, exc.value);
Nova::reply(Thread_base::myself()->stack_top());
}
void Rpc_entrypoint::_activation_entry()
{
/* retrieve portal id from eax/rdi */
#ifdef __x86_64__
addr_t id_pt; asm volatile ("" : "=D" (id_pt));
#else
addr_t id_pt; asm volatile ("" : "=a" (id_pt));
#endif
Rpc_entrypoint &ep = *static_cast<Rpc_entrypoint *>(Thread_base::myself());
Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb();
Receive_window &rcv_window = ep.native_thread().rcv_window;
rcv_window.post_ipc(utcb);
/* handle ill-formed message */
if (utcb.msg_words() < 2) {
ep._rcv_buf.word(0) = ~0UL; /* invalid opcode */
} else {
copy_utcb_to_msgbuf(utcb, rcv_window, ep._rcv_buf);
}
Ipc_unmarshaller unmarshaller(ep._rcv_buf);
Rpc_opcode opcode(0);
unmarshaller.extract(opcode);
/* default return value */
Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
/* in case of a portal cleanup call we are done here - just reply */
if (ep._cap.local_name() == id_pt) {
if (!rcv_window.prepare_rcv_window(utcb))
PWRN("out of capability selectors for handling server requests");
ep._rcv_buf.reset();
reply(utcb, exc, ep._snd_buf);
}
{
/* potentially delay start */
Lock::Guard lock_guard(ep._delay_start);
}
/* atomically lookup and lock referenced object */
auto lambda = [&] (Rpc_object_base *obj) {
if (!obj) {
PERR("could not look up server object, return from call id_pt=%lx",
id_pt);
return;
}
/*
* Inhibit removal of capabilities sent as results of client requests.
* This prevents the recursive revocation of NOVA portal caps and,
* therefore, permits clients to use result capabilities after server
* code dropped all references.
*/
for (unsigned i = 0; i < ep._snd_buf.used_caps(); ++i)
ep._snd_buf.cap(i).keep_if_last_reference();
/* dispatch request */
ep._snd_buf.reset();
try { exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); }
catch (Blocking_canceled) { }
};
ep.apply(id_pt, lambda);
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)ep.utcb()))
PWRN("out of capability selectors for handling server requests");
ep._rcv_buf.reset();
reply(utcb, exc, ep._snd_buf);
}
void Rpc_entrypoint::entry()
{
/*
* Thread entry is not used for activations on NOVA
*/
}
void Rpc_entrypoint::_block_until_cap_valid() { }
void Rpc_entrypoint::activate()
{
/*
* In contrast to a normal thread, a server activation is created at
* construction time. However, it executes no code because processing
* time is always provided by the caller of the server activation. To
* delay the processing of requests until the 'activate' function is
* called, we grab the '_delay_start' lock on construction and release it
* here.
*/
_delay_start.unlock();
}
Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
const char *name, bool start_on_construction,
Affinity::Location location)
:
Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size, location),
_delay_start(Lock::LOCKED),
_pd_session(*pd_session)
{
/* set magic value evaluated by thread_nova.cc to start a local thread */
if (native_thread().ec_sel == Native_thread::INVALID_INDEX)
native_thread().ec_sel = Native_thread::INVALID_INDEX - 1;
/* required to create a 'local' EC */
Thread_base::start();
/* create cleanup portal */
_cap = _alloc_rpc_cap(_pd_session, Native_capability(native_thread().ec_sel),
(addr_t)_activation_entry);
if (!_cap.valid())
throw Cpu_session::Thread_creation_failed();
Receive_window &rcv_window = Thread_base::native_thread().rcv_window;
/* prepare portal receive window of new thread */
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb()))
throw Cpu_session::Thread_creation_failed();
if (start_on_construction)
activate();
}
Rpc_entrypoint::~Rpc_entrypoint()
{
typedef Object_pool<Rpc_object_base> Pool;
Pool::remove_all([&] (Rpc_object_base *obj) {
PWRN("Object pool not empty in %s", __func__);
_dissolve(obj);
});
if (!_cap.valid())
return;
_free_rpc_cap(_pd_session, _cap);
}

View File

@ -0,0 +1,44 @@
/*
* \brief NOVA specific implementation of the signaling framework
* \author Alexander Boettcher
* \date 2015-03-16
*/
/*
* 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.
*/
/* Genode includes */
#include <base/signal.h>
#include <base/trace/events.h>
using namespace Genode;
void Signal_transmitter::submit(unsigned cnt)
{
{
Trace::Signal_submit trace_event(cnt);
}
if (!_context.valid())
return;
using namespace Nova;
uint8_t res = NOVA_OK;
for (unsigned i = 0; res == NOVA_OK && i < cnt; i++)
res = sm_ctrl(_context.local_name(), SEMAPHORE_UP);
if (res == NOVA_OK)
return;
PDBG("submitting signal failed - error %u - context=0x%lx", res,
_context.local_name());
_context = Signal_context_capability();
}

View File

@ -0,0 +1,37 @@
/*
* \brief Lay back and relax
* \author Norman Feske
* \author Christian Helmuth
* \date 2006-07-19
*/
/*
* Copyright (C) 2006-2016 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/sleep.h>
#include <base/lock.h>
/* base-internal includes */
#include <base/internal/native_thread.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
void Genode::sleep_forever()
{
using namespace Nova;
Thread_base *myself = Thread_base::myself();
addr_t sem = myself ? myself->native_thread().exc_pt_sel + SM_SEL_EC : SM_SEL_EC;
while (1) {
if (Nova::sm_ctrl(sem, SEMAPHORE_DOWNZERO))
nova_die();
}
}

View File

@ -0,0 +1,127 @@
/*
* \brief Stack-specific part of the thread library
* \author Norman Feske
* \author Alexander Boettcher
* \author Martin Stein
* \date 2010-01-19
*
* This part of the thread library is required by the IPC framework
* also if no threads are used.
*/
/*
* 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 <util/construct_at.h>
#include <base/env.h>
#include <base/thread.h>
/* base-internal includes */
#include <base/internal/stack.h>
#include <base/internal/stack_area.h>
#include <base/internal/native_utcb.h>
/* base-nova includes */
#include <base/cap_map.h>
using namespace Genode;
extern addr_t __initial_sp;
/*******************
** local helpers **
*******************/
Native_utcb * main_thread_utcb()
{
using namespace Genode;
return reinterpret_cast<Native_utcb *>(
stack_area_virtual_base() + stack_virtual_size() - Nova::PAGE_SIZE_BYTE);
}
addr_t main_thread_running_semaphore() { return Nova::SM_SEL_EC; }
class Initial_cap_range : public Cap_range
{
private:
enum { CAP_RANGE_START = 4096 };
public:
Initial_cap_range() : Cap_range(CAP_RANGE_START) { }
};
Initial_cap_range * initial_cap_range()
{
static Initial_cap_range s;
return &s;
}
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
using namespace Genode;
cap_map()->insert(initial_cap_range());
/* for Core we can't perform the following code so early */
if (!__initial_sp) {
enum { CAP_RANGES = 32 };
unsigned index = initial_cap_range()->base() +
initial_cap_range()->elements();
static char local[CAP_RANGES][sizeof(Cap_range)];
for (unsigned i = 0; i < CAP_RANGES; i++) {
Cap_range * range = reinterpret_cast<Cap_range *>(local[i]);
*range = Cap_range(index);
cap_map()->insert(range);
index = range->base() + range->elements();
}
}
}
void prepare_reinit_main_thread()
{
using namespace Genode;
construct_at<Capability_map>(cap_map());
construct_at<Initial_cap_range>(initial_cap_range());
prepare_init_main_thread();
}
/*****************
** Thread_base **
*****************/
Native_utcb *Thread_base::utcb()
{
/*
* If 'utcb' is called on the object returned by 'myself',
* the 'this' pointer may be NULL (if the calling thread is
* the main thread). Therefore we allow this special case
* here.
*/
if (this == 0) return main_thread_utcb();
return &_stack->utcb();
}

View File

@ -0,0 +1,210 @@
/*
* \brief NOVA-specific implementation of the Thread API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \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>
#include <base/rpc_client.h>
#include <session/session.h>
#include <nova_native_cpu/client.h>
/* base-internal includes */
#include <base/internal/stack.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
#include <nova_cpu_session/connection.h>
using namespace Genode;
/**
* Entry point entered by new threads
*/
void Thread_base::_thread_start()
{
using namespace Genode;
/* catch any exception at this point and try to print an error message */
try {
Thread_base::myself()->entry();
} catch (...) {
char thread_name[48];
Thread_base::myself()->name(thread_name, sizeof(thread_name));
try {
PERR("Thread '%s' died because of an uncaught exception", thread_name);
} catch (...) {
/* die in a noisy way */
nova_die();
}
throw;
}
Thread_base::myself()->_join_lock.unlock();
/* sleep silently */
Genode::sleep_forever();
}
/*****************
** Thread base **
*****************/
void Thread_base::_init_platform_thread(size_t weight, Type type)
{
using namespace Nova;
/*
* Allocate capability selectors for the thread's execution context,
* running semaphore and exception handler portals.
*/
native_thread().ec_sel = Native_thread::INVALID_INDEX;
/* for main threads the member initialization differs */
if (type == MAIN || type == REINITIALIZED_MAIN) {
_thread_cap = env()->parent()->main_thread_cap();
Genode::Native_capability pager_cap(Nova::PT_SEL_MAIN_PAGER);
native_thread().exc_pt_sel = 0;
native_thread().ec_sel = Nova::PT_SEL_MAIN_EC;
request_native_ec_cap(pager_cap, native_thread().ec_sel);
return;
}
/*
* Revoke possible left-over UTCB of a previously destroyed thread
* which used this context location.
*
* This cannot be done in '_deinit_platform_thread()', because a
* self-destructing thread needs its UTCB to call
* 'Cpu_session::kill_thread()' and is not able to revoke the UTCB
* afterwards.
*/
Rights rwx(true, true, true);
addr_t utcb = reinterpret_cast<addr_t>(&_stack->utcb());
revoke(Mem_crd(utcb >> 12, 0, rwx));
native_thread().exc_pt_sel = cap_map()->insert(NUM_INITIAL_PT_LOG2);
if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed();
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(env()->pd_session_cap(), weight, buf, _affinity);
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
}
void Thread_base::_deinit_platform_thread()
{
using namespace Nova;
if (native_thread().ec_sel != Native_thread::INVALID_INDEX) {
revoke(Obj_crd(native_thread().ec_sel, 1));
cap_map()->remove(native_thread().ec_sel, 1, false);
}
/* de-announce thread */
if (_thread_cap.valid())
_cpu_session->kill_thread(_thread_cap);
cap_map()->remove(native_thread().exc_pt_sel, NUM_INITIAL_PT_LOG2);
}
void Thread_base::start()
{
if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1)
throw Cpu_session::Thread_creation_failed();
/*
* Default: create global thread - ec.sel == INVALID_INDEX
* create local thread - ec.sel == INVALID_INDEX - 1
*/
bool global = native_thread().ec_sel == Native_thread::INVALID_INDEX;
using namespace Genode;
/* obtain interface to NOVA-specific CPU session operations */
Nova_native_cpu_client native_cpu(_cpu_session->native_cpu());
/* create new pager object and assign it to the new thread */
Native_capability pager_cap = native_cpu.pager_cap(_thread_cap);
if (!pager_cap.valid())
throw Cpu_session::Thread_creation_failed();
/* create EC at core */
Thread_state state;
state.sel_exc_base = native_thread().exc_pt_sel;
state.is_vcpu = native_thread().is_vcpu;
/* local thread have no start instruction pointer - set via portal entry */
addr_t thread_ip = global ? reinterpret_cast<addr_t>(_thread_start) : 0;
try { _cpu_session->state(_thread_cap, state); }
catch (...) { throw Cpu_session::Thread_creation_failed(); }
if (_cpu_session->start(_thread_cap, thread_ip, _stack->top()))
throw Cpu_session::Thread_creation_failed();
/* request native EC thread cap */
native_thread().ec_sel = cap_map()->insert(1);
if (native_thread().ec_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed();
/* requested pager cap used by request_native_ec_cap in Signal_source_client */
enum { MAP_PAGER_CAP = 1 };
request_native_ec_cap(pager_cap, native_thread().ec_sel, MAP_PAGER_CAP);
using namespace Nova;
/* request exception portals for normal threads */
if (!native_thread().is_vcpu) {
request_event_portal(pager_cap, native_thread().exc_pt_sel, 0, NUM_INITIAL_PT_LOG2);
/* default: we don't accept any mappings or translations */
Utcb * utcb_obj = reinterpret_cast<Utcb *>(utcb());
utcb_obj->crd_rcv = Obj_crd();
utcb_obj->crd_xlt = Obj_crd();
}
if (global)
/* request creation of SC to let thread run*/
_cpu_session->resume(_thread_cap);
}
void Thread_base::cancel_blocking()
{
using namespace Nova;
if (sm_ctrl(native_thread().exc_pt_sel + SM_SEL_EC, SEMAPHORE_UP))
nova_die();
}