From c426bac8bb3fcb3be45493b571f8f63589329a47 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 23 Sep 2013 09:07:33 +0200 Subject: [PATCH] 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 --- base-nova/include/base/pager.h | 15 +++-- base-nova/include/nova/syscall-generic.h | 2 - base-nova/src/base/pager/pager.cc | 75 +++++++++++------------ base-nova/src/base/thread/thread_nova.cc | 4 +- base-nova/src/core/platform_thread.cc | 78 +++--------------------- 5 files changed, 56 insertions(+), 118 deletions(-) diff --git a/base-nova/include/base/pager.h b/base-nova/include/base/pager.h index fe1163e45a..e3bca4b7c4 100644 --- a/base-nova/include/base/pager.h +++ b/base-nova/include/base/pager.h @@ -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()); } /** diff --git a/base-nova/include/nova/syscall-generic.h b/base-nova/include/nova/syscall-generic.h index 1216bc7952..653a7fe31a 100644 --- a/base-nova/include/nova/syscall-generic.h +++ b/base-nova/include/nova/syscall-generic.h @@ -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 */ }; diff --git a/base-nova/src/base/pager/pager.cc b/base-nova/src/base/pager/pager.cc index 3159db1abf..0b24d56edf 100644 --- a/base-nova/src/base/pager/pager.cc +++ b/base-nova/src/base/pager/pager.cc @@ -74,7 +74,7 @@ void Pager_object::_page_fault_handler() Native_capability pager_obj = obj->Object_pool::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(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(_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(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(_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::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); } diff --git a/base-nova/src/base/thread/thread_nova.cc b/base-nova/src/base/thread/thread_nova.cc index 7f1db2042c..0f16a9c83a 100644 --- a/base-nova/src/base/thread/thread_nova.cc +++ b/base-nova/src/base/thread/thread_nova.cc @@ -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]; diff --git a/base-nova/src/core/platform_thread.cc b/base-nova/src/core/platform_thread.cc index 7c10874462..a94b14c290 100644 --- a/base-nova/src/core/platform_thread.cc +++ b/base-nova/src/core/platform_thread.cc @@ -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); - } }