nova: create sm of each thread in pager

Mainly simplification of the code and getting rid of reserved (Genode) special
cap selectors in the syscall-generic.h file.

Issue #478
This commit is contained in:
Alexander Boettcher 2013-09-23 09:07:33 +02:00 committed by Norman Feske
parent a903049a1a
commit c426bac8bb
5 changed files with 56 additions and 118 deletions

View File

@ -49,13 +49,9 @@ namespace Genode {
*/
addr_t _pt_cleanup;
/**
* Semaphore selector to synchronize pause/state/resume operations
*/
addr_t _sm_state_notify;
addr_t _initial_esp;
addr_t _initial_eip;
addr_t _client_exc_pt_sel;
struct
{
@ -70,6 +66,11 @@ namespace Genode {
void _copy_state(Nova::Utcb * utcb);
/**
* Semaphore selector to synchronize pause/state/resume operations
*/
addr_t sm_state_notify() { return _pt_cleanup + 1; }
static void _page_fault_handler();
static void _startup_handler();
static void _invoke_handler();
@ -79,6 +80,7 @@ namespace Genode {
static void _exception_handler(addr_t portal_id);
static Nova::Utcb * _check_handler(Thread_base *&, Pager_object *&);
public:
Pager_object(unsigned long badge, Affinity::Location location);
@ -106,6 +108,7 @@ namespace Genode {
* Return base of initial portal window
*/
addr_t exc_pt_sel() { return _tid.exc_pt_sel; }
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
/**
* Set initial stack pointer used by the startup handler
@ -154,7 +157,7 @@ namespace Genode {
if (_state.dead)
return Native_capability::invalid_cap();
return Native_capability(_sm_state_notify);
return Native_capability(sm_state_notify());
}
/**

View File

@ -560,8 +560,6 @@ namespace Nova {
PT_SEL_PARENT = 0x1a, /* convention on Genode */
PT_SEL_STARTUP = 0x1e,
PT_SEL_RECALL = 0x1f,
PD_SEL = 0x1b,
SM_SEL_EC_CLIENT = 0x1c, /* convention on Genode */
SM_SEL_EC = 0x1d, /* convention on Genode */
};

View File

@ -74,7 +74,7 @@ void Pager_object::_page_fault_handler()
Native_capability pager_obj = obj->Object_pool<Pager_object>::Entry::cap();
revoke(pager_obj.dst(), true);
revoke(Obj_crd(obj->exc_pt_sel(), NUM_INITIAL_PT_LOG2), false);
revoke(Obj_crd(obj->exc_pt_sel_client(), NUM_INITIAL_PT_LOG2), false);
obj->_state.dead = true;
}
@ -143,7 +143,7 @@ void Pager_object::_recall_handler()
obj->_state.valid = true;
if (sm_ctrl(obj->_sm_state_notify, SEMAPHORE_UP) != NOVA_OK)
if (sm_ctrl(obj->sm_state_notify(), SEMAPHORE_UP) != NOVA_OK)
PWRN("notify failed");
if (sm_ctrl(obj->exc_pt_sel() + SM_SEL_EC, SEMAPHORE_DOWNZERO) != NOVA_OK)
@ -197,14 +197,7 @@ void Pager_object::_invoke_handler()
if (event < PT_SEL_PARENT || event == PT_SEL_STARTUP ||
event == SM_SEL_EC || event == PT_SEL_RECALL) {
/*
* Caller is requesting the SM cap of thread
* this object is paging - it is stored at SM_SEL_EC_CLIENT
*/
if (event == SM_SEL_EC) event = SM_SEL_EC_CLIENT;
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel() + event,
0), 0);
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + event, 0), 0);
/* one item ever fits on the UTCB */
(void)res;
}
@ -218,7 +211,7 @@ void Pager_object::wake_up() { cancel_blocking(); }
void Pager_object::client_cancel_blocking()
{
uint8_t res = sm_ctrl(exc_pt_sel() + SM_SEL_EC_CLIENT, SEMAPHORE_UP);
uint8_t res = sm_ctrl(exc_pt_sel_client() + SM_SEL_EC, SEMAPHORE_UP);
if (res != NOVA_OK)
PWRN("cancel blocking failed");
}
@ -232,11 +225,8 @@ uint8_t Pager_object::client_recall()
void Pager_object::cleanup_call()
{
/*
* Revoke all portals of Pager_object from others.
* The portals will be finally revoked during thread destruction.
*/
revoke(Obj_crd(exc_pt_sel(), NUM_INITIAL_PT_LOG2), false);
/* revoke all portals handling the client. */
revoke(Obj_crd(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2));
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
if (reinterpret_cast<Utcb *>(this->utcb()) == utcb) return;
@ -262,7 +252,8 @@ static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd,
}
Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
: Thread_base("pager:", PF_HANDLER_STACK_SIZE), _badge(badge)
: Thread_base("pager:", PF_HANDLER_STACK_SIZE),
_badge(reinterpret_cast<unsigned long>(_context->name + 6))
{
class Create_exception_pt_failed { };
uint8_t res;
@ -272,13 +263,17 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
sizeof(_context->name) - 6);
addr_t pd_sel = __core_pd_sel;
_pt_cleanup = cap_selector_allocator()->alloc();
_sm_state_notify = cap_selector_allocator()->alloc();
_pt_cleanup = cap_selector_allocator()->alloc(1);
_client_exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
_state.valid = false;
_state.dead = false;
_state.singlestep = false;
_state.sel_client_ec = Native_thread::INVALID_INDEX;
if (_pt_cleanup == Native_thread::INVALID_INDEX ||
_client_exc_pt_sel == Native_thread::INVALID_INDEX)
throw Create_exception_pt_failed();
/* tell thread starting code on which CPU to let run the pager */
reinterpret_cast<Affinity::Location *>(stack_top())[-1] = location;
@ -287,20 +282,16 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
/* create portal for exception handlers 0x0 - 0xd */
for (unsigned i = 0; i < PT_SEL_PAGE_FAULT; i++) {
res = create_portal(exc_pt_sel() + i, pd_sel, _tid.ec_sel, Mtd(0),
(addr_t)_exception_handler);
res = create_portal(exc_pt_sel_client() + i, pd_sel, _tid.ec_sel,
Mtd(Mtd::EIP), (addr_t)_exception_handler);
if (res) {
PERR("could not create exception portal, error = %u\n", res);
throw Create_exception_pt_failed();
}
}
/* threads in core get default page fault handler assigned, revoke it */
if (_tid.ec_sel != Native_thread::INVALID_INDEX)
revoke(Obj_crd(exc_pt_sel() + PT_SEL_PAGE_FAULT, 0));
/* create portal for page-fault handler */
res = create_portal(exc_pt_sel() + PT_SEL_PAGE_FAULT, pd_sel, _tid.ec_sel,
res = create_portal(exc_pt_sel_client() + PT_SEL_PAGE_FAULT, pd_sel, _tid.ec_sel,
Mtd(Mtd::QUAL | Mtd::EIP), (mword_t)_page_fault_handler);
if (res) {
PERR("could not create page-fault portal, error = %u\n", res);
@ -310,8 +301,8 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
/* create portal for exception handlers 0xf - 0x19 */
for (unsigned i = PT_SEL_PAGE_FAULT + 1; i < PT_SEL_PARENT; i++) {
res = create_portal(exc_pt_sel() + i, pd_sel, _tid.ec_sel, Mtd(0),
(addr_t)_exception_handler);
res = create_portal(exc_pt_sel_client() + i, pd_sel, _tid.ec_sel,
Mtd(Mtd::EIP), (addr_t)_exception_handler);
if (res) {
PERR("could not create exception portal, error = %u\n", res);
throw Create_exception_pt_failed();
@ -319,7 +310,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
}
/* create portal for startup handler */
res = create_portal(exc_pt_sel() + PT_SEL_STARTUP, pd_sel, _tid.ec_sel,
res = create_portal(exc_pt_sel_client() + PT_SEL_STARTUP, pd_sel, _tid.ec_sel,
Mtd(Mtd::ESP | Mtd::EIP), (mword_t)_startup_handler);
if (res) {
PERR("could not create startup portal, error = %u\n",
@ -330,7 +321,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
/* create portal for recall handler */
Mtd mtd(Mtd::ESP | Mtd::EIP | Mtd::ACDB | Mtd::EFL | Mtd::EBSD | Mtd::FSGS);
res = create_portal(exc_pt_sel() + PT_SEL_RECALL, pd_sel, _tid.ec_sel,
res = create_portal(exc_pt_sel_client() + PT_SEL_RECALL, pd_sel, _tid.ec_sel,
mtd, (addr_t)_recall_handler);
if (res) {
PERR("could not create recall portal, error = %u\n", res);
@ -338,6 +329,16 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
throw Create_recall_pt_failed();
}
/*
* Create semaphore required for Genode locking. It can be later on
* requested by the thread the same way as all exception portals.
*/
res = Nova::create_sm(exc_pt_sel_client() + SM_SEL_EC, pd_sel, 0);
if (res != Nova::NOVA_OK) {
class Create_state_notifiy_sm_failed { };
throw Create_state_notifiy_sm_failed();
}
/* create portal for final cleanup call used during destruction */
res = create_portal(_pt_cleanup, pd_sel, _tid.ec_sel, Mtd(0),
reinterpret_cast<addr_t>(_invoke_handler));
@ -347,7 +348,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
throw Create_cleanup_pt_failed();
}
res = Nova::create_sm(_sm_state_notify, pd_sel, 0);
res = Nova::create_sm(sm_state_notify(), pd_sel, 0);
if (res != Nova::NOVA_OK) {
class Create_state_notifiy_sm_failed { };
throw Create_state_notifiy_sm_failed();
@ -357,13 +358,9 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
Pager_object::~Pager_object()
{
/* revoke semaphore cap to signal valid state after recall */
addr_t sm_cap = _sm_state_notify;
_sm_state_notify = Native_thread::INVALID_INDEX;
/* if pager is blocked wake him up */
sm_ctrl(sm_cap, SEMAPHORE_UP);
revoke(Obj_crd(sm_cap, 0));
sm_ctrl(sm_state_notify(), SEMAPHORE_UP);
revoke(Obj_crd(sm_state_notify(), 0));
/* take care nobody is handled anymore by this object */
cleanup_call();
@ -372,9 +369,9 @@ Pager_object::~Pager_object()
revoke(Obj_crd(_pt_cleanup, 0));
Native_capability pager_obj = ::Object_pool<Pager_object>::Entry::cap();
cap_selector_allocator()->free(_pt_cleanup, 0);
cap_selector_allocator()->free(sm_cap, 0);
cap_selector_allocator()->free(_pt_cleanup, 1);
cap_selector_allocator()->free(pager_obj.local_name(), 0);
cap_selector_allocator()->free(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2);
}

View File

@ -75,8 +75,10 @@ void Thread_base::_init_platform_thread()
* Allocate capability selectors for the thread's execution context,
* running semaphore and exception handler portals.
*/
_tid.ec_sel = ~0UL;
_tid.ec_sel = Native_thread::INVALID_INDEX;
_tid.exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
if (_tid.exc_pt_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed();
/* create thread at core */
char buf[48];

View File

@ -72,28 +72,14 @@ int Platform_thread::start(void *ip, void *sp)
return -3;
}
/*
* Create semaphore required for Genode locking.
* It is created at the root pager exception base +
* SM_SEL_EC_CLIENT and can be later on requested by the thread
* the same way as STARTUP and PAGEFAULT portal.
*/
addr_t sm = _pager->exc_pt_sel() + SM_SEL_EC_CLIENT;
uint8_t res = Nova::create_sm(sm, _pd->pd_sel(), 0);
if (res != Nova::NOVA_OK) {
PERR("creation of semaphore for new thread failed %u", res);
return -4;
}
/* ip == 0 means that caller will use the thread as worker */
bool thread_global = ip;
res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(), utcb,
initial_sp, _sel_exc_base, thread_global);
uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(),
utcb, initial_sp, _sel_exc_base, thread_global);
if (res != Nova::NOVA_OK) {
revoke(Obj_crd(sm, 0));
PERR("creation of new thread failed %u", res);
return -5;
return -4;
}
_pager->initial_eip((addr_t)ip);
@ -105,7 +91,7 @@ int Platform_thread::start(void *ip, void *sp)
if (_sel_exc_base != Native_thread::INVALID_INDEX) {
PERR("thread already started");
return -6;
return -5;
}
/*
@ -116,59 +102,24 @@ int Platform_thread::start(void *ip, void *sp)
Native_config::context_area_virtual_size() -
get_page_size();
_sel_exc_base = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
_sel_exc_base = _pager->exc_pt_sel_client();
addr_t pd_core_sel = Platform_pd::pd_core_sel();
addr_t sm_ec_sel = _pager->exc_pt_sel() + SM_SEL_EC_CLIENT;
addr_t remap_src[] = { _pd->parent_pt_sel(),
_pager->exc_pt_sel() + PT_SEL_STARTUP,
_pager->exc_pt_sel() + PT_SEL_RECALL,
sm_ec_sel };
addr_t remap_dst[] = { PT_SEL_PARENT,
PT_SEL_STARTUP,
PT_SEL_RECALL,
SM_SEL_EC };
addr_t remap_src[] = { _pd->parent_pt_sel() };
addr_t remap_dst[] = { PT_SEL_PARENT };
addr_t pd_sel;
Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2);
uint8_t res;
/* create lock for EC used by lock_helper */
res = create_sm(sm_ec_sel, pd_core_sel, 0);
if (res != NOVA_OK) {
PERR("could not create semaphore for new thread");
goto cleanup_base;
}
/* remap exception portals for first thread */
if (map_local((Utcb *)Thread_base::myself()->utcb(),
Obj_crd(_pager->exc_pt_sel(), 4),
Obj_crd(_sel_exc_base, 4)))
goto cleanup_base;
if (map_local((Utcb *)Thread_base::myself()->utcb(),
Obj_crd(_pager->exc_pt_sel() + 0x10, 3),
Obj_crd(_sel_exc_base + 0x10, 3)))
goto cleanup_base;
if (map_local((Utcb *)Thread_base::myself()->utcb(),
Obj_crd(_pager->exc_pt_sel() + 0x18, 1),
Obj_crd(_sel_exc_base + 0x18, 1)))
goto cleanup_base;
if (PT_SEL_PARENT != 0x1a) {
PERR("PT_SEL_PARENT changed !! Adjust remap code !!");
goto cleanup_base;
}
/* remap Genode specific, RECALL and STARTUP portals for first thread */
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
if (map_local((Utcb *)Thread_base::myself()->utcb(),
Obj_crd(remap_src[i], 0),
Obj_crd(_sel_exc_base + remap_dst[i], 0)))
goto cleanup_base;
return -6;
}
pd_sel = cap_selector_allocator()->alloc();
@ -224,12 +175,6 @@ int Platform_thread::start(void *ip, void *sp)
revoke(Obj_crd(pd_sel, 0));
cap_selector_allocator()->free(pd_sel, 0);
cleanup_base:
revoke(Obj_crd(sm_ec_sel, 0));
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base, NUM_INITIAL_PT_LOG2);
_sel_exc_base = Native_thread::INVALID_INDEX;
return -7;
}
@ -340,11 +285,4 @@ Platform_thread::~Platform_thread()
/* 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 (_is_main_thread && _sel_exc_base != Native_thread::INVALID_INDEX) {
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base,
NUM_INITIAL_PT_LOG2);
}
}