mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
NOVA: Throughly cleanup caps in case of errors
This commit is contained in:
parent
e3a7d2220d
commit
650a1d47f0
@ -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;
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user