mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-16 14:18:27 +00:00
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:
188
repos/base-nova/src/lib/base/cap_map.cc
Normal file
188
repos/base-nova/src/lib/base/cap_map.cc
Normal 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 ↦
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** 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;
|
||||
}
|
||||
}
|
74
repos/base-nova/src/lib/base/ipc.cc
Normal file
74
repos/base-nova/src/lib/base/ipc.cc
Normal 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));
|
||||
}
|
52
repos/base-nova/src/lib/base/region_map_client.cc
Normal file
52
repos/base-nova/src/lib/base/region_map_client.cc
Normal 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;
|
||||
}
|
||||
|
56
repos/base-nova/src/lib/base/rpc_cap_alloc.cc
Normal file
56
repos/base-nova/src/lib/base/rpc_cap_alloc.cc
Normal 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);
|
||||
}
|
263
repos/base-nova/src/lib/base/rpc_entrypoint.cc
Normal file
263
repos/base-nova/src/lib/base/rpc_entrypoint.cc
Normal 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);
|
||||
}
|
44
repos/base-nova/src/lib/base/signal_submit.cc
Normal file
44
repos/base-nova/src/lib/base/signal_submit.cc
Normal 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();
|
||||
}
|
37
repos/base-nova/src/lib/base/sleep.cc
Normal file
37
repos/base-nova/src/lib/base/sleep.cc
Normal 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();
|
||||
}
|
||||
}
|
127
repos/base-nova/src/lib/base/stack.cc
Normal file
127
repos/base-nova/src/lib/base/stack.cc
Normal 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();
|
||||
}
|
210
repos/base-nova/src/lib/base/thread_start.cc
Normal file
210
repos/base-nova/src/lib/base/thread_start.cc
Normal 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();
|
||||
}
|
Reference in New Issue
Block a user