diff --git a/repos/base-hw/include/base/native_types.h b/repos/base-hw/include/base/native_types.h index 6fd0445fc2..30fff4e9ca 100644 --- a/repos/base-hw/include/base/native_types.h +++ b/repos/base-hw/include/base/native_types.h @@ -161,7 +161,10 @@ class Genode::Native_utcb void copy_to(Msgbuf_base &o) { o._snd_cap_cnt = _cap_cnt; - for (unsigned i = 0; i < _cap_cnt; i++) o._caps[i] = _caps[i]; + for (unsigned i = 0; i < _cap_cnt; i++) { + o._caps[i] = _caps[i]; + if (o._caps[i].valid()) Kernel::ack_cap(o._caps[i].dst()); + } memcpy(o.buf, _buf, min(_size, o._size)); } diff --git a/repos/base-hw/include/kernel/interface.h b/repos/base-hw/include/kernel/interface.h index b74f5a08d1..aee31bf025 100644 --- a/repos/base-hw/include/kernel/interface.h +++ b/repos/base-hw/include/kernel/interface.h @@ -41,7 +41,8 @@ namespace Kernel constexpr Call_arg call_id_print_char() { return 10; } constexpr Call_arg call_id_update_data_region() { return 11; } constexpr Call_arg call_id_update_instr_region() { return 12; } - constexpr Call_arg call_id_delete_cap() { return 13; } + constexpr Call_arg call_id_ack_cap() { return 13; } + constexpr Call_arg call_id_delete_cap() { return 14; } /***************************************************************** @@ -266,6 +267,16 @@ namespace Kernel return call(call_id_kill_signal_context(), context); } + /** + * Acknowledge reception of a capability + * + * \param cap capability id to acknowledge + */ + inline void ack_cap(capid_t const cap) + { + call(call_id_ack_cap(), cap); + } + /** * Delete a capability id * diff --git a/repos/base-hw/src/core/include/kernel/object.h b/repos/base-hw/src/core/include/kernel/object.h index e043f13ec5..6adfd5acf7 100644 --- a/repos/base-hw/src/core/include/kernel/object.h +++ b/repos/base-hw/src/core/include/kernel/object.h @@ -106,6 +106,7 @@ class Kernel::Object_identity_reference capid_t _capid; Object_identity *_identity; Pd &_pd; + unsigned short _in_utcbs; public: @@ -125,6 +126,10 @@ class Kernel::Object_identity_reference Pd & pd() { return _pd; } capid_t capid() { return _capid; } + void add_to_utcb() { _in_utcbs++; } + void remove_from_utcb() { _in_utcbs--; } + bool in_utcb() { return _in_utcbs > 0; } + void invalidate(); diff --git a/repos/base-hw/src/core/include/kernel/thread.h b/repos/base-hw/src/core/include/kernel/thread.h index 5c180a93f1..719b88fd3c 100644 --- a/repos/base-hw/src/core/include/kernel/thread.h +++ b/repos/base-hw/src/core/include/kernel/thread.h @@ -244,6 +244,7 @@ class Kernel::Thread void _call_ack_irq(); void _call_new_obj(); void _call_delete_obj(); + void _call_ack_cap(); void _call_delete_cap(); template diff --git a/repos/base-hw/src/core/kernel/ipc_node.cc b/repos/base-hw/src/core/kernel/ipc_node.cc index 1f2d803944..493bcc70ae 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.cc +++ b/repos/base-hw/src/core/kernel/ipc_node.cc @@ -47,13 +47,6 @@ void Ipc_node::copy_msg(Ipc_node * const sender) continue; } - /* within the same pd, we can simply copy the id */ - if (pd() == sender->pd()) { - _utcb->cap_add(id); - pd()->platform_pd()->capability_slab().free(_obj_id_ref_ptr[i]); - continue; - } - /* lookup the capability id within the caller's cap space */ Reference *oir = (id == cap_id_invalid()) ? nullptr : sender->pd()->cap_tree().find(id); @@ -76,6 +69,8 @@ void Ipc_node::copy_msg(Ipc_node * const sender) } else /* otherwise free the pre-allocation */ pd()->platform_pd()->capability_slab().free(_obj_id_ref_ptr[i]); + if (dst_oir) dst_oir->add_to_utcb(); + /* add the translated capability id to the target buffer */ _utcb->cap_add(dst_oir ? dst_oir->capid() : cap_id_invalid()); } diff --git a/repos/base-hw/src/core/kernel/object.cc b/repos/base-hw/src/core/kernel/object.cc index 83bdefb697..fdd4006138 100644 --- a/repos/base-hw/src/core/kernel/object.cc +++ b/repos/base-hw/src/core/kernel/object.cc @@ -82,7 +82,7 @@ void Object_identity_reference::invalidate() { Object_identity_reference::Object_identity_reference(Object_identity *oi, Pd &pd) -: _capid(pd.capid_alloc().alloc()), _identity(oi), _pd(pd) +: _capid(pd.capid_alloc().alloc()), _identity(oi), _pd(pd), _in_utcbs(0) { if (_identity) _identity->insert(this); _pd.cap_tree().insert(this); diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index fa328e5a55..5bb5e303ca 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -585,10 +585,21 @@ void Thread::_call_delete_obj() } +void Thread::_call_ack_cap() +{ + Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1()); + if (oir) oir->remove_from_utcb(); +} + + void Thread::_call_delete_cap() { Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1()); - if (oir) destroy(pd()->platform_pd()->capability_slab(), oir); + if (!oir) return; + + if (oir->in_utcb()) return; + + destroy(pd()->platform_pd()->capability_slab(), oir); } @@ -612,6 +623,7 @@ void Thread::_call() case call_id_await_signal(): _call_await_signal(); return; case call_id_ack_signal(): _call_ack_signal(); return; case call_id_print_char(): _call_print_char(); return; + case call_id_ack_cap(): _call_ack_cap(); return; case call_id_delete_cap(): _call_delete_cap(); return; default: /* check wether this is a core thread */