2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Implementation of the IPC API for NOVA
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2009-10-02
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2009-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/ipc.h>
|
|
|
|
#include <base/thread.h>
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/log.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
/* base-internal includes */
|
2016-03-18 22:53:25 +01:00
|
|
|
#include <base/internal/ipc.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-06-15 15:04:54 +02:00
|
|
|
/* NOVA includes */
|
|
|
|
#include <nova/cap_map.h>
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
2016-03-15 20:01:59 +01:00
|
|
|
** IPC client **
|
2011-12-22 16:19:25 +01:00
|
|
|
****************/
|
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
|
|
|
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
|
|
|
|
size_t rcv_caps)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2016-03-18 22:53:25 +01:00
|
|
|
Receive_window rcv_window;
|
|
|
|
rcv_msg.reset();
|
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
/* update receive window for capability selectors if needed */
|
|
|
|
if (rcv_caps != ~0UL) {
|
|
|
|
|
|
|
|
/* calculate max order of caps to be received during reply */
|
2018-10-25 11:42:11 +02:00
|
|
|
unsigned short log2_max = 0;
|
|
|
|
if (rcv_caps) {
|
|
|
|
log2_max = log2(rcv_caps);
|
|
|
|
|
|
|
|
/* if this happens, the call is bogus and invalid */
|
|
|
|
if ((log2_max >= sizeof(rcv_caps) * 8))
|
|
|
|
throw Ipc_error();
|
|
|
|
|
|
|
|
if ((1UL << log2_max) < rcv_caps)
|
|
|
|
log2_max ++;
|
|
|
|
}
|
2016-03-15 20:01:59 +01:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
rcv_window.rcv_wnd(log2_max);
|
2016-03-15 20:01:59 +01:00
|
|
|
}
|
|
|
|
|
2016-06-15 15:04:54 +02:00
|
|
|
Thread * const myself = Thread::myself();
|
|
|
|
Nova::Utcb &utcb = *(Nova::Utcb *)myself->utcb();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
/* the protocol value is unused as the badge is delivered by the kernel */
|
|
|
|
if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
error("could not setup IPC");
|
2016-03-15 20:01:59 +01:00
|
|
|
throw Ipc_error();
|
2012-07-05 11:14:02 +02:00
|
|
|
}
|
2013-01-17 17:09:09 +01:00
|
|
|
|
2016-06-15 15:04:54 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2013-01-17 17:09:09 +01:00
|
|
|
/* if we can't setup receive window, die in order to recognize the issue */
|
2016-06-15 15:04:54 +02:00
|
|
|
if (!rcv_window.prepare_rcv_window(utcb, manual_rcv_sel))
|
2013-01-17 17:09:09 +01:00
|
|
|
/* printf doesn't work here since for IPC also rcv_prepare* is used */
|
|
|
|
nova_die();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* establish the mapping via a portal traversal */
|
2016-03-15 20:01:59 +01:00
|
|
|
uint8_t res = Nova::call(dst.local_name());
|
2016-06-03 14:38:59 +02:00
|
|
|
|
|
|
|
if (res != Nova::NOVA_OK)
|
2012-06-25 14:56:46 +02:00
|
|
|
/* If an error occurred, reset word&item count (not done by kernel). */
|
2016-03-18 22:53:25 +01:00
|
|
|
utcb.set_msg_word(0);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-06-03 14:38:59 +02:00
|
|
|
/* track potentially received caps and invalidate unused caps slots */
|
2016-06-15 15:04:54 +02:00
|
|
|
rcv_window.post_ipc(utcb, manual_rcv_sel);
|
2016-03-15 20:01:59 +01:00
|
|
|
|
2016-06-03 14:38:59 +02:00
|
|
|
if (res != Nova::NOVA_OK)
|
|
|
|
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
|
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
/* handle malformed reply from a server */
|
2016-03-18 22:53:25 +01:00
|
|
|
if (utcb.msg_words() < 1)
|
2016-03-15 20:01:59 +01:00
|
|
|
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_window, rcv_msg));
|
2013-09-06 11:03:12 +02:00
|
|
|
}
|
2016-06-15 15:04:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** 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)
|
base/core: use references instead of pointers
This patch replaces the former prominent use of pointers by references
wherever feasible. This has the following benefits:
* The contract between caller and callee becomes more obvious. When
passing a reference, the contract says that the argument cannot be
a null pointer. The caller is responsible to ensure that. Therefore,
the use of reference eliminates the need to add defensive null-pointer
checks at the callee site, which sometimes merely exist to be on the
safe side. The bottom line is that the code becomes easier to follow.
* Reference members must be initialized via an object initializer,
which promotes a programming style that avoids intermediate object-
construction states. Within core, there are still a few pointers
as member variables left though. E.g., caused by the late association
of 'Platform_thread' objects with their 'Platform_pd' objects.
* If no pointers are present as member variables, we don't need to
manually provide declarations of a private copy constructor and
an assignment operator to avoid -Weffc++ errors "class ... has
pointer data members [-Werror=effc++]".
This patch also changes a few system bindings on NOVA and Fiasco.OC,
e.g., the return value of the global 'cap_map' accessor has become a
reference. Hence, the patch touches a few places outside of core.
Fixes #3135
2019-01-24 22:00:01 +01:00
|
|
|
cap_map().remove(_rcv_pt_base + i, 0, false);
|
2016-06-15 15:04:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
base/core: use references instead of pointers
This patch replaces the former prominent use of pointers by references
wherever feasible. This has the following benefits:
* The contract between caller and callee becomes more obvious. When
passing a reference, the contract says that the argument cannot be
a null pointer. The caller is responsible to ensure that. Therefore,
the use of reference eliminates the need to add defensive null-pointer
checks at the callee site, which sometimes merely exist to be on the
safe side. The bottom line is that the code becomes easier to follow.
* Reference members must be initialized via an object initializer,
which promotes a programming style that avoids intermediate object-
construction states. Within core, there are still a few pointers
as member variables left though. E.g., caused by the late association
of 'Platform_thread' objects with their 'Platform_pd' objects.
* If no pointers are present as member variables, we don't need to
manually provide declarations of a private copy constructor and
an assignment operator to avoid -Weffc++ errors "class ... has
pointer data members [-Werror=effc++]".
This patch also changes a few system bindings on NOVA and Fiasco.OC,
e.g., the return value of the global 'cap_map' accessor has become a
reference. Hence, the patch touches a few places outside of core.
Fixes #3135
2019-01-24 22:00:01 +01:00
|
|
|
cap_map().remove(_rcv_pt_base + i, 0, _rcv_pt_cap_free[i] != FREE_SEL);
|
2016-06-15 15:04:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
base/core: use references instead of pointers
This patch replaces the former prominent use of pointers by references
wherever feasible. This has the following benefits:
* The contract between caller and callee becomes more obvious. When
passing a reference, the contract says that the argument cannot be
a null pointer. The caller is responsible to ensure that. Therefore,
the use of reference eliminates the need to add defensive null-pointer
checks at the callee site, which sometimes merely exist to be on the
safe side. The bottom line is that the code becomes easier to follow.
* Reference members must be initialized via an object initializer,
which promotes a programming style that avoids intermediate object-
construction states. Within core, there are still a few pointers
as member variables left though. E.g., caused by the late association
of 'Platform_thread' objects with their 'Platform_pd' objects.
* If no pointers are present as member variables, we don't need to
manually provide declarations of a private copy constructor and
an assignment operator to avoid -Weffc++ errors "class ... has
pointer data members [-Werror=effc++]".
This patch also changes a few system bindings on NOVA and Fiasco.OC,
e.g., the return value of the global 'cap_map' accessor has become a
reference. Hence, the patch touches a few places outside of core.
Fixes #3135
2019-01-24 22:00:01 +01:00
|
|
|
_rcv_pt_base = cap_map().insert(_rcv_wnd_log2);
|
2016-06-15 15:04:54 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|