From 2726740d6b14bbb502fc325a129f987e45610496 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 7 Aug 2012 11:41:03 +0200 Subject: [PATCH] NOVA: enable specifying a receive index for IPC Extend Native_capability type to hold a specific selector index where the to be received cap during a IPC should be mapped to. This feature is required to place created caps by the cap_session at specific indexes. This feature is used by Vancouver to setup the virtualization exception portals (created by the cap_session) at the intended indexes. --- base-nova/include/base/ipc_msgbuf.h | 125 +++++++++++++++++++------- base-nova/include/base/native_types.h | 84 +++++++++++++---- base-nova/src/base/ipc/ipc.cc | 2 +- 3 files changed, 160 insertions(+), 51 deletions(-) diff --git a/base-nova/include/base/ipc_msgbuf.h b/base-nova/include/base/ipc_msgbuf.h index 845ca4dae5..df35c76bd9 100644 --- a/base-nova/include/base/ipc_msgbuf.h +++ b/base-nova/include/base/ipc_msgbuf.h @@ -80,11 +80,13 @@ namespace Genode { char _msg_start[]; /* symbol marks start of message */ public: + enum { INVALID_INDEX = ~0UL }; /** * Constructor */ - Msgbuf_base() : _rcv_pt_base(~0UL), _rcv_items(0) + Msgbuf_base() + : _rcv_pt_base(INVALID_INDEX), _rcv_items(0) { rcv_reset(); snd_reset(); @@ -137,15 +139,17 @@ namespace Genode { */ inline size_t snd_pt_sel_cnt() { - return _snd_pt_sel_cnt; + return _snd_pt_sel_cnt; } /** * Return portal capability selector * * \param i index (0 ... 'pt_sel_cnt()' - 1) - * \return portal-capability selector, or - * -1 if index is invalid + * \return portal-capability range descriptor + * + * The returned object could be a null cap. Use + * is_null method to check for it. */ Nova::Obj_crd snd_pt_sel(addr_t i, bool &trans_map) { @@ -154,7 +158,7 @@ namespace Genode { trans_map = _snd_pt_sel[i].trans_map; return Nova::Obj_crd(_snd_pt_sel[i].sel, 0, - _snd_pt_sel[i].rights); + _snd_pt_sel[i].rights); } /** @@ -171,7 +175,7 @@ namespace Genode { _rcv_pt_sel_cnt = 0; _rcv_pt_sel_max = 0; - _rcv_pt_base = ~0UL; + _rcv_pt_base = INVALID_INDEX; } /** @@ -183,31 +187,43 @@ namespace Genode { if (_rcv_pt_sel_cnt < _rcv_pt_sel_max) return _rcv_pt_sel[_rcv_pt_sel_cnt++].sel; else - return ~0UL; + return INVALID_INDEX; } /** * Return true if receive window must be re-initialized */ - bool rcv_invalid() { return _rcv_pt_base == ~0UL; } + bool rcv_invalid() + { + return _rcv_pt_base == INVALID_INDEX; + } /** * Return true if receive window must be re-initialized * - * After reading portal selectors from the message buffer using - * 'rcv_pt_sel()', we assume that the IDC call populated the - * current receive window with one or more portal capabilities. - * To enable the reception of portal capability selectors for the - * next IDC, we need a fresh receive window. + * After reading portal selectors from the message + * buffer using 'rcv_pt_sel()', we assume that the IDC + * call populated the current receive window with one + * or more portal capabilities. + * To enable the reception of portal capability + * selectors for the next IDC, we need a fresh receive + * window. * - * \param keep If 'true', try to keep receive window if it's clean. - * If 'false', free caps of receive window because object is freed afterwards. + * \param keep 'true' - Try to keep receive window if + * it's clean. + * 'false' - Free caps of receive window + * because object is freed + * afterwards. * - * \result 'true' if receive window was freed, 'false' if it was kept. + * \result 'true' - receive window was freed + * 'false' - portal selectors has been kept */ bool rcv_cleanup(bool keep) { - /* If nothing has been used, revoke/free at once */ + /* + * If nothing has been used, revoke and free + * at once. + */ if (_rcv_pt_sel_cnt == 0) { _rcv_pt_sel_max = 0; @@ -246,7 +262,7 @@ namespace Genode { * in _rcv_pt_sel, but would be there. */ Nova::revoke(Nova::Obj_crd(rcv_pt_base() + i, 0), true); - /* i was unused, free at allocator */ + /* i was unused, free at allocator */ cap_selector_allocator()->free(rcv_pt_base() + i, 0); } @@ -257,21 +273,49 @@ namespace Genode { } /** - * Initialize receive window for portal capability selectors + * Initialize receive window for portal capability + * selectors * - * \param utcb UTCB of designated receiver thread + * \param utcb - UTCB of designated receiver + * thread + * \param rcv_window - If specified - receive exactly + * one capability at the specified + * index of rcv_window * - * Depending on the 'rcv_dirty' state of the message buffer, this - * function allocates a fresh receive window and clears 'rcv_dirty'. + * Depending on the 'rcv_invalid', 'rcv_cleanup(true)' + * state of the message buffer and the specified + * rcv_window parameter, this function allocates a + * fresh receive window and clears 'rcv_invalid'. */ - void rcv_prepare_pt_sel_window(Nova::Utcb *utcb) + void rcv_prepare_pt_sel_window(Nova::Utcb *utcb, + addr_t rcv_window = INVALID_INDEX) { - if (rcv_invalid() || rcv_cleanup(true)) - _rcv_pt_base = cap_selector_allocator()->alloc(MAX_CAP_ARGS_LOG2); + /* + * If a rcv_window was specified use solely + * the selector specified by rcv_window. + */ + if (rcv_window != INVALID_INDEX) { + /* + * Cleanup if this msgbuf was already + * used + */ + if (!rcv_invalid()) rcv_cleanup(false); + _rcv_pt_base = rcv_window; + } else { + if (rcv_invalid() || rcv_cleanup(true)) + _rcv_pt_base = cap_selector_allocator()->alloc(MAX_CAP_ARGS_LOG2); + } + + addr_t max = 0; + if (rcv_window == INVALID_INDEX) + max = MAX_CAP_ARGS_LOG2; + + using namespace Nova; /* register receive window at the UTCB */ - utcb->crd_rcv = Nova::Obj_crd(rcv_pt_base(),MAX_CAP_ARGS_LOG2); - utcb->crd_xlt = Nova::Obj_crd(0, sizeof(addr_t) * 8 - 12); + utcb->crd_rcv = Obj_crd(rcv_pt_base(), max); + /* Open maximal translate window */ + utcb->crd_xlt = Obj_crd(0, ~0UL); } /** @@ -284,20 +328,33 @@ namespace Genode { * * \param utcb UTCB of designated receiver thread */ - void post_ipc(Nova::Utcb *utcb) { + void post_ipc(Nova::Utcb *utcb) + { + using namespace Nova; + _rcv_items = (utcb->items >> 16) & 0xffffu; _rcv_pt_sel_max = 0; _rcv_pt_sel_cnt = 0; - for (unsigned i=0; i < _rcv_items; i++) { - Nova::Utcb::Item * item = utcb->get_item(i); - if (!item) break; - if (_rcv_pt_sel_max >= MAX_CAP_ARGS) break; + addr_t max = 1UL << utcb->crd_rcv.order(); + for (unsigned i = 0; i < _rcv_items; i++) { + Utcb::Item * item = utcb->get_item(i); + if (!item || + _rcv_pt_sel_max >= max) break; - Nova::Crd cap = Nova::Crd(item->crd); - _rcv_pt_sel[_rcv_pt_sel_max].sel = cap.is_null() ? ~0UL : cap.base(); + Crd cap = Crd(item->crd); + _rcv_pt_sel[_rcv_pt_sel_max].sel = cap.is_null() ? INVALID_INDEX : cap.base(); _rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del(); } + /* + * If a specific rcv_window has been specified, + * (see rcv_prepare_pt_sel_window) then the + * caller want to take care about freeing the + * selector. Make the _rcv_pt_base invalid so + * that it is not cleanup twice. + */ + if (max != MAX_CAP_ARGS) + _rcv_pt_base = INVALID_INDEX; } }; diff --git a/base-nova/include/base/native_types.h b/base-nova/include/base/native_types.h index 1b4afecbd7..4e970c0536 100644 --- a/base-nova/include/base/native_types.h +++ b/base-nova/include/base/native_types.h @@ -22,17 +22,16 @@ namespace Genode { - typedef volatile int Native_lock; - struct Native_thread { enum { INVALID_INDEX = ~0UL }; addr_t ec_sel; /* NOVA cap selector for execution context */ addr_t exc_pt_sel; /* base of event portal window */ + bool is_vcpu; Native_thread() : ec_sel(INVALID_INDEX), - exc_pt_sel (INVALID_INDEX) { } + exc_pt_sel (INVALID_INDEX), is_vcpu(false) {} }; typedef Native_thread Native_thread_id; @@ -96,61 +95,114 @@ namespace Genode { bool _trans_map; void * _ptr; + addr_t _rcv_window; enum { INVALID_INDEX = ~0UL }; protected: explicit - Native_capability(void* ptr) : _cap(), - _trans_map(true), - _ptr(ptr) { } + Native_capability(void* ptr) + : _cap(), _trans_map(true), _ptr(ptr), + _rcv_window(INVALID_INDEX) {} public: - Native_capability() : _cap(), _trans_map(true), - _ptr(0) { } + /** + * Constructors + */ + Native_capability() + : _cap(), _trans_map(true), _ptr(0), + _rcv_window(INVALID_INDEX) {} explicit Native_capability(addr_t sel, unsigned rights = 0x1f) - : _cap(sel, rights), _trans_map(true), _ptr(0) { } + : _cap(sel, rights), _trans_map(true), _ptr(0), + _rcv_window(INVALID_INDEX) {} Native_capability(const Native_capability &o) - : _cap(o._cap), _trans_map(o._trans_map), _ptr(o._ptr) { } + : _cap(o._cap), _trans_map(o._trans_map), _ptr(o._ptr), + _rcv_window(o._rcv_window) {} - Native_capability& operator=(const Native_capability &o){ + /** + * Copy constructor + */ + Native_capability& operator= + (const Native_capability &o) + { if (this == &o) return *this; _cap = o._cap; _trans_map = o._trans_map; _ptr = o._ptr; + _rcv_window = o._rcv_window; return *this; } + /** + * Check whether the selector of the Native_cap and + * the capability type is valid. + */ bool valid() const { - return !_cap.dst.is_null() && - _cap.dst.base() != INVALID_INDEX; - } + return !_cap.dst.is_null() && + _cap.dst.base() != INVALID_INDEX; + } Dst dst() const { return _cap.dst; } + + /** + * Return pointer to the server object identified by + * this cap + */ void * local() const { return _ptr; } - addr_t local_name() const { + /** + * Return the local_name. On NOVA it is the same as the + * destination value. + */ + addr_t local_name() const + { if (valid()) return _cap.dst.base(); else return INVALID_INDEX; } + /** + * Set one specific cap selector index as receive + * window for the next IPC. This can be used to make + * sure that the to be received mapped capability will + * be placed at a specific index. + */ + void rcv_window(addr_t rcv) { _rcv_window = rcv; } + + /** + * Return the selector of the rcv_window. + */ + addr_t rcv_window() const { return _rcv_window; } + + /** + * Return an invalid Dst object + */ static Dst invalid() { return Dst(); } + /** + * Return a invalid Native_capability + */ static Native_capability invalid_cap() { return Native_capability(INVALID_INDEX); } - /** Invoke map syscall instead of translate_map call */ + /** + * Invoke map syscall instead of translate_map call + */ void solely_map() { _trans_map = false; } + + /** + * Return true if the cap should be tried first to + * be translated and if this fails it should be mapped. + */ bool trans_map() const { return _trans_map; } }; diff --git a/base-nova/src/base/ipc/ipc.cc b/base-nova/src/base/ipc/ipc.cc index 88ddada0dd..fa645e5422 100644 --- a/base-nova/src/base/ipc/ipc.cc +++ b/base-nova/src/base/ipc/ipc.cc @@ -140,7 +140,7 @@ void Ipc_client::_call() PERR("could not setup IPC"); return; } - _rcv_msg->rcv_prepare_pt_sel_window(utcb); + _rcv_msg->rcv_prepare_pt_sel_window(utcb, Ipc_ostream::_dst.rcv_window()); /* establish the mapping via a portal traversal */ uint8_t res = Nova::call(Ipc_ostream::_dst.local_name());