diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index 9496477b8..185938b27 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -730,7 +730,6 @@ namespace Nova { enum { PT_SEL_PAGE_FAULT = 0xe, PT_SEL_PARENT = 0x1a, /* convention on Genode */ - PT_SEL_MAIN_PAGER = 0x1b, /* convention on Genode */ PT_SEL_MAIN_EC = 0x1c, /* convention on Genode */ PT_SEL_STARTUP = 0x1e, PT_SEL_RECALL = 0x1f, diff --git a/repos/base-nova/include/nova/util.h b/repos/base-nova/include/nova/util.h index 3f47c1f8b..556d968d4 100644 --- a/repos/base-nova/include/nova/util.h +++ b/repos/base-nova/include/nova/util.h @@ -29,9 +29,8 @@ inline void nova_die(const char * text = 0) } -inline void request_event_portal(Genode::Native_capability const &cap, - Genode::addr_t sel, Genode::addr_t event, - unsigned short log2_count = 0) +inline void request_event_portal(Genode::addr_t const cap, + Genode::addr_t const sel, Genode::addr_t event) { Genode::Thread * myself = Genode::Thread::myself(); Nova::Utcb *utcb = reinterpret_cast(myself->utcb()); @@ -40,38 +39,36 @@ inline void request_event_portal(Genode::Native_capability const &cap, Nova::Crd orig_crd = utcb->crd_rcv; /* request event-handler portal */ - utcb->crd_rcv = Nova::Obj_crd(sel, log2_count); + utcb->crd_rcv = Nova::Obj_crd(sel, 0); utcb->msg[0] = event; - utcb->msg[1] = log2_count; - utcb->set_msg_word(2); + utcb->set_msg_word(1); - Genode::uint8_t res = Nova::call(cap.local_name()); + Genode::uint8_t res = Nova::call(cap); /* restore original receive window */ utcb->crd_rcv = orig_crd; if (res) - Genode::error("request of event (", event, ") ", + Genode::error("request of event (", Genode::Hex(event), ") ", "capability selector failed (res=", res, ")"); } -inline void request_native_ec_cap(Genode::Native_capability const &cap, - Genode::addr_t const sel, - unsigned const no_pager_cap = 0) -{ - request_event_portal(cap, sel , ~0UL, no_pager_cap); -} - - -inline void request_signal_sm_cap(Genode::Native_capability const &cap, +inline void request_native_ec_cap(Genode::addr_t const cap, Genode::addr_t const sel) { - request_event_portal(cap, sel, ~0UL - 1, 0); + request_event_portal(cap, sel , ~0UL); } -inline void translate_remote_pager(Genode::Native_capability const &cap, +inline void request_signal_sm_cap(Genode::addr_t const cap, + Genode::addr_t const sel) +{ + request_event_portal(cap, sel, ~0UL - 1); +} + + +inline void translate_remote_pager(Genode::addr_t const cap, Genode::addr_t const sel) { Genode::Thread * myself = Genode::Thread::myself(); @@ -94,7 +91,7 @@ inline void translate_remote_pager(Genode::Native_capability const &cap, Nova::Obj_crd obj_crd(sel, 0); if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE)) /* trigger the translation */ - res = Nova::call(cap.local_name()); + res = Nova::call(cap); /* restore original receive window */ utcb->crd_rcv = orig_crd; diff --git a/repos/base-nova/src/core/include/nova_util.h b/repos/base-nova/src/core/include/nova_util.h index 6a386e06d..53623643a 100644 --- a/repos/base-nova/src/core/include/nova_util.h +++ b/repos/base-nova/src/core/include/nova_util.h @@ -222,4 +222,69 @@ inline void unmap_local(Nova::Utcb *utcb, Genode::addr_t start, } +template +inline Nova::uint8_t syscall_retry(Genode::Pager_object &pager, FUNC func) +{ + Nova::uint8_t res; + do { + res = func(); + } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == pager.handle_oom()); + + return res; +} + +inline Nova::uint8_t async_map(Genode::Pager_object &pager, + Genode::addr_t const source_pd, + Genode::addr_t const target_pd, + Nova::Obj_crd const &source_initial_caps, + Nova::Obj_crd const &target_initial_caps, + Nova::Utcb *utcb) +{ + /* asynchronously map capabilities */ + utcb->set_msg_word(0); + + /* ignore return value as one item always fits into the utcb */ + bool const ok = utcb->append_item(source_initial_caps, 0); + (void)ok; + + return syscall_retry(pager, + [&]() { + return Nova::delegate(source_pd, target_pd, target_initial_caps); + }); +} + +inline Nova::uint8_t map_vcpu_portals(Genode::Pager_object &pager, + Genode::addr_t const source_exc_base, + Genode::addr_t const target_exc_base, + Nova::Utcb *utcb, + Genode::addr_t const source_pd) +{ + using Nova::Obj_crd; + using Nova::NUM_INITIAL_VCPU_PT_LOG2; + + Obj_crd const source_initial_caps(source_exc_base, NUM_INITIAL_VCPU_PT_LOG2); + Obj_crd const target_initial_caps(target_exc_base, NUM_INITIAL_VCPU_PT_LOG2); + + return async_map(pager, source_pd, pager.pd_sel(), + source_initial_caps, target_initial_caps, utcb); +} + +inline Nova::uint8_t map_pagefault_portal(Genode::Pager_object &pager, + Genode::addr_t const source_exc_base, + Genode::addr_t const target_exc_base, + Genode::addr_t const target_pd, + Nova::Utcb *utcb) +{ + using Nova::Obj_crd; + using Nova::PT_SEL_PAGE_FAULT; + + Genode::addr_t const source_pd = Genode::platform_specific()->core_pd_sel(); + + Obj_crd const source_initial_caps(source_exc_base + PT_SEL_PAGE_FAULT, 0); + Obj_crd const target_initial_caps(target_exc_base + PT_SEL_PAGE_FAULT, 0); + + return async_map(pager, source_pd, target_pd, + source_initial_caps, target_initial_caps, utcb); +} + #endif /* _CORE__INCLUDE__NOVA_UTIL_H_ */ diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h index 5cd9f5d9c..9b608bcd2 100644 --- a/repos/base-nova/src/core/include/pager.h +++ b/repos/base-nova/src/core/include/pager.h @@ -121,7 +121,6 @@ namespace Genode { Exception_handlers _exceptions; addr_t _pd_target; - addr_t _pd_source; void _copy_state_from_utcb(Nova::Utcb * utcb); void _copy_state_to_utcb(Nova::Utcb * utcb); @@ -179,15 +178,8 @@ namespace Genode { /** * Assign PD selector to PD */ - void assign_pd(addr_t pd_sel) - { - if (_pd_target == _pd_source) - _pd_source = pd_sel; - - _pd_target = pd_sel; - } + void assign_pd(addr_t pd_sel) { _pd_target = pd_sel; } addr_t pd_sel() const { return _pd_target; } - addr_t pd_source() const { return _pd_source; } void exception(uint8_t exit_id); @@ -227,14 +219,6 @@ namespace Genode { return true; } - /** - * Return entry point address - */ - addr_t handler_address() - { - return reinterpret_cast(_invoke_handler); - } - /** * Copy thread state of recalled thread. */ @@ -403,15 +387,6 @@ namespace Genode { Pager_activation_base(char const * const name, size_t const stack_size); - /** - * Set entry point, which the activation serves - * - * This function is only called by the 'Pager_entrypoint' - * constructor. - */ - void ep(Pager_entrypoint *ep) { _ep = ep; } - Pager_entrypoint *ep() { return _ep; } - /** * Thread interface */ @@ -440,11 +415,6 @@ namespace Genode { */ class Pager_entrypoint : public Object_pool { - private: - - Pager_activation_base *_activation; - Rpc_cap_factory &_cap_factory; - public: /** @@ -459,7 +429,8 @@ namespace Genode { /** * Associate Pager_object with the entry point */ - Pager_capability manage(Pager_object *obj); + Pager_capability manage(Pager_object *) { + return Pager_capability(); } /** * Dissolve Pager_object from entry point diff --git a/repos/base-nova/src/core/include/platform_pd.h b/repos/base-nova/src/core/include/platform_pd.h index 0a7bc7a52..19697034c 100644 --- a/repos/base-nova/src/core/include/platform_pd.h +++ b/repos/base-nova/src/core/include/platform_pd.h @@ -28,7 +28,7 @@ namespace Genode { Native_capability _parent; int _thread_cnt; - addr_t _pd_sel; + addr_t const _pd_sel; const char * _label; public: @@ -66,11 +66,6 @@ namespace Genode { */ addr_t parent_pt_sel() { return _parent.local_name(); } - /** - * Assign PD selector to PD - */ - void assign_pd(addr_t pd_sel) { _pd_sel = pd_sel; } - /** * Capability selector of this task. * diff --git a/repos/base-nova/src/core/include/platform_thread.h b/repos/base-nova/src/core/include/platform_thread.h index 485c1fab9..fb51b7e4d 100644 --- a/repos/base-nova/src/core/include/platform_thread.h +++ b/repos/base-nova/src/core/include/platform_thread.h @@ -45,6 +45,7 @@ namespace Genode { VCPU = 0x2U, WORKER = 0x4U, SC_CREATED = 0x8U, + REMOTE_PD = 0x10U, }; uint8_t _features; uint8_t _priority; @@ -60,9 +61,19 @@ namespace Genode { inline bool vcpu() const { return _features & VCPU; } inline bool worker() const { return _features & WORKER; } inline bool sc_created() const { return _features & SC_CREATED; } + inline bool remote_pd() const { return _features & REMOTE_PD; } public: + /* mark as vcpu in remote pd if it is a vcpu */ + addr_t remote_vcpu() { + if (!vcpu()) + return Native_thread::INVALID_INDEX; + + _features |= Platform_thread::REMOTE_PD; + return _sel_exc_base; + } + /* invalid thread number */ enum { THREAD_INVALID = -1 }; @@ -137,7 +148,7 @@ namespace Genode { /** * Set pager */ - void pager(Pager_object *pager) { _pager = pager; } + void pager(Pager_object *pager); /** * Return pager object diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index b52555685..578c7435e 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -25,6 +25,8 @@ #include #include #include +#include +#include /* NOVA includes */ #include @@ -115,6 +117,10 @@ void Pager_object::_page_fault_handler(addr_t pager_obj) Pager_activation_base * pager_thread = static_cast(myself); + /* potential request to ask for EC cap or signal SM cap */ + if (utcb->msg_words() == 1) + _invoke_handler(pager_obj); + /* lookup fault address and decide what to do */ int error = obj->pager(ipc_pager); @@ -298,8 +304,14 @@ void Pager_object::_invoke_handler(addr_t pager_obj) if (utcb->crd_rcv.value()) nova_die(); - addr_t const event = utcb->msg[0]; - addr_t const logcount = utcb->msg[1]; + /* if protocol is violated ignore request */ + if (utcb->msg_words() != 1) { + utcb->mtd = 0; + utcb->set_msg_word(0); + reply(myself->stack_top()); + } + + addr_t const event = utcb->msg[0]; /* check for translated pager portals - required for vCPU in remote PDs */ if (utcb->msg_items() == 1 && utcb->msg_words() == 1 && event == 0xaffe) { @@ -309,17 +321,27 @@ void Pager_object::_invoke_handler(addr_t pager_obj) /* valid item which got translated ? */ if (!cap.is_null() && !item->is_del()) { - using Pool = Object_pool; - pager_threads[0]->ep()->Pool::apply(cap.base(), - [&] (Pager_object *source) { - /* set source PD (VMM) where vCPU exception portals are */ - obj->_pd_source = source->pd_sel(); - }); - } - } + Rpc_entrypoint *e = core_env()->entrypoint(); + e->apply(cap.base(), + [&] (Cpu_thread_component *source) { + if (!source) + return; + + Platform_thread &p = source->platform_thread(); + addr_t const sel_exc_base = p.remote_vcpu(); + if (sel_exc_base == Native_thread::INVALID_INDEX) + return; + + /* delegate VM-exit portals */ + map_vcpu_portals(*p.pager(), sel_exc_base, sel_exc_base, + utcb, obj->pd_sel()); + + /* delegate portal to contact pager */ + map_pagefault_portal(*obj, p.pager()->exc_pt_sel_client(), + sel_exc_base, obj->pd_sel(), utcb); + }); + } - /* if protocol is violated ignore request */ - if (utcb->msg_words() != 2) { utcb->mtd = 0; utcb->set_msg_word(0); reply(myself->stack_top()); @@ -345,12 +367,7 @@ void Pager_object::_invoke_handler(addr_t pager_obj) */ bool res = utcb->append_item(Obj_crd(obj->_state.sel_client_ec, 0, Obj_crd::RIGHT_EC_RECALL), 0); - /* if logcount > 0 then the pager cap should also be mapped */ - if (logcount) - res = utcb->append_item(Obj_crd(obj->Object_pool::Entry::cap().local_name(), 0), 1); (void)res; - - reply(myself->stack_top()); } /* semaphore for signaling thread is requested, reuse PT_SEL_STARTUP. */ @@ -371,20 +388,8 @@ void Pager_object::_invoke_handler(addr_t pager_obj) bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + PT_SEL_STARTUP, 0), 0); (void)res; - - reply(myself->stack_top()); } - /* sanity check, if event is not valid return nothing */ - if (logcount > NUM_INITIAL_PT_LOG2 || event > 1UL << NUM_INITIAL_PT_LOG2 || - event + (1UL << logcount) > (1UL << NUM_INITIAL_PT_LOG2)) - reply(myself->stack_top()); - - /* valid event portal is requested, delegate it to caller */ - bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + event, - logcount), 0); - (void)res; - reply(myself->stack_top()); } @@ -479,16 +484,14 @@ void Pager_object::print(Output &out) const static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd, addr_t eip, Pager_object * oom_handler) { - addr_t const badge_localname = reinterpret_cast(oom_handler); - - uint8_t res; - do { - res = create_pt(pt, pd, ec, mtd, eip); - } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == oom_handler->handle_oom()); + uint8_t res = syscall_retry(*oom_handler, + [&]() { return create_pt(pt, pd, ec, mtd, eip); }); if (res != NOVA_OK) return res; + addr_t const badge_localname = reinterpret_cast(oom_handler); + res = pt_ctrl(pt, badge_localname); if (res == NOVA_OK) revoke(Obj_crd(pt, 0, Obj_crd::RIGHT_PT_CTRL)); @@ -582,8 +585,7 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, _cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap), _location(location), _exceptions(this), - _pd_target(Native_thread::INVALID_INDEX), - _pd_source(Native_thread::INVALID_INDEX) + _pd_target(Native_thread::INVALID_INDEX) { uint8_t res; @@ -934,7 +936,6 @@ void Pager_activation_base::entry() { } Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory) -: _cap_factory(cap_factory) { /* sanity check for pager threads */ if (kernel_hip()->cpu_max() > PAGER_CPUS) { @@ -954,56 +955,12 @@ Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory) pager_threads[i] = pager_of_cpu; construct_at(pager_threads[i]); - pager_threads[i]->ep(this); } } -Pager_capability Pager_entrypoint::manage(Pager_object *obj) -{ - /* let handle pager_object of pager thread on same CPU */ - unsigned const genode_cpu_id = obj->location().xpos(); - unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id); - if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id) || - !pager_threads[genode_cpu_id]) { - warning("invalid CPU parameter used in pager object"); - return Pager_capability(); - } - Native_capability pager_thread_cap = - Capability_space::import(pager_threads[genode_cpu_id]->native_thread().ec_sel); - - /* request creation of portal bind to pager thread */ - Native_capability cap_session = - _cap_factory.alloc(pager_thread_cap, obj->handler_address(), 0); - - imprint_badge(cap_session.local_name(), reinterpret_cast(obj)); - - /* disable the feature for security reasons now */ - revoke(Obj_crd(cap_session.local_name(), 0, Obj_crd::RIGHT_PT_CTRL)); - - /* add server object to object pool */ - obj->Object_pool::Entry::cap(cap_session); - insert(obj); - - /* return capability that uses the object id as badge */ - return reinterpret_cap_cast( - obj->Object_pool::Entry::cap()); -} - - void Pager_entrypoint::dissolve(Pager_object *obj) { - Native_capability pager_obj = obj->Object_pool::Entry::cap(); - - /* cleanup at cap factory */ - _cap_factory.free(pager_obj); - - /* revoke cap selector locally */ - revoke(Capability_space::crd(pager_obj), true); - - /* remove object from pool */ - remove(obj); - /* take care that no faults are in-flight */ obj->cleanup_call(); } diff --git a/repos/base-nova/src/core/platform_pd.cc b/repos/base-nova/src/core/platform_pd.cc index 5f6e960fa..c89ac800c 100644 --- a/repos/base-nova/src/core/platform_pd.cc +++ b/repos/base-nova/src/core/platform_pd.cc @@ -16,6 +16,7 @@ #include /* core includes */ +#include #include using namespace Genode; @@ -48,7 +49,23 @@ void Platform_pd::assign_parent(Native_capability parent) Platform_pd::Platform_pd(Allocator * md_alloc, char const *label, signed pd_id, bool create) -: _thread_cnt(0), _pd_sel(Native_thread::INVALID_INDEX), _label(label) { } +: _thread_cnt(0), _pd_sel(cap_map()->insert()), _label(label) +{ + if (_pd_sel == Native_thread::INVALID_INDEX) { + error("platform pd creation failed "); + return; + } + + /* create task */ + enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 }; + uint8_t res = Nova::create_pd(_pd_sel, platform_specific()->core_pd_sel(), + Nova::Obj_crd(), + KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE, + UPPER_LIMIT_PAGES); + + if (res != Nova::NOVA_OK) + error("create_pd returned ", res); +} Platform_pd::~Platform_pd() diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index dff3a839a..6793922a5 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -34,6 +34,33 @@ using namespace Genode; + +static uint8_t map_thread_portals(Pager_object &pager, + addr_t const target_exc_base, + Nova::Utcb *utcb) +{ + using Nova::Obj_crd; + using Nova::NUM_INITIAL_PT_LOG2; + + addr_t const source_pd = platform_specific()->core_pd_sel(); + addr_t const source_exc_base = pager.exc_pt_sel_client(); + addr_t const target_pd = pager.pd_sel(); + + /* xxx better map portals with solely pt_call and sm separately ? xxx */ + addr_t const rights = Obj_crd::RIGHT_EC_RECALL | + Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL | + Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN; + + Obj_crd const source_initial_caps(source_exc_base, NUM_INITIAL_PT_LOG2, + rights); + Obj_crd const target_initial_caps(target_exc_base, NUM_INITIAL_PT_LOG2, + rights); + + return async_map(pager, source_pd, target_pd, + source_initial_caps, target_initial_caps, utcb); +} + + /********************* ** Platform thread ** *********************/ @@ -62,14 +89,8 @@ int Platform_thread::start(void *ip, void *sp) return -2; } - if (_pager->pd_sel() != Native_thread::INVALID_INDEX) { - error("thread already started"); - return -2; - } - Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); - addr_t const pts = vcpu() ? NUM_INITIAL_VCPU_PT_LOG2 - : NUM_INITIAL_PT_LOG2; + unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos()); addr_t const pt_oom = _pager->get_oom_portal(); if (!pt_oom || map_local(utcb, @@ -87,35 +108,30 @@ int Platform_thread::start(void *ip, void *sp) return -3; } - _pager->assign_pd(_pd->pd_sel()); + uint8_t res = syscall_retry(*_pager, + [&]() { + return create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + utcb_addr, initial_sp, _sel_exc_base, + !worker()); + }); - /* second++ vcpu case which runs in other pd than VMM */ - if (vcpu() && _pager->pd_sel() != _pager->pd_source()) { - Obj_crd const source_initial_caps(_sel_exc_base, pts); - Obj_crd const target_initial_caps(_sel_exc_base, pts); - - /* asynchronously map capabilities */ - utcb->set_msg_word(0); - if (!utcb->append_item(source_initial_caps, 0)) - return -3; - - uint8_t res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(), - target_initial_caps); - if (res != NOVA_OK) - return -3; + if (res != Nova::NOVA_OK) { + error("creation of new thread failed ", res); + return -4; } - uint8_t res; - do { - unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos()); - res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, - utcb_addr, initial_sp, _sel_exc_base, !worker()); - if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) { - _pager->assign_pd(Native_thread::INVALID_INDEX); - error("creation of new thread failed ", res); - return -4; - } - } while (res != Nova::NOVA_OK); + if (vcpu()) { + if (!remote_pd()) + res = map_pagefault_portal(*_pager, _pager->exc_pt_sel_client(), + _sel_exc_base, _pd->pd_sel(), utcb); + } else + res = map_thread_portals(*_pager, _sel_exc_base, utcb); + + if (res != NOVA_OK) { + revoke(Obj_crd(_sel_ec(), 0)); + error("creation of new thread/vcpu failed ", res); + return -3; + } if (worker()) { /* local/worker threads do not require a startup portal */ @@ -135,21 +151,14 @@ int Platform_thread::start(void *ip, void *sp) } addr_t pd_utcb = 0; - Obj_crd initial_pts; if (!vcpu()) { _sel_exc_base = _pager->exc_pt_sel_client(); pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size(); - addr_t const rights = Obj_crd::RIGHT_EC_RECALL | - Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL | - Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN; - initial_pts = Obj_crd(_sel_exc_base, pts, rights); - - addr_t remap_src[] = { _pd->parent_pt_sel(), - (unsigned long)_pager->Object_pool::Entry::cap().local_name() }; - addr_t remap_dst[] = { PT_SEL_PARENT, PT_SEL_MAIN_PAGER }; + addr_t remap_src[] = { _pd->parent_pt_sel() }; + addr_t remap_dst[] = { PT_SEL_PARENT }; /* remap exception portals for first thread */ for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) { @@ -160,88 +169,49 @@ int Platform_thread::start(void *ip, void *sp) } } - /* create task */ - addr_t const pd_sel = cap_map()->insert(); - - enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 }; - uint8_t res = create_pd(pd_sel, platform_specific()->core_pd_sel(), - initial_pts, - KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE, - UPPER_LIMIT_PAGES); - if (res != NOVA_OK) { - error("create_pd returned ", res); - goto cleanup_pd; - } - /* create first thread in task */ enum { THREAD_GLOBAL = true }; - res = create_ec(_sel_ec(), pd_sel, - platform_specific()->kernel_cpu_id(_location.xpos()), - pd_utcb, 0, 0, - THREAD_GLOBAL); + uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + pd_utcb, 0, vcpu() ? _sel_exc_base : 0, + THREAD_GLOBAL); if (res != NOVA_OK) { error("create_ec returned ", res); - goto cleanup_pd; + return -7; } - /* - * We have to assign the pd here, because after create_sc the thread - * becomes running immediately. - */ - _pd->assign_pd(pd_sel); _pager->client_set_ec(_sel_ec()); _pager->initial_eip((addr_t)ip); _pager->initial_esp((addr_t)sp); - _pager->assign_pd(pd_sel); - if (vcpu() && _pager->pd_sel() != _pager->pd_source()) { - Obj_crd const source_initial_caps(_sel_exc_base, pts); - Obj_crd const target_initial_caps(0, pts); - - /* asynchronously map capabilities */ - utcb->set_msg_word(0); - res = utcb->append_item(source_initial_caps, 0); - if (res) - res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(), - target_initial_caps); - } + if (vcpu()) + _features |= REMOTE_PD; + else + res = map_thread_portals(*_pager, 0, utcb); if (res == NOVA_OK) { - do { - /* let the thread run */ - res = create_sc(_sel_sc(), pd_sel, _sel_ec(), - Qpd(Qpd::DEFAULT_QUANTUM, _priority)); - } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom()); + res = syscall_retry(*_pager, + [&]() { + /* let the thread run */ + return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + Qpd(Qpd::DEFAULT_QUANTUM, _priority)); + }); } if (res != NOVA_OK) { - /* - * Reset pd cap since thread got not running and pd cap will - * be revoked during cleanup. - */ - _pd->assign_pd(Native_thread::INVALID_INDEX); _pager->client_set_ec(Native_thread::INVALID_INDEX); _pager->initial_eip(0); _pager->initial_esp(0); - _pager->assign_pd(Native_thread::INVALID_INDEX); error("create_sc returned ", res); - goto cleanup_ec; + + /* cap_selector free for _sel_ec is done in de-constructor */ + revoke(Obj_crd(_sel_ec(), 0)); + return -8; } _features |= SC_CREATED; 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_map()->remove(pd_sel, 0, false); - - return -7; } @@ -264,15 +234,16 @@ void Platform_thread::resume() return; } - uint8_t res; - do { - if (!_pd) { - error("protection domain undefined - resuming thread failed"); - return; - } - res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), - Qpd(Qpd::DEFAULT_QUANTUM, _priority)); - } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom()); + if (!_pd || !_pager) { + error("protection domain undefined - resuming thread failed"); + return; + } + + uint8_t res = syscall_retry(*_pager, + [&]() { + return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + Qpd(Qpd::DEFAULT_QUANTUM, _priority)); + }); if (res == NOVA_OK) _features |= SC_CREATED; @@ -374,6 +345,13 @@ unsigned long long Platform_thread::execution_time() const } +void Platform_thread::pager(Pager_object *pager) +{ + _pager = pager; + _pager->assign_pd(_pd->pd_sel()); +} + + Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, Affinity::Location affinity, int thread_id) : diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index bf3d57a47..00721f759 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -24,8 +24,8 @@ #include /* core includes */ -#include #include +#include using namespace Genode; diff --git a/repos/base-nova/src/include/signal_source/client.h b/repos/base-nova/src/include/signal_source/client.h index b1ddb028e..7fb347246 100644 --- a/repos/base-nova/src/include/signal_source/client.h +++ b/repos/base-nova/src/include/signal_source/client.h @@ -54,7 +54,7 @@ namespace Genode { { /* request mapping of semaphore capability selector */ Thread * myself = Thread::myself(); - request_signal_sm_cap(Capability_space::import(myself->native_thread().ec_sel + 1), + request_signal_sm_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP); _sem = Capability_space::import(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP); call(_sem); diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc index d1a948ec8..04047b70f 100644 --- a/repos/base-nova/src/lib/base/thread_start.cc +++ b/repos/base-nova/src/lib/base/thread_start.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include /* base-internal includes */ @@ -82,13 +81,10 @@ void Thread::_init_platform_thread(size_t weight, Type type) if (type == MAIN || type == REINITIALIZED_MAIN) { _thread_cap = env()->parent()->main_thread_cap(); - Genode::Native_capability pager_cap = - Capability_space::import(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); + request_native_ec_cap(PT_SEL_PAGE_FAULT, native_thread().ec_sel); return; } @@ -126,8 +122,8 @@ void Thread::_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); + revoke(Obj_crd(native_thread().ec_sel, 0)); + cap_map()->remove(native_thread().ec_sel, 0, false); } /* de-announce thread */ @@ -151,14 +147,6 @@ void Thread::start() 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; @@ -175,20 +163,20 @@ void Thread::start() cpu_thread.start(thread_ip, _stack->top()); /* request native EC thread cap */ - native_thread().ec_sel = cap_map()->insert(1); + native_thread().ec_sel = cap_map()->insert(); 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); + /* + * Requested ec cap that is used for recall and + * creation of portals (Nova_native_pd::alloc_rpc_cap). + */ + request_native_ec_cap(native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, + native_thread().ec_sel); using namespace Nova; - /* request exception portals for normal threads */ if (!native_thread().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_obj->crd_rcv = Obj_crd(); diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc index a7dae5831..d24734ceb 100644 --- a/repos/base-nova/src/test/platform/main.cc +++ b/repos/base-nova/src/test/platform/main.cc @@ -227,8 +227,8 @@ void test_revoke(Genode::Env &env) * as used before by copy_session_cap */ Genode::Thread * myself = Genode::Thread::myself(); - Genode::Native_capability pager_cap = Capability_space::import(myself->native_thread().ec_sel + 1); - request_event_portal(pager_cap, copy_session_cap.local_name(), 0, 0); + request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, + copy_session_cap.local_name()); /* check whether the requested cap before is valid and placed well */ crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h index 80db8a4b4..20a6a5e6d 100644 --- a/repos/ports/include/vmm/vcpu_thread.h +++ b/repos/ports/include/vmm/vcpu_thread.h @@ -20,7 +20,6 @@ #include #include #include -#include #include /* NOVA includes */ @@ -79,21 +78,15 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread state.vcpu = true; Cpu_thread_client cpu_thread(vcpu_vm); - cpu_thread.state(state); - /* 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(vcpu_vm); - /* - * Translate pager cap of current executing thread, which is used - * to lookup current PD - required during PD creation. + * Translate vcpu_vm thread cap via current executing thread, + * which is used to lookup current PD to delegate VM-exit portals. */ - translate_remote_pager(pager_cap, - Thread::myself()->native_thread().ec_sel + 1); + addr_t const current = Thread::myself()->native_thread().exc_pt_sel + + Nova::PT_SEL_PAGE_FAULT; + translate_remote_pager(current, vcpu_vm.local_name()); /* start vCPU in separate PD */ cpu_thread.start(0, 0); @@ -102,7 +95,11 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread * Request native EC thread cap and put it next to the * SM cap - see Vcpu_dispatcher->sel_sm_ec description */ - request_native_ec_cap(pager_cap, sel_ec); + addr_t const pager_pt = _exc_pt_sel + Nova::PT_SEL_PAGE_FAULT; + request_native_ec_cap(pager_pt, sel_ec); + + /* solely needed for vcpu to request native ec cap - drop it */ + Nova::revoke(Nova::Obj_crd(pager_pt, 0)); /* request creation of SC to let vCPU run */ cpu_thread.resume(); @@ -152,15 +149,15 @@ class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread { this->Thread::start(); - /* obtain interface to NOVA-specific CPU session operations */ - Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); - /* * Request native EC thread cap and put it next to the * SM cap - see Vcpu_dispatcher->sel_sm_ec description */ - Native_capability pager_cap = native_cpu.pager_cap(_thread_cap); - request_native_ec_cap(pager_cap, sel_ec); + addr_t const pager_pt = exc_base() + Nova::PT_SEL_PAGE_FAULT; + request_native_ec_cap(pager_pt, sel_ec); + + /* solely needed for vcpu to request native ec cap - drop it */ + Nova::revoke(Nova::Obj_crd(pager_pt, 0)); } void entry() { }