mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
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.
This commit is contained in:
parent
f68482f87a
commit
2726740d6b
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user