mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-22 03:55:26 +00:00
NOVA: use translate feature of kernel, issue #268
Kernel patch: Introduce a transfer item type to express that a cap should be translated and if this fails to map it instead. It would be possible without this combined transfer item type however with additional overhead. In this case Genode/NOVA would have to map and translate all caps used as parameter in IPC. It would look like this: * If the map and translation succeed, the cap at the new cap index would have to be revoked. Then the translated cap index can be used. * If the map succeeds and the translation fails then the mapped cap index can be used. * It would become complicated when multiple caps are mapped and translated and only some of the translation succeed. In such cases Genode would have to figure out the right relation of translated/mapped and not translated/mapped caps. It would require to make some assumption about the order how translated/mapped caps are reported at the UTCB by the kernel. All the points above lead to the decision to create a separate transfer item type for that. Genode: Most the times the translation succeeds, mapping of caps happens either seldom. This takes now a bit the pressure of not enough aligned receive cap windows as described in issue #247. The patch mainly adds adjustments to handle the translated and mapped caps correctly especially during freeing of the receive window (don't free translated cap indexes). Fixes #268
This commit is contained in:
parent
44ef8912d6
commit
2b161b7aff
@ -45,17 +45,23 @@ namespace Genode {
|
||||
/**
|
||||
* Portal capability selectors to delegate
|
||||
*/
|
||||
int _snd_pt_sel[MAX_CAP_ARGS];
|
||||
addr_t _snd_pt_sel[MAX_CAP_ARGS];
|
||||
|
||||
/**
|
||||
* Base of portal receive window
|
||||
*/
|
||||
int _rcv_pt_base;
|
||||
|
||||
struct {
|
||||
addr_t sel;
|
||||
bool del;
|
||||
} _rcv_pt_sel [MAX_CAP_ARGS];
|
||||
|
||||
/**
|
||||
* Read counter for unmarshalling portal capability selectors
|
||||
*/
|
||||
int _rcv_pt_sel_cnt;
|
||||
unsigned _rcv_pt_sel_cnt;
|
||||
unsigned _rcv_pt_sel_max;
|
||||
|
||||
/**
|
||||
* Flag set to true if receive window must be re-initialized
|
||||
@ -98,7 +104,7 @@ namespace Genode {
|
||||
/**
|
||||
* Append portal capability selector to message buffer
|
||||
*/
|
||||
inline bool snd_append_pt_sel(int pt_sel)
|
||||
inline bool snd_append_pt_sel(addr_t pt_sel)
|
||||
{
|
||||
if (_snd_pt_sel_cnt >= MAX_CAP_ARGS - 1)
|
||||
return false;
|
||||
@ -119,25 +125,35 @@ namespace Genode {
|
||||
* \return portal-capability selector, or
|
||||
* -1 if index is invalid
|
||||
*/
|
||||
int snd_pt_sel(unsigned i) { return i < _snd_pt_sel_cnt ? _snd_pt_sel[i] : -1; }
|
||||
addr_t snd_pt_sel(unsigned i) { return i < _snd_pt_sel_cnt ? _snd_pt_sel[i] : -1; }
|
||||
|
||||
/**
|
||||
* Request current portal-receive window
|
||||
*/
|
||||
int rcv_pt_base() { return _rcv_pt_base; }
|
||||
addr_t rcv_pt_base() { return _rcv_pt_base; }
|
||||
|
||||
/**
|
||||
* Reset portal-capability receive window
|
||||
*/
|
||||
void rcv_reset() { _rcv_pt_sel_cnt = 0; }
|
||||
void rcv_reset()
|
||||
{
|
||||
if (!rcv_invalid()) { rcv_cleanup(false); }
|
||||
|
||||
_rcv_pt_sel_cnt = 0;
|
||||
_rcv_pt_sel_max = 0;
|
||||
_rcv_pt_base = ~0UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return received portal-capability selector
|
||||
*/
|
||||
int rcv_pt_sel()
|
||||
addr_t rcv_pt_sel()
|
||||
{
|
||||
_rcv_dirty = true;
|
||||
return _rcv_pt_base + _rcv_pt_sel_cnt++;
|
||||
/* return only received or translated caps */
|
||||
if (_rcv_pt_sel_cnt < _rcv_pt_sel_max)
|
||||
return _rcv_pt_sel[_rcv_pt_sel_cnt++].sel;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,8 +164,62 @@ namespace Genode {
|
||||
* 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.
|
||||
*
|
||||
* \result 'true' if receive window was freed, 'false' if it was kept.
|
||||
*/
|
||||
bool rcv_dirty() { return _rcv_dirty; }
|
||||
bool rcv_cleanup(bool keep)
|
||||
{
|
||||
/* If nothing has been used, revoke/free at once */
|
||||
if (_rcv_pt_sel_cnt == 0) {
|
||||
_rcv_pt_sel_max = 0;
|
||||
|
||||
if (_rcv_items)
|
||||
Nova::revoke(Nova::Obj_crd(rcv_pt_base(), MAX_CAP_ARGS_LOG2), true);
|
||||
|
||||
if (keep) return false;
|
||||
|
||||
cap_selector_allocator()->free(rcv_pt_base(), MAX_CAP_ARGS_LOG2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Revoke received unused caps, skip translated caps */
|
||||
for (unsigned i = _rcv_pt_sel_cnt; i < _rcv_pt_sel_max; i++) {
|
||||
if (_rcv_pt_sel[i].del) {
|
||||
/* revoke cap we received but didn't use */
|
||||
Nova::revoke(Nova::Obj_crd(_rcv_pt_sel[i].sel, 0), true);
|
||||
/* mark cap as free */
|
||||
cap_selector_allocator()->free(_rcv_pt_sel[i].sel, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* free all caps which are unused from the receive window */
|
||||
for (unsigned i=0; i < MAX_CAP_ARGS; i++) {
|
||||
unsigned j=0;
|
||||
for (j=0; j < _rcv_pt_sel_max; j++) {
|
||||
if (_rcv_pt_sel[j].sel == rcv_pt_base() + i) break;
|
||||
}
|
||||
if (j < _rcv_pt_sel_max) continue;
|
||||
|
||||
/* Revoke seems needless here, but is required.
|
||||
* It is possible that an evil guy translated us
|
||||
* more then MAX_CAP_ARGS and then mapped us
|
||||
* something to the receive window.
|
||||
* The mappings would not show up
|
||||
* 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 */
|
||||
cap_selector_allocator()->free(rcv_pt_base() + i, 0);
|
||||
}
|
||||
|
||||
_rcv_pt_sel_cnt = 0;
|
||||
_rcv_pt_sel_max = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize receive window for portal capability selectors
|
||||
@ -168,7 +238,34 @@ namespace Genode {
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post IPC processing.
|
||||
*
|
||||
* Remember where and which caps have been received
|
||||
* respectively have been translated.
|
||||
* The information is required to correctly free
|
||||
* cap indexes and to revoke unused received caps.
|
||||
*
|
||||
* \param utcb UTCB of designated receiver thread
|
||||
*/
|
||||
void post_ipc(Nova::Utcb *utcb) {
|
||||
_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;
|
||||
|
||||
_rcv_pt_sel[_rcv_pt_sel_max].sel = item->crd >> 12;
|
||||
_rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -392,6 +392,7 @@ namespace Nova {
|
||||
struct Item {
|
||||
mword_t crd;
|
||||
mword_t hotspot;
|
||||
bool is_del() { return hotspot & 0x1; }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -415,7 +416,8 @@ namespace Nova {
|
||||
__attribute__((warn_unused_result))
|
||||
bool append_item(Crd crd, mword_t sel_hotspot,
|
||||
bool kern_pd = false,
|
||||
bool update_guest_pt = false)
|
||||
bool update_guest_pt = false,
|
||||
bool translate_map = false)
|
||||
{
|
||||
/* transfer items start at the end of the UTCB */
|
||||
items += 1 << 16;
|
||||
@ -433,12 +435,24 @@ namespace Nova {
|
||||
/* update guest page table */
|
||||
unsigned g = update_guest_pt ? (1 << 10) : 0;
|
||||
|
||||
item->hotspot = crd.hotspot(sel_hotspot) | g | h | 1;
|
||||
item->hotspot = crd.hotspot(sel_hotspot) | g | h | (translate_map ? 2 : 1);
|
||||
item->crd = crd.value();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typed item at postion i in UTCB
|
||||
*
|
||||
* \param i position of item requested, starts with 0
|
||||
*/
|
||||
Item * get_item(const unsigned i) {
|
||||
if (i > (PAGE_SIZE_BYTE / sizeof(struct Item))) return 0;
|
||||
Item * item = reinterpret_cast<Item *>(this) + (PAGE_SIZE_BYTE / sizeof(struct Item)) - i - 1;
|
||||
if (reinterpret_cast<mword_t *>(item) < this->msg) return 0;
|
||||
return item;
|
||||
}
|
||||
|
||||
mword_t mtd_value() const { return static_cast<Mtd>(mtd).value(); }
|
||||
} __attribute__((packed));
|
||||
|
||||
|
51
base-nova/patches/xlt_rcv.patch
Normal file
51
base-nova/patches/xlt_rcv.patch
Normal file
@ -0,0 +1,51 @@
|
||||
diff --git a/src/pd.cpp b/src/pd.cpp
|
||||
index 8160d73..be9aa63 100644
|
||||
--- a/src/pd.cpp
|
||||
+++ b/src/pd.cpp
|
||||
@@ -173,8 +173,9 @@ void Pd::xlt_crd (Pd *pd, Crd xlt, Crd &crd)
|
||||
sb = (sb - mdb->node_base) + (mdb->node_phys - node->node_phys) + node->node_base;
|
||||
|
||||
if ((ro = clamp (sb, rb, so, ro)) != ~0UL) {
|
||||
+ trace (TRACE_DEL, "XLT OBJ PD:%p->%p SB:%#010lx RB:%#010lx O:%#04lx", pd, this, crd.base(), rb, so);
|
||||
crd = Crd (crd.type(), rb, ro, mdb->node_attr);
|
||||
- return;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,22 +246,32 @@ void Pd::rev_crd (Crd crd, bool self)
|
||||
|
||||
void Pd::xfer_items (Pd *src, Crd xlt, Crd del, Xfer *s, Xfer *d, unsigned long ti)
|
||||
{
|
||||
- for (Crd crd; ti--; s--) {
|
||||
+ mword set_as_del;
|
||||
|
||||
+ for (Crd crd; ti--; s--) {
|
||||
+
|
||||
crd = *s;
|
||||
+ set_as_del = 0;
|
||||
|
||||
- switch (s->flags() & 1) {
|
||||
+ switch (s->flags() & 3) {
|
||||
|
||||
case 0:
|
||||
xlt_crd (src, xlt, crd);
|
||||
break;
|
||||
|
||||
+ case 2:
|
||||
+ xlt_crd (src, xlt, crd);
|
||||
+ if (crd.type()) break;
|
||||
+
|
||||
+ crd = *s;
|
||||
+ set_as_del = 1;
|
||||
+
|
||||
case 1:
|
||||
del_crd (src == &root && s->flags() & 0x800 ? &kern : src, del, crd, s->flags() >> 9 & 3, s->hotspot());
|
||||
break;
|
||||
};
|
||||
|
||||
if (d)
|
||||
- *d-- = Xfer (crd, s->flags());
|
||||
+ *d-- = Xfer (crd, s->flags() | set_as_del);
|
||||
}
|
||||
}
|
@ -179,6 +179,7 @@ void Ipc_server::_wait()
|
||||
|
||||
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
|
||||
|
||||
_rcv_msg->post_ipc(utcb);
|
||||
copy_utcb_to_msgbuf(utcb, _rcv_msg);
|
||||
|
||||
/* reset unmarshaller */
|
||||
|
Loading…
x
Reference in New Issue
Block a user