From 67c1ad4cddf30779fe3fecd0dad54517d93a3684 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 14 Nov 2013 10:35:44 +0100 Subject: [PATCH] nova: support creation of vCPU in own PD With the patch a VMM is not forced anymore to co-located the VMM and VM in same PD. Fixes #949 --- base-nova/include/base/pager.h | 14 ++++++ base-nova/include/nova/syscall-generic.h | 1 + base-nova/include/nova/util.h | 23 ++++++++++ base-nova/src/base/pager/pager.cc | 19 +++++++- base-nova/src/core/platform_thread.cc | 57 ++++++++++++------------ 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/base-nova/include/base/pager.h b/base-nova/include/base/pager.h index b218a11fb..2f8f63339 100644 --- a/base-nova/include/base/pager.h +++ b/base-nova/include/base/pager.h @@ -52,6 +52,7 @@ namespace Genode { addr_t _initial_esp; addr_t _initial_eip; addr_t _client_exc_pt_sel; + addr_t _client_exc_vcpu; struct { @@ -131,6 +132,7 @@ namespace Genode { */ addr_t exc_pt_sel() { return _tid.exc_pt_sel; } addr_t exc_pt_sel_client() { return _client_exc_pt_sel; } + addr_t exc_pt_vcpu() { return _client_exc_vcpu; } /** * Set initial stack pointer used by the startup handler @@ -226,6 +228,18 @@ namespace Genode { * all remotely available portals had been revoked beforehand. */ void cleanup_call(); + + /** + * Open receive window for initial portals for vCPU. + */ + void prepare_vCPU_portals() + { + _client_exc_vcpu = cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2); + + Nova::Utcb *utcb = reinterpret_cast(Thread_base::utcb()); + + utcb->crd_rcv = Nova::Obj_crd(_client_exc_vcpu, Nova::NUM_INITIAL_VCPU_PT_LOG2); + } }; diff --git a/base-nova/include/nova/syscall-generic.h b/base-nova/include/nova/syscall-generic.h index 653a7fe31..0f8a7256e 100644 --- a/base-nova/include/nova/syscall-generic.h +++ b/base-nova/include/nova/syscall-generic.h @@ -550,6 +550,7 @@ namespace Nova { NUM_INITIAL_PT_LOG2 = 5, NUM_INITIAL_PT = 1UL << NUM_INITIAL_PT_LOG2, NUM_INITIAL_PT_RESERVED = 2 * NUM_INITIAL_PT, + NUM_INITIAL_VCPU_PT_LOG2 = 8, }; /** diff --git a/base-nova/include/nova/util.h b/base-nova/include/nova/util.h index 159fae9dc..a9093dbf9 100644 --- a/base-nova/include/nova/util.h +++ b/base-nova/include/nova/util.h @@ -64,4 +64,27 @@ inline void request_signal_sm_cap(Genode::Native_capability const &cap, Genode::addr_t sel) { request_event_portal(cap, sel, ~0UL - 1, 0); } + +inline void delegate_vcpu_portals(Genode::Native_capability const &cap, + Genode::addr_t sel) +{ + using namespace Nova; + Utcb *utcb = reinterpret_cast(Genode::Thread_base::myself()->utcb()); + + /* save original receive window */ + Crd orig_crd = utcb->crd_rcv; + + utcb->crd_rcv = Obj_crd(); + utcb->set_msg_word(0); + uint8_t res = utcb->append_item(Obj_crd(sel, NUM_INITIAL_VCPU_PT_LOG2), 0); + (void)res; + + res = call(cap.local_name()); + + /* restore original receive window */ + utcb->crd_rcv = orig_crd; + + if (res) + PERR("setting exception portals for vCPU failed %u", res); +} #endif /* _NOVA__INCLUDE__UTIL_H_ */ diff --git a/base-nova/src/base/pager/pager.cc b/base-nova/src/base/pager/pager.cc index b2c218963..e35a0c8a5 100644 --- a/base-nova/src/base/pager/pager.cc +++ b/base-nova/src/base/pager/pager.cc @@ -194,6 +194,12 @@ void Pager_object::_invoke_handler() Pager_object *obj; Utcb *utcb = _check_handler(myself, obj); + /* if protocol is violated ignore request and close receive window */ + if (utcb->msg_words() != 2) { + utcb->crd_rcv = Obj_crd(); + reply(myself->stack_top()); + } + /* send single portal as reply */ addr_t const event = utcb->msg[0]; addr_t const logcount = utcb->msg[1]; @@ -325,8 +331,10 @@ 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(reinterpret_cast(_context->name + 6)) +: + Thread_base("pager:", PF_HANDLER_STACK_SIZE), + _badge(reinterpret_cast(_context->name + 6)), + _client_exc_vcpu(Native_thread::INVALID_INDEX) { class Create_exception_pt_failed { }; uint8_t res; @@ -441,6 +449,13 @@ Pager_object::~Pager_object() cap_map()->remove(_pt_cleanup, 1, false); cap_map()->remove(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2, false); + + if (_client_exc_vcpu == Native_thread::INVALID_INDEX) + return; + + /* revoke vCPU exception portals */ + revoke(Obj_crd(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2)); + cap_map()->remove(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2, false); } diff --git a/base-nova/src/core/platform_thread.cc b/base-nova/src/core/platform_thread.cc index 873452fe0..49d7d71dd 100644 --- a/base-nova/src/core/platform_thread.cc +++ b/base-nova/src/core/platform_thread.cc @@ -100,38 +100,32 @@ int Platform_thread::start(void *ip, void *sp) return -5; } - /* - * For the first thread of a new PD, use the initial stack pointer for - * reporting the thread's UTCB address. - */ - addr_t pd_utcb = Native_config::context_area_virtual_base() + - Native_config::context_area_virtual_size() - - get_page_size(); - - _sel_exc_base = _pager->exc_pt_sel_client(); - addr_t pd_core_sel = Platform_pd::pd_core_sel(); + addr_t pd_utcb = 0; + _sel_exc_base = is_vcpu() ? _pager->exc_pt_vcpu() : _pager->exc_pt_sel_client(); - addr_t remap_src[] = { _pd->parent_pt_sel() }; - addr_t remap_dst[] = { PT_SEL_PARENT }; - addr_t pd_sel; + if (!is_vcpu()) { + pd_utcb = Native_config::context_area_virtual_base() + + Native_config::context_area_virtual_size() - get_page_size(); - Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2); + addr_t remap_src[] = { _pd->parent_pt_sel() }; + addr_t remap_dst[] = { PT_SEL_PARENT }; - uint8_t res; - - /* remap exception 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))) - return -6; + /* remap exception 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))) + return -6; + } } - pd_sel = cap_map()->insert(); + addr_t pd_sel = cap_map()->insert(); /* create task */ - res = create_pd(pd_sel, pd_core_sel, initial_pts); + Obj_crd initial_pts(_sel_exc_base, is_vcpu() ? + NUM_INITIAL_VCPU_PT_LOG2 : NUM_INITIAL_PT_LOG2); + uint8_t res = create_pd(pd_sel, pd_core_sel, initial_pts); if (res != NOVA_OK) { PERR("create_pd returned %d", res); goto cleanup_pd; @@ -238,9 +232,6 @@ Thread_state Platform_thread::state() void Platform_thread::state(Thread_state s) { - /* not permitted for main thread */ - if (is_main_thread()) throw Cpu_session::State_access_failed(); - /* you can do it only once */ if (_sel_exc_base != Native_thread::INVALID_INDEX) throw Cpu_session::State_access_failed(); @@ -251,8 +242,16 @@ void Platform_thread::state(Thread_state s) * s.is_vcpu If true it will run as vCPU, * otherwise it will be a thread. */ - _sel_exc_base = s.sel_exc_base; - if (s.is_vcpu) _features |= VCPU; + if (!is_main_thread()) + _sel_exc_base = s.sel_exc_base; + + if (!s.is_vcpu) + return; + + _features |= VCPU; + + if (is_main_thread() && _pager) + _pager->prepare_vCPU_portals(); }