NOVA: Throughly cleanup caps in case of errors

This commit is contained in:
Alexander Boettcher 2012-08-02 12:20:00 +02:00 committed by Norman Feske
parent e3a7d2220d
commit 650a1d47f0
6 changed files with 131 additions and 55 deletions

View File

@ -35,7 +35,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
using namespace Nova;
Untyped_capability ep_cap, new_obj_cap;
Untyped_capability ec_cap, ep_cap;
/* _ec_sel is invalid until thread gets started */
if (tid().ec_sel != ~0UL)
@ -46,11 +46,11 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
ep_cap = _cap_session->alloc(ec_cap, (addr_t)_activation_entry);
/* add server object to object pool */
obj->cap(new_obj_cap);
obj->cap(ep_cap);
insert(obj);
/* return capability that uses the local object id as badge */
return new_obj_cap;
/* return entrypoint capability */
return ep_cap;
}
@ -88,13 +88,13 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
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
/* retrieve portal id from eax */
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(Thread_base::myself());
Ipc_server srv(&ep->_snd_buf, &ep->_rcv_buf);
@ -208,7 +208,11 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap =
env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
if (!pager_cap.valid())
throw Cpu_session::Thread_creation_failed();
if (env()->cpu_session()->set_pager(_thread_cap, pager_cap))
throw Cpu_session::Thread_creation_failed();
addr_t thread_sp = (addr_t)&_context->stack[-4];
Genode::Nova_cpu_connection cpu;

View File

@ -59,15 +59,14 @@ void Thread_base::_init_platform_thread()
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap =
env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
if (env()->pd_session()->bind_thread(_thread_cap))
throw Cpu_session::Thread_creation_failed();
}
@ -106,8 +105,13 @@ void Thread_base::start()
using namespace Genode;
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
Pager_capability pager_cap =
env()->rm_session()->add_client(_thread_cap);
if (!pager_cap.valid())
throw Cpu_session::Thread_creation_failed();
if (env()->cpu_session()->set_pager(_thread_cap, pager_cap))
throw Cpu_session::Thread_creation_failed();
/* create EC at core */
addr_t thread_sp = reinterpret_cast<addr_t>(&_context->stack[-4]);

View File

@ -29,9 +29,8 @@ namespace Genode {
{
private:
int _thread_cnt;
Native_capability _parent;
int _id;
int _thread_cnt;
addr_t _pd_sel;
public:
@ -76,10 +75,13 @@ namespace Genode {
*/
void assign_pd(addr_t pd_sel) { _pd_sel = pd_sel; }
/**
* Capability selector of this task.
*
* \return PD selector
*/
addr_t pd_sel() { return _pd_sel; }
int id() { return _id; }
/**
* Capability selector of core protection domain
*

View File

@ -1,6 +1,7 @@
/*
* \brief Thread facility
* \author Norman Feske
* \author Alexander Boettcher
* \date 2009-10-02
*/
@ -30,21 +31,24 @@ namespace Genode {
Platform_pd *_pd;
Pager_object *_pager;
bool _is_main_thread;
addr_t _id_base;
addr_t _sel_exc_base;
unsigned _cpu_no;
bool _is_main_thread;
addr_t _sel_ec() { return _id_base; }
addr_t _sel_sc() { return _id_base + 1; }
addr_t _sel_ec() { return _id_base; }
addr_t _sel_sc() { return _id_base + 1; }
public:
enum { THREAD_INVALID = -1 }; /* invalid thread number */
/* invalid thread number */
enum { THREAD_INVALID = -1 };
/**
* Constructor
*/
Platform_thread(const char *name = 0, unsigned priority = 0,
Platform_thread(const char *name = 0,
unsigned priority = 0,
int thread_id = THREAD_INVALID);
/**
@ -98,6 +102,9 @@ namespace Genode {
*/
void pager(Pager_object *pager) { _pager = pager; }
/**
* Return pager object
*/
Pager_object *pager() { return _pager; }
/**
@ -123,6 +130,19 @@ namespace Genode {
_pd = pd, _is_main_thread = is_main_thread;
}
/**
* Return native EC cap with specific rights mask set.
* If the cap is mapped the kernel will demote the
* rights of the EC as specified by the rights mask.
*
* The cap is supposed to be returned to clients,
* which they have to use as argument to identify
* the thread to which they want attach portals.
*
* The demotion by the kernel during the map operation
* takes care that the EC cap itself contains
* no usable rights for the clients.
*/
Native_capability native_cap()
{
using namespace Nova;

View File

@ -13,6 +13,7 @@
/* Genode includes */
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
/* core includes */
#include <platform_pd.h>
@ -45,12 +46,15 @@ int Platform_pd::assign_parent(Native_capability parent)
}
static int id_cnt;
Platform_pd::Platform_pd(signed pd_id, bool create)
: _thread_cnt(0), _id(++id_cnt), _pd_sel(0) { }
: _thread_cnt(0), _pd_sel(~0UL) { }
Platform_pd::~Platform_pd()
{ }
{
if (_pd_sel == ~0UL) return;
/* Revoke and free cap, pd is gone */
Nova::revoke(Nova::Obj_crd(_pd_sel, 0));
cap_selector_allocator()->free(_pd_sel, 0);
}

View File

@ -85,23 +85,28 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base)
bool thread_global = ip;
res = create_ec(_sel_ec(), _pd->pd_sel(), _cpu_no, utcb,
initial_sp, exc_base, thread_global);
if (res)
PERR("creation of new thread failed %u", res);
return res ? -5 : 0;
}
if (_sel_exc_base != ~0UL) {
PERR("thread already started");
return -6;
}
/*
* For the first thread of a new PD, use the initial stack pointer for
* reporting the thread's UTCB address.
*/
_pager->initial_esp(PD_UTCB + get_page_size());
addr_t pd_sel = Platform_pd::pd_core_sel();
addr_t exc_base_sel = cap_selector_allocator()->alloc(Nova::NUM_INITIAL_PT_LOG2);
addr_t sm_alloc_sel = exc_base_sel + PD_SEL_CAP_LOCK;
addr_t sm_ec_sel = exc_base_sel + SM_SEL_EC;
_sel_exc_base = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
addr_t pd_core_sel = Platform_pd::pd_core_sel();
addr_t sm_alloc_sel = _sel_exc_base + PD_SEL_CAP_LOCK;
addr_t sm_ec_sel = _sel_exc_base + SM_SEL_EC;
addr_t remap_src[] = { _pager->exc_pt_sel() + PT_SEL_PAGE_FAULT,
_pd->parent_pt_sel(),
@ -109,60 +114,88 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base)
addr_t remap_dst[] = { PT_SEL_PAGE_FAULT,
PT_SEL_PARENT,
PT_SEL_STARTUP };
addr_t pd_sel;
Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2);
uint8_t res;
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
/* locally map portals to initial portal window */
if (map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
if (map_local((Utcb *)Thread_base::myself()->utcb(),
Obj_crd(remap_src[i], 0),
Obj_crd(exc_base_sel + remap_dst[i], 0))) {
Obj_crd(_sel_exc_base + remap_dst[i], 0))) {
PERR("could not remap portal %lx->%lx",
remap_src[i], remap_dst[i]);
return -6;
goto cleanup_base;
}
}
/* Create lock for cap allocator selector */
uint8_t res = Nova::create_sm(sm_alloc_sel, pd_sel, 1);
if (res != Nova::NOVA_OK) {
res = create_sm(sm_alloc_sel, pd_core_sel, 1);
if (res != NOVA_OK) {
PERR("could not create semaphore for capability allocator");
return -7;
goto cleanup_base;
}
/* Create lock for EC used by lock_helper */
res = Nova::create_sm(sm_ec_sel, pd_sel, 0);
if (res != Nova::NOVA_OK) {
res = create_sm(sm_ec_sel, pd_core_sel, 0);
if (res != NOVA_OK) {
PERR("could not create semaphore for new thread");
return -8;
goto cleanup_base;
}
/* Create task */
addr_t pd0_sel = cap_selector_allocator()->alloc();
_pd->assign_pd(pd0_sel);
pd_sel = cap_selector_allocator()->alloc();
Obj_crd initial_pts(exc_base_sel, Nova::NUM_INITIAL_PT_LOG2);
res = create_pd(pd0_sel, pd_sel, initial_pts);
/* create task */
res = create_pd(pd_sel, pd_core_sel, initial_pts);
if (res) {
PERR("create_pd returned %d", res);
return -9;
goto cleanup_pd;
}
/* Create first thread in task */
enum { THREAD_GLOBAL = true };
res = create_ec(_sel_ec(), pd0_sel, _cpu_no, PD_UTCB, 0, 0,
res = create_ec(_sel_ec(), pd_sel, _cpu_no, PD_UTCB, 0, 0,
THREAD_GLOBAL);
if (res) {
PERR("create_ec returned %d", res);
return -10;
goto cleanup_pd;
}
/**
* We have to assign the pd here, because after create_sc the thread
* becomes running immediately.
*/
_pd->assign_pd(pd_sel);
/* Let the thread run */
res = create_sc(_sel_sc(), pd0_sel, _sel_ec(), Qpd());
res = create_sc(_sel_sc(), pd_sel, _sel_ec(), Qpd());
if (res) {
/* Reset pd cap since thread got not running and pd cap will
* be revoked during cleanup*/
_pd->assign_pd(~0UL);
PERR("create_sc returned %d", res);
return -11;
goto cleanup_ec;
}
return 0;
cleanup_ec:
/* cap_selector free for _sel_ec is done in de-constructor */
revoke(Obj_crd(_sel_ec(), 0));
cleanup_pd:
revoke(Obj_crd(pd_sel, 0));
cap_selector_allocator()->free(pd_sel, 0);
cleanup_base:
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base, NUM_INITIAL_PT_LOG2);
_sel_exc_base = ~0UL;
return -1;
}
@ -192,13 +225,22 @@ unsigned long Platform_thread::pager_object_badge() const { return ~0UL; }
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id)
: _pd(0), _id_base(cap_selector_allocator()->alloc(1)), _cpu_no(0) { }
: _pd(0), _pager(0), _id_base(cap_selector_allocator()->alloc(1)),
_sel_exc_base(~0UL), _cpu_no(0), _is_main_thread(false) { }
Platform_thread::~Platform_thread()
{
using namespace Nova;
if (_is_main_thread)
revoke(Obj_crd(_pd->pd_sel(), 0));
/* free ec and sc caps */
revoke(Obj_crd(_id_base, 1));
cap_selector_allocator()->free(_id_base, 1);
/* free exc_base used by main thread */
if (_sel_exc_base != ~0UL) {
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base,
NUM_INITIAL_PT_LOG2);
}
}