mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-16 14:18:27 +00:00
Unification of native_capability.h
This patch establishes the sole use of generic headers across all kernels. The common 'native_capability.h' is based on the version of base-sel4. All traditional L4 kernels and Linux use the same implementation of the capability-lifetime management. On base-hw, NOVA, Fiasco.OC, and seL4, custom implementations (based on their original mechanisms) are used, with the potential to unify them further in the future. This change achieves binary compatibility of dynamically linked programs across all kernels. Furthermore, the patch introduces a Native_capability::print method, which allows the easy output of the kernel-specific capability representation using the base/log.h API. Issue #1993
This commit is contained in:
@ -11,12 +11,12 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/cap_map.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
|
||||
/* base-nova specific include */
|
||||
/* NOVA includes */
|
||||
#include <nova/syscalls.h>
|
||||
#include <nova/cap_map.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
78
repos/base-nova/src/lib/base/capability.cc
Normal file
78
repos/base-nova/src/lib/base/capability.cc
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* \brief Capability lifetime management
|
||||
* \author Norman Feske
|
||||
* \date 2015-05-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/capability_data.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/cap_map.h>
|
||||
#include <nova/capability_space.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
Native_capability::Native_capability()
|
||||
{
|
||||
*this = Capability_space::import(Capability_space::INVALID_INDEX);
|
||||
}
|
||||
|
||||
|
||||
void Native_capability::_inc()
|
||||
{
|
||||
Cap_index idx(cap_map()->find(local_name()));
|
||||
idx.inc();
|
||||
}
|
||||
|
||||
|
||||
void Native_capability::_dec()
|
||||
{
|
||||
Cap_index idx(cap_map()->find(local_name()));
|
||||
idx.dec();
|
||||
}
|
||||
|
||||
|
||||
long Native_capability::local_name() const
|
||||
{
|
||||
if (valid())
|
||||
return Capability_space::crd(*this).base();
|
||||
else
|
||||
return Capability_space::INVALID_INDEX;
|
||||
}
|
||||
|
||||
|
||||
bool Native_capability::valid() const
|
||||
{
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
|
||||
Native_capability::Raw Native_capability::raw() const
|
||||
{
|
||||
return { 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
|
||||
void Native_capability::print(Genode::Output &out) const
|
||||
{
|
||||
using Genode::print;
|
||||
|
||||
print(out, "cap<");
|
||||
if (_data) {
|
||||
print(out, local_name());
|
||||
} else {
|
||||
print(out, "invalid");
|
||||
}
|
||||
print(out, ">");
|
||||
}
|
@ -19,6 +19,9 @@
|
||||
/* base-internal includes */
|
||||
#include <base/internal/ipc.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/cap_map.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
@ -43,7 +46,8 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
||||
rcv_window.rcv_wnd(log2_max);
|
||||
}
|
||||
|
||||
Nova::Utcb &utcb = *(Nova::Utcb *)Thread::myself()->utcb();
|
||||
Thread * const myself = Thread::myself();
|
||||
Nova::Utcb &utcb = *(Nova::Utcb *)myself->utcb();
|
||||
|
||||
/* the protocol value is unused as the badge is delivered by the kernel */
|
||||
if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) {
|
||||
@ -51,8 +55,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
||||
throw Ipc_error();
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine manually defined selector for receiving the call result.
|
||||
* See the comment in 'base-nova/include/nova/native_thread.h'.
|
||||
*/
|
||||
addr_t const manual_rcv_sel = myself ? myself->native_thread().client_rcv_sel
|
||||
: Receive_window::INVALID_INDEX;
|
||||
|
||||
/* if we can't setup receive window, die in order to recognize the issue */
|
||||
if (!rcv_window.prepare_rcv_window(utcb, dst.rcv_window()))
|
||||
if (!rcv_window.prepare_rcv_window(utcb, manual_rcv_sel))
|
||||
/* printf doesn't work here since for IPC also rcv_prepare* is used */
|
||||
nova_die();
|
||||
|
||||
@ -64,7 +75,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
||||
utcb.set_msg_word(0);
|
||||
|
||||
/* track potentially received caps and invalidate unused caps slots */
|
||||
rcv_window.post_ipc(utcb, dst.rcv_window());
|
||||
rcv_window.post_ipc(utcb, manual_rcv_sel);
|
||||
|
||||
if (res != Nova::NOVA_OK)
|
||||
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
|
||||
@ -75,3 +86,112 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
||||
|
||||
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_window, rcv_msg));
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Receive_window **
|
||||
********************/
|
||||
|
||||
void Receive_window::rcv_pt_sel(Native_capability &cap)
|
||||
{
|
||||
if (_rcv_pt_sel_cnt >= _rcv_pt_sel_max) {
|
||||
cap = Native_capability();
|
||||
return;
|
||||
}
|
||||
|
||||
/* return only received or translated caps */
|
||||
cap = Capability_space::import(_rcv_pt_sel[_rcv_pt_sel_cnt++].sel);
|
||||
}
|
||||
|
||||
|
||||
bool Receive_window::rcv_invalid() const
|
||||
{
|
||||
return _rcv_pt_base == Capability_space::INVALID_INDEX;
|
||||
}
|
||||
|
||||
|
||||
bool Receive_window::rcv_cleanup(bool keep, unsigned short const new_max)
|
||||
{
|
||||
/* mark used mapped capabilities as used to prevent freeing */
|
||||
bool reinit = false;
|
||||
for (unsigned i = 0; i < _rcv_pt_sel_cnt; i++) {
|
||||
if (!_rcv_pt_sel[i].del)
|
||||
continue;
|
||||
|
||||
/* should never happen */
|
||||
if (_rcv_pt_sel[i].sel < _rcv_pt_base ||
|
||||
(_rcv_pt_sel[i].sel >= _rcv_pt_base + MAX_CAP_ARGS))
|
||||
nova_die();
|
||||
|
||||
_rcv_pt_cap_free [_rcv_pt_sel[i].sel - _rcv_pt_base] = USED_CAP;
|
||||
|
||||
reinit = true;
|
||||
}
|
||||
|
||||
/* if old receive window was smaller, we need to re-init */
|
||||
for (unsigned i = 0; !reinit && i < new_max; i++)
|
||||
if (_rcv_pt_cap_free[i] == FREE_INVALID)
|
||||
reinit = true;
|
||||
|
||||
_rcv_pt_sel_cnt = 0;
|
||||
_rcv_pt_sel_max = 0;
|
||||
|
||||
/* we can keep the cap selectors if none was used */
|
||||
if (keep && !reinit) {
|
||||
for (unsigned i = 0; i < MAX_CAP_ARGS; i++) {
|
||||
/* revoke received caps which are unused */
|
||||
if (_rcv_pt_cap_free[i] == UNUSED_CAP)
|
||||
Nova::revoke(Nova::Obj_crd(_rcv_pt_base + i, 0), true);
|
||||
|
||||
/* free rest of indexes if new_max is smaller then last window */
|
||||
if (i >= new_max && _rcv_pt_cap_free[i] == FREE_SEL)
|
||||
cap_map()->remove(_rcv_pt_base + i, 0, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* decrease ref count if valid selector */
|
||||
for (unsigned i = 0; i < MAX_CAP_ARGS; i++) {
|
||||
if (_rcv_pt_cap_free[i] == FREE_INVALID)
|
||||
continue;
|
||||
cap_map()->remove(_rcv_pt_base + i, 0, _rcv_pt_cap_free[i] != FREE_SEL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Receive_window::prepare_rcv_window(Nova::Utcb &utcb, addr_t rcv_window)
|
||||
{
|
||||
/* open maximal translate window */
|
||||
utcb.crd_xlt = Nova::Obj_crd(0, ~0UL);
|
||||
|
||||
/* use receive window if specified */
|
||||
if (rcv_window != INVALID_INDEX) {
|
||||
/* cleanup if receive window already used */
|
||||
if (!rcv_invalid()) rcv_cleanup(false);
|
||||
|
||||
_rcv_pt_base = rcv_window;
|
||||
|
||||
/* open receive window */
|
||||
utcb.crd_rcv = Nova::Obj_crd(_rcv_pt_base, _rcv_wnd_log2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* allocate receive window if necessary, otherwise use old one */
|
||||
if (rcv_invalid() || rcv_cleanup(true, 1U << _rcv_wnd_log2))
|
||||
{
|
||||
_rcv_pt_base = cap_map()->insert(_rcv_wnd_log2);
|
||||
|
||||
if (_rcv_pt_base == INVALID_INDEX) {
|
||||
/* no mappings can be received */
|
||||
utcb.crd_rcv = Nova::Obj_crd();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* open receive window */
|
||||
utcb.crd_rcv = Nova::Obj_crd(_rcv_pt_base, _rcv_wnd_log2);
|
||||
return true;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <base/internal/ipc.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/syscalls.h>
|
||||
#include <nova/util.h>
|
||||
#include <nova/native_thread.h>
|
||||
|
||||
@ -42,7 +41,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
|
||||
|
||||
/* _ec_sel is invalid until thread gets started */
|
||||
if (native_thread().ec_sel != Native_thread::INVALID_INDEX)
|
||||
ec_cap = Native_capability(native_thread().ec_sel);
|
||||
ec_cap = Capability_space::import(native_thread().ec_sel);
|
||||
else
|
||||
ec_cap = _thread_cap;
|
||||
|
||||
@ -127,7 +126,7 @@ void Rpc_entrypoint::_activation_entry()
|
||||
Rpc_entrypoint &ep = *static_cast<Rpc_entrypoint *>(Thread::myself());
|
||||
Nova::Utcb &utcb = *(Nova::Utcb *)Thread::myself()->utcb();
|
||||
|
||||
Receive_window &rcv_window = ep.native_thread().rcv_window;
|
||||
Receive_window &rcv_window = ep.native_thread().server_rcv_window;
|
||||
rcv_window.post_ipc(utcb);
|
||||
|
||||
/* handle ill-formed message */
|
||||
@ -146,7 +145,7 @@ void Rpc_entrypoint::_activation_entry()
|
||||
Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
|
||||
|
||||
/* in case of a portal cleanup call we are done here - just reply */
|
||||
if (ep._cap.local_name() == id_pt) {
|
||||
if (ep._cap.local_name() == (long)id_pt) {
|
||||
if (!rcv_window.prepare_rcv_window(utcb))
|
||||
PWRN("out of capability selectors for handling server requests");
|
||||
|
||||
@ -224,12 +223,13 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
|
||||
Thread::start();
|
||||
|
||||
/* create cleanup portal */
|
||||
_cap = _alloc_rpc_cap(_pd_session, Native_capability(native_thread().ec_sel),
|
||||
_cap = _alloc_rpc_cap(_pd_session,
|
||||
Capability_space::import(native_thread().ec_sel),
|
||||
(addr_t)_activation_entry);
|
||||
if (!_cap.valid())
|
||||
throw Cpu_session::Thread_creation_failed();
|
||||
|
||||
Receive_window &rcv_window = Thread::native_thread().rcv_window;
|
||||
Receive_window &rcv_window = Thread::native_thread().server_rcv_window;
|
||||
|
||||
/* prepare portal receive window of new thread */
|
||||
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb()))
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <base/signal.h>
|
||||
#include <base/trace/events.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include <base/internal/stack_area.h>
|
||||
#include <base/internal/native_utcb.h>
|
||||
|
||||
/* base-nova includes */
|
||||
#include <base/cap_map.h>
|
||||
/* NOVA includes */
|
||||
#include <nova/cap_map.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
/* NOVA includes */
|
||||
#include <nova/syscalls.h>
|
||||
#include <nova/util.h>
|
||||
#include <nova/cap_map.h>
|
||||
#include <nova/capability_space.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
@ -80,7 +82,8 @@ void Thread::_init_platform_thread(size_t weight, Type type)
|
||||
if (type == MAIN || type == REINITIALIZED_MAIN) {
|
||||
_thread_cap = env()->parent()->main_thread_cap();
|
||||
|
||||
Genode::Native_capability pager_cap(Nova::PT_SEL_MAIN_PAGER);
|
||||
Genode::Native_capability pager_cap =
|
||||
Capability_space::import(Nova::PT_SEL_MAIN_PAGER);
|
||||
|
||||
native_thread().exc_pt_sel = 0;
|
||||
native_thread().ec_sel = Nova::PT_SEL_MAIN_EC;
|
||||
|
Reference in New Issue
Block a user