Unify ipc_msgbuf.h across base platforms

Besides unifying the Msgbuf_base classes across all platforms, this
patch merges the Ipc_marshaller functionality into Msgbuf_base, which
leads to several further simplifications. For example, this patch
eventually moves the Native_connection_state and removes all state
from the former Ipc_server to the actual server loop, which not only
makes the flow of control and information much more obvious, but is
also more flexible. I.e., on NOVA, we don't even have the notion of
reply-and-wait. Now, we are no longer forced to pretend otherwise.

Issue #1832
This commit is contained in:
Norman Feske 2016-03-18 22:53:25 +01:00 committed by Christian Helmuth
parent 0c299c5e08
commit f186587cab
74 changed files with 2058 additions and 2952 deletions

View File

@ -1,88 +0,0 @@
/*
* \brief Fiasco-specific layout of IPC message buffer
* \author Norman Feske
* \date 2006-06-14
*/
/*
* Copyright (C) 2006-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/stdint.h>
namespace Genode {
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
class Msgbuf_base
{
private:
size_t const _capacity;
protected:
size_t _data_size = 0;
friend class Ipc_marshaller;
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
struct Headroom { long space[4]; } _headroom;
char buf[];
public:
template <typename T>
T &header()
{
static_assert(sizeof(T) <= sizeof(Headroom),
"Header size exceeds message headroom");
return *reinterpret_cast<T *>(buf - sizeof(T));
}
unsigned long &word(unsigned i)
{
return reinterpret_cast<unsigned long *>(buf)[i];
}
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
void *data() { return buf; };
void const *data() const { return buf; };
size_t data_size() const { return _data_size; }
};
/**
* Instance of IPC message buffer with specified buffer size
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -7,7 +7,7 @@
LIBS += cxx startup
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc
SRC_CC += ipc/ipc.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
SRC_CC += allocator/allocator_avl.cc

View File

@ -26,6 +26,8 @@ namespace Fiasco {
#include <l4/sys/kdebug.h>
}
using namespace Genode;
class Msg_header
{
@ -36,54 +38,90 @@ class Msg_header
Fiasco::l4_msgdope_t size_dope;
Fiasco::l4_msgdope_t send_dope;
public:
/*
* First data word of message, used to transfer the local name of the
* invoked object (when a client calls a server) or the exception code
* (when the server replies). This data word is never fetched from
* memory but transferred via the first short-IPC register. The
* 'protocol_word' is needed as a spacer between the header fields
* define above and the regular message payload..
* First two data words of message, used to transfer the local name of
* the invoked object (when a client calls a server) or the exception
* code (when the server replies), and the number of capability
* arguments. The kernel does not fetch these data words from memory
* but transfers them via the short-IPC registers.
*/
Fiasco::l4_umword_t protocol_word;
Fiasco::l4_umword_t num_caps;
private:
enum { MAX_CAPS_PER_MSG = Msgbuf_base::MAX_CAPS_PER_MSG };
Fiasco::l4_threadid_t _cap_tid [MAX_CAPS_PER_MSG];
unsigned long _cap_local_name [MAX_CAPS_PER_MSG];
size_t _num_msg_words(size_t num_data_words) const
{
size_t const caps_size = sizeof(_cap_tid) + sizeof(_cap_local_name);
/*
* Account for the transfer of the protocol word, capability count,
* and capability arguments in front of the payload.
*/
return 2 + caps_size/sizeof(Fiasco::l4_umword_t) + num_data_words;
}
public:
void *msg_start() { return &rcv_fpage; }
/**
* Define message size for sending
* Load header fields according to send-message buffer
*/
void snd_size(Genode::size_t size)
void prepare_snd_msg(unsigned long protocol, Msgbuf_base const &snd_msg)
{
using namespace Fiasco;
/* account for the transfer of the protocol word in front of the payload */
Genode::size_t const snd_words = size/sizeof(l4_umword_t);
send_dope = L4_IPC_DOPE(snd_words + 1, 0);
protocol_word = protocol;
num_caps = min((unsigned)MAX_CAPS_PER_MSG, snd_msg.used_caps());
size_t const snd_words = snd_msg.data_size()/sizeof(l4_umword_t);
send_dope = L4_IPC_DOPE(_num_msg_words(snd_words), 0);
/* reset _cap_tid and _cap_local_name */
for (unsigned i = 0; i < MAX_CAPS_PER_MSG; i++) {
_cap_tid[i] = L4_INVALID_ID;
_cap_local_name[i] = 0;
}
for (unsigned i = 0; i < num_caps; i++) {
Native_capability const &cap = snd_msg.cap(i);
_cap_tid[i] = cap.dst();
_cap_local_name[i] = cap.local_name();
}
}
/**
* Define size of receive buffer
* Prepare header for receiving a message
*/
void rcv_capacity(Genode::size_t capacity)
void prepare_rcv_msg(Msgbuf_base const &rcv_msg)
{
using namespace Fiasco;
size_dope = L4_IPC_DOPE(capacity/sizeof(l4_umword_t), 0);
size_t const rcv_max_words = rcv_msg.capacity()/sizeof(l4_umword_t);
size_dope = L4_IPC_DOPE(_num_msg_words(rcv_max_words), 0);
}
void *msg_type(Genode::size_t size)
/**
* Copy received capability arguments into receive message buffer
*/
void extract_caps(Msgbuf_base &rcv_msg) const
{
using namespace Fiasco;
return size <= sizeof(l4_umword_t) ? L4_IPC_SHORT_MSG : msg_start();
for (unsigned i = 0; i < min((unsigned)MAX_CAPS_PER_MSG, num_caps); i++)
rcv_msg.insert(Native_capability(_cap_tid[i],
_cap_local_name[i]));
}
};
using namespace Genode;
/****************
** IPC client **
****************/
@ -95,156 +133,128 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
using namespace Fiasco;
Msg_header &snd_header = snd_msg.header<Msg_header>();
snd_header.snd_size(snd_msg.data_size());
snd_header.prepare_snd_msg(dst.local_name(), snd_msg);
Msg_header &rcv_header = rcv_msg.header<Msg_header>();
rcv_header.rcv_capacity(rcv_msg.capacity());
rcv_header.prepare_rcv_msg(rcv_msg);
l4_msgdope_t ipc_result;
l4_umword_t exception_code = 0;
l4_ipc_call(dst.dst(),
snd_header.msg_type(snd_msg.data_size()),
dst.local_name(),
snd_msg.word(0),
snd_header.msg_start(),
snd_header.protocol_word,
snd_header.num_caps,
rcv_header.msg_start(),
&exception_code,
&rcv_msg.word(0),
&rcv_header.protocol_word,
&rcv_header.num_caps,
L4_IPC_NEVER, &ipc_result);
rcv_header.extract_caps(rcv_msg);
if (L4_IPC_IS_ERROR(ipc_result)) {
if (L4_IPC_ERROR(ipc_result) == L4_IPC_RECANCELED)
throw Genode::Blocking_canceled();
PERR("Ipc error %lx", L4_IPC_ERROR(ipc_result));
PERR("ipc_call error %lx", L4_IPC_ERROR(ipc_result));
throw Genode::Ipc_error();
}
return Rpc_exception_code(exception_code);
return Rpc_exception_code(rcv_header.protocol_word);
}
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
_reply_needed = true;
_read_offset = _write_offset = 0;
}
static umword_t wait(Native_connection_state &rcv_cs, Msgbuf_base &rcv_msg)
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
using namespace Fiasco;
l4_msgdope_t result;
umword_t badge = 0;
/*
* Wait until we get a proper message and thereby
* ignore receive message cuts on the server-side.
* This error condition should be handled by the
* client. The server does not bother.
*/
do {
Msg_header &rcv_header = rcv_msg.header<Msg_header>();
rcv_header.rcv_capacity(rcv_msg.capacity());
l4_ipc_wait(&rcv_cs.caller, rcv_header.msg_start(),
&badge,
&rcv_msg.word(0),
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
return badge;
}
void Ipc_server::reply()
{
using namespace Fiasco;
Msg_header &snd_header = _snd_msg.header<Msg_header>();
snd_header.snd_size(_snd_msg.data_size());
Msg_header &snd_header = snd_msg.header<Msg_header>();
snd_header.prepare_snd_msg(exc.value, snd_msg);
l4_msgdope_t result;
l4_ipc_send(_caller.dst(), snd_header.msg_start(),
_exception_code.value,
_snd_msg.word(0),
l4_ipc_send(caller.dst(), snd_header.msg_start(),
snd_header.protocol_word,
snd_header.num_caps,
L4_IPC_SEND_TIMEOUT_0, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx, ignored", L4_IPC_ERROR(result));
_prepare_next_reply_wait();
PERR("ipc_send error %lx, ignored", L4_IPC_ERROR(result));
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
using namespace Fiasco;
if (_reply_needed) {
l4_msgdope_t ipc_result;
l4_msgdope_t ipc_result;
bool need_to_wait = true;
Msg_header &snd_header = _snd_msg.header<Msg_header>();
snd_header.snd_size(_snd_msg.data_size());
Msg_header &snd_header = reply_msg.header<Msg_header>();
snd_header.prepare_snd_msg(exc.value, reply_msg);
Msg_header &rcv_header = _rcv_msg.header<Msg_header>();
rcv_header.rcv_capacity(_rcv_msg.capacity());
request_msg.reset();
Msg_header &rcv_header = request_msg.header<Msg_header>();
rcv_header.prepare_rcv_msg(request_msg);
l4_threadid_t caller = L4_INVALID_ID;
if (last_caller.valid()) {
/*
* Use short IPC for reply if possible. This is the common case of
* returning an integer as RPC result.
*/
l4_ipc_reply_and_wait(
_caller.dst(),
snd_header.msg_type(_snd_msg.data_size()),
_exception_code.value,
_snd_msg.word(0),
&_rcv_cs.caller, rcv_header.msg_start(),
&_badge,
&_rcv_msg.word(0),
L4_IPC_SEND_TIMEOUT_0, &ipc_result);
l4_ipc_reply_and_wait(last_caller.dst(), snd_header.msg_start(),
snd_header.protocol_word,
snd_header.num_caps,
&caller, rcv_header.msg_start(),
&rcv_header.protocol_word,
&rcv_header.num_caps,
L4_IPC_SEND_TIMEOUT_0, &ipc_result);
/*
* The error condition could be a message cut (which we want to ignore
* on the server side) or a reply failure (for example, if the caller
* went dead during the call. In both cases, we do not reflect the
* error condition to the user but want to wait for the next proper
* incoming message.
*/
if (L4_IPC_IS_ERROR(ipc_result)) {
PERR("Ipc error %lx", L4_IPC_ERROR(ipc_result));
/*
* The error conditions could be a message cut (which
* we want to ignore on the server side) or a reply failure
* (for example, if the caller went dead during the call.
* In both cases, we do not reflect the error condition to
* the user but want to wait for the next proper incoming
* message. So let's just wait now.
*/
_badge = wait(_rcv_cs, _rcv_msg);
PERR("ipc_reply_and_wait error %lx", L4_IPC_ERROR(ipc_result));
} else {
need_to_wait = false;
}
} else {
_badge = wait(_rcv_cs, _rcv_msg);
}
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, 0);
while (need_to_wait) {
_prepare_next_reply_wait();
l4_ipc_wait(&caller, rcv_header.msg_start(),
&rcv_header.protocol_word,
&rcv_header.num_caps,
L4_IPC_NEVER, &ipc_result);
if (L4_IPC_IS_ERROR(ipc_result)) {
PERR("ipc_wait error %lx", L4_IPC_ERROR(ipc_result));
} else {
need_to_wait = false;
}
};
rcv_header.extract_caps(request_msg);
return Rpc_request(Native_capability(caller, 0), rcv_header.protocol_word);
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Fiasco::l4_myself(), 0),
_rcv_cs(cs)
{ }
Ipc_server::Ipc_server() : Native_capability(Fiasco::l4_myself(), 0) { }
Ipc_server::~Ipc_server() { }

View File

@ -0,0 +1,50 @@
/*
* \brief Kernel-specific RM-faulter wake-up mechanism
* \author Norman Feske
* \date 2016-04-12
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <pager.h>
/* Fiasco includes */
namespace Fiasco {
#include <l4/sys/ipc.h>
#include <l4/sys/syscalls.h>
#include <l4/sys/kdebug.h>
}
using namespace Genode;
void Pager_object::wake_up()
{
using namespace Fiasco;
/* kernel-defined message header */
struct {
l4_fpage_t rcv_fpage; /* unused */
l4_msgdope_t size_dope = L4_IPC_DOPE(0, 0);
l4_msgdope_t send_dope = L4_IPC_DOPE(0, 0);
} rcv_header;
l4_msgdope_t ipc_result;
l4_umword_t dummy = 0;
l4_ipc_call(cap().dst(), L4_IPC_SHORT_MSG,
0, /* fault address */
(l4_umword_t)this, /* instruction pointer */
&rcv_header, &dummy, &dummy, L4_IPC_NEVER, &ipc_result);
}
void Pager_object::unresolved_page_fault_occurred()
{
state.unresolved_page_fault = true;
}

View File

@ -64,7 +64,6 @@ vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core

View File

@ -1,34 +0,0 @@
/*
* \brief Connection state
* \author Norman Feske
* \date 2016-03-03
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
/* Genode includes */
#include <base/stdint.h>
/* Fiasco includes */
namespace Fiasco {
#include <l4/sys/types.h>
}
namespace Genode { struct Native_connection_state; }
struct Genode::Native_connection_state
{
Fiasco::l4_threadid_t caller;
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */

View File

@ -1,178 +0,0 @@
/*
* \brief IPC message buffer layout for Fiasco.OC
* \author Stefan Kalkowski
* \date 2010-11-30
*
* On Fiasco.OC, IPC is used to transmit plain data and capabilities.
* Therefore the message buffer contains both categories of payload.
*/
/*
* Copyright (C) 2010-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
/* Genode includes */
#include <base/cap_map.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/types.h>
#include <l4/sys/utcb.h>
}
namespace Genode {
class Ipc_marshaller;
class Msgbuf_base
{
public:
enum { MAX_CAP_ARGS_LOG2 = 2, MAX_CAP_ARGS = 1 << MAX_CAP_ARGS_LOG2 };
protected:
friend class Ipc_marshaller;
size_t const _capacity;
size_t _data_size = 0;
/**
* Number of capability selectors to send.
*/
size_t _snd_cap_sel_cnt = 0;
/**
* Capability selectors to delegate.
*/
addr_t _snd_cap_sel[MAX_CAP_ARGS];
/**
* Base of capability receive window.
*/
Cap_index* _rcv_idx_base = nullptr;
/**
* Read counter for unmarshalling portal capability selectors
*/
addr_t _rcv_cap_sel_cnt = 0;
unsigned long _label = 0;
char _msg_start[]; /* symbol marks start of message */
/**
* Constructor
*/
Msgbuf_base(size_t capacity)
:
_capacity(capacity),
_rcv_idx_base(cap_idx_alloc()->alloc_range(MAX_CAP_ARGS))
{
rcv_reset();
snd_reset();
}
public:
~Msgbuf_base()
{
cap_idx_alloc()->free(_rcv_idx_base, MAX_CAP_ARGS);
}
/*
* Begin of actual message buffer
*/
char buf[];
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
unsigned long &word(unsigned i)
{
return reinterpret_cast<unsigned long *>(buf)[i];
}
/**
* Reset portal capability selector payload
*/
void snd_reset() { _snd_cap_sel_cnt = 0; }
/**
* Append capability selector to message buffer
*/
bool snd_append_cap_sel(addr_t cap_sel)
{
if (_snd_cap_sel_cnt >= MAX_CAP_ARGS)
return false;
_snd_cap_sel[_snd_cap_sel_cnt++] = cap_sel;
return true;
}
/**
* Return number of marshalled capability selectors
*/
size_t snd_cap_sel_cnt() const { return _snd_cap_sel_cnt; }
/**
* Return capability selector to send.
*
* \param i index (0 ... 'snd_cap_sel_cnt()' - 1)
* \return capability selector, or 0 if index is invalid
*/
addr_t snd_cap_sel(unsigned i) const {
return i < _snd_cap_sel_cnt ? _snd_cap_sel[i] : 0; }
/**
* Return address of capability receive window.
*/
addr_t rcv_cap_sel_base() { return _rcv_idx_base->kcap(); }
/**
* Reset capability receive window
*/
void rcv_reset() { _rcv_cap_sel_cnt = 0; }
/**
* Return next received capability selector.
*
* \return capability selector, or 0 if index is invalid
*/
addr_t rcv_cap_sel() {
return rcv_cap_sel_base() + _rcv_cap_sel_cnt++ * Fiasco::L4_CAP_SIZE; }
void label(unsigned long label) { _label = label; }
unsigned long label() { return _label & (~0UL << 2); }
};
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -20,6 +20,7 @@
/* Genode includes */
#include <base/stdint.h>
#include <foc/receive_window.h>
/* Fiasco.OC includes */
namespace Fiasco {
@ -32,6 +33,9 @@ struct Genode::Native_thread
{
Fiasco::l4_cap_idx_t kcap = 0;
/* receive window for capability selectors received at the server side */
Receive_window rcv_window;
Native_thread() { }
explicit Native_thread(Fiasco::l4_cap_idx_t kcap) : kcap(kcap) { }
};

View File

@ -0,0 +1,65 @@
/*
* \brief Receive window for capability selectors
* \author Norman Feske
* \date 2016-03-22
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__FOC__RECEIVE_WINDOW_H_
#define _INCLUDE__FOC__RECEIVE_WINDOW_H_
/* Genode includes */
#include <base/stdint.h>
#include <base/ipc_msgbuf.h>
#include <base/cap_map.h>
namespace Genode { struct Receive_window; }
class Genode::Receive_window
{
private:
/**
* Base of capability receive window.
*/
Cap_index* _rcv_idx_base = nullptr;
enum { MAX_CAPS_PER_MSG = Msgbuf_base::MAX_CAPS_PER_MSG };
public:
Receive_window() { }
~Receive_window()
{
if (_rcv_idx_base)
cap_idx_alloc()->free(_rcv_idx_base, MAX_CAPS_PER_MSG);
}
void init()
{
_rcv_idx_base = cap_idx_alloc()->alloc_range(MAX_CAPS_PER_MSG);
}
/**
* Return address of capability receive window
*/
addr_t rcv_cap_sel_base() { return _rcv_idx_base->kcap(); }
/**
* Return received selector with index i
*
* \return capability selector, or 0 if index is invalid
*/
addr_t rcv_cap_sel(unsigned i) {
return rcv_cap_sel_base() + i*Fiasco::L4_CAP_SIZE; }
};
#endif /* _INCLUDE__FOC__RECEIVE_WINDOW_H_ */

View File

@ -89,15 +89,23 @@ namespace Genode {
{
using namespace Fiasco;
/* block on semaphore, will be unblocked if signal is available */
l4_irq_receive(_sem.dst(), L4_IPC_NEVER);
Signal signal;
do {
/*
* Now that the server has unblocked the semaphore, we are sure
* that there is a signal pending. The following 'wait_for_signal'
* request will be immediately answered.
*/
return call<Rpc_wait_for_signal>();
/* block on semaphore until signal context was submitted */
l4_irq_receive(_sem.dst(), L4_IPC_NEVER);
/*
* The following request will return immediately and either
* return a valid or a null signal. The latter may happen in
* the case a submitted signal context was destroyed (by the
* submitter) before we have a chance to raise our request.
*/
signal = call<Rpc_wait_for_signal>();
} while (!signal.imprint());
return signal;
}
};
}

View File

@ -45,58 +45,11 @@ using namespace Genode;
using namespace Fiasco;
/*****************************
** IPC marshalling support **
*****************************/
void Ipc_marshaller::insert(Native_capability const &cap)
{
if (cap.valid()) {
if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst()))) {
insert(0UL);
return;
}
}
/* transfer capability id */
insert(cap.local_name());
/* only transfer kernel-capability if it's a valid one */
if (cap.valid())
_snd_msg.snd_append_cap_sel(cap.dst());
ASSERT(!cap.valid() ||
l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())),
"Send invalid cap");
}
void Ipc_unmarshaller::extract(Native_capability &cap)
{
long value = 0;
/* extract capability id from message buffer */
extract(value);
/* if id is zero an invalid capability was transfered */
if (!value) {
cap = Native_capability();
return;
}
/* try to insert received capability in the map and return it */
cap = Native_capability(cap_map()->insert_map(value, _rcv_msg.rcv_cap_sel()));
}
/***************
** Utilities **
***************/
enum Debug {
DEBUG_MSG = 1,
HALT_ON_ERROR = 0
};
enum Debug { DEBUG_MSG = 1, HALT_ON_ERROR = 0 };
static inline bool ipc_error(l4_msgtag_t tag, bool print)
@ -116,39 +69,110 @@ static inline bool ipc_error(l4_msgtag_t tag, bool print)
}
enum { INVALID_BADGE = ~0UL };
/**
* Representation of a capability during UTCB marshalling/unmarshalling
*/
struct Cap_info
{
bool valid = false;
unsigned long sel = 0;
unsigned long badge = 0;
};
/**
* Copy message registers from UTCB to destination message buffer
*
* \return protocol word (local name or exception code)
*/
static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, Msgbuf_base &rcv_msg)
static unsigned long extract_msg_from_utcb(l4_msgtag_t tag,
Receive_window &rcv_window,
Msgbuf_base &rcv_msg)
{
unsigned const num_msg_words = l4_msgtag_words(tag);
unsigned const num_cap_sel = l4_msgtag_items(tag);
unsigned num_msg_words = l4_msgtag_words(tag);
/* each message has at least the protocol word */
if (num_msg_words < 2 && num_cap_sel == 0)
l4_mword_t const *msg_words = (l4_mword_t const *)l4_utcb_mr();
/* each message has at least the protocol word and the capability count */
if (num_msg_words < 2)
return 0;
/* the first message word is reserved for the protocol word */
unsigned num_data_msg_words = num_msg_words - 1;
/* read badge / exception code from first message word */
unsigned long const protocol_word = *msg_words++;
if ((num_data_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) {
if (DEBUG_MSG)
outstring("receive message buffer too small");
num_data_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t);
/* read number of capability arguments from second message word */
unsigned long const num_caps = min(*msg_words, Msgbuf_base::MAX_CAPS_PER_MSG);
msg_words++;
num_msg_words -= 2;
if (num_caps > 0 && num_msg_words < num_caps) {
outstring("unexpected end of message, capability info missing\n");
return 0;
}
/* read protocol word from first UTCB message register */
unsigned long const protocol_word = l4_utcb_mr()->mr[0];
/*
* Extract capabilities
*
* The badges are stored in the subsequent message registers. For each
* valid badge, we expect one capability selector to be present in the
* receive window. The content of the receive window is tracked via
* 'sel_idx'. If we encounter an invalid badge, the sender specified
* an invalid capabilty as argument.
*/
unsigned const num_cap_sel = l4_msgtag_items(tag);
Cap_info caps[num_caps];
for (unsigned i = 0, sel_idx = 0; i < num_caps; i++) {
unsigned long const badge = *msg_words++;
if (badge == INVALID_BADGE)
continue;
/* received a delegated capability */
if (sel_idx == num_cap_sel) {
outstring("missing capability selector in message\n");
break;
}
caps[i].badge = badge;
caps[i].valid = true;
caps[i].sel = rcv_window.rcv_cap_sel(sel_idx++);
}
num_msg_words -= num_caps;
/* the remainder of the message contains the regular data payload */
if ((num_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) {
if (DEBUG_MSG)
outstring("receive message buffer too small\n");
num_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t);
}
/* read message payload beginning from the second UTCB message register */
l4_mword_t *src = (l4_mword_t *)l4_utcb_mr() + 1;
l4_mword_t *dst = (l4_mword_t *)rcv_msg.data();
for (unsigned i = 0; i < num_data_msg_words; i++)
*dst++ = *src++;
for (unsigned i = 0; i < num_msg_words; i++)
*dst++ = *msg_words++;
rcv_msg.rcv_reset();
rcv_msg.data_size(sizeof(l4_mword_t)*num_msg_words);
/*
* Insert received capability selectors into cap map.
*
* Note that this operation pollutes the UTCB. Therefore we must perform
* it not before the entire message content is extracted.
*/
for (unsigned i = 0; i < num_caps; i++) {
if (caps[i].valid) {
rcv_msg.insert(Native_capability(cap_map()->insert_map(caps[i].badge,
caps[i].sel)));
} else {
rcv_msg.insert(Native_capability());
}
}
return protocol_word;
}
@ -164,31 +188,76 @@ static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, Msgbuf_base &rcv_msg
static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg,
unsigned long protocol_word)
{
unsigned const num_data_words = snd_msg.data_size() / sizeof(l4_mword_t);
unsigned const num_msg_words = num_data_words + 1;
unsigned const num_cap_sel = snd_msg.snd_cap_sel_cnt();
/* account for message words, local name, and capability arguments */
if (num_msg_words + 2*num_cap_sel > L4_UTCB_GENERIC_DATA_SIZE) {
if (DEBUG_MSG)
outstring("receive message buffer too small");
unsigned const num_data_words = snd_msg.data_size() / sizeof(l4_mword_t);
unsigned const num_caps = snd_msg.used_caps();
/* validate capabilities present in the message buffer */
for (unsigned i = 0; i < num_caps; i++) {
Native_capability &cap = snd_msg.cap(i);
if (!cap.valid())
continue;
if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())))
cap = Native_capability();
}
/*
* Obtain capability info from message buffer
*
* This step must be performed prior any write operation to the UTCB
* because the 'Genode::Capability' operations may indirectly trigger
* system calls, which pollute the UTCB.
*/
Cap_info caps[num_caps];
for (unsigned i = 0; i < num_caps; i++) {
Native_capability const &cap = snd_msg.cap(i);
if (cap.valid()) {
caps[i].valid = true;
caps[i].badge = cap.local_name();
caps[i].sel = cap.dst();
}
}
/*
* The message consists of a protocol word, the capability count, one badge
* value per capability, and the data payload.
*/
unsigned const num_msg_words = 2 + num_caps + num_data_words;
if (num_msg_words > L4_UTCB_GENERIC_DATA_SIZE) {
outstring("receive message buffer too small\n");
throw Ipc_error();
}
/* copy badge / exception code to UTCB message register */
l4_utcb_mr()->mr[0] = protocol_word;
l4_mword_t *msg_words = (l4_mword_t *)l4_utcb_mr();
*msg_words++ = protocol_word;
*msg_words++ = num_caps;
unsigned num_cap_sel = 0;
for (unsigned i = 0; i < num_caps; i++) {
Native_capability const &cap = snd_msg.cap(i);
/* store badge as normal message word */
*msg_words++ = caps[i].valid ? caps[i].badge : INVALID_BADGE;
/* setup flexpage for valid capability to delegate */
if (caps[i].valid) {
unsigned const idx = num_msg_words + 2*num_cap_sel;
l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/;
l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(caps[i].sel,
0, L4_FPAGE_RWX).raw;
num_cap_sel++;
}
}
/* store message data into UTCB message registers */
for (unsigned i = 0; i < num_data_words; i++)
l4_utcb_mr()->mr[i + 1] = snd_msg.word(i);
/* setup flexpages of capabilities to send */
for (unsigned i = 0; i < num_cap_sel; i++) {
unsigned const idx = num_msg_words + 2*i;
l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/;
l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(snd_msg.snd_cap_sel(i),
0, L4_FPAGE_RWX).raw;
}
*msg_words++ = snd_msg.word(i);
return l4_msgtag(0, num_msg_words, num_cap_sel, 0);
}
@ -202,11 +271,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
Receive_window rcv_window;
rcv_window.init();
rcv_msg.reset();
/* copy call message to the UTCBs message registers */
l4_msgtag_t const call_tag = copy_msgbuf_to_utcb(snd_msg, dst.local_name());
addr_t rcv_cap_sel = rcv_msg.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) {
addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) {
l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP;
rcv_cap_sel += L4_CAP_SIZE;
}
@ -220,106 +293,86 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
if (ipc_error(reply_tag, DEBUG_MSG))
throw Genode::Ipc_error();
return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_msg));
return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_window, rcv_msg));
}
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::_prepare_next_reply_wait()
static bool badge_matches_label(unsigned long badge, unsigned long label)
{
_reply_needed = true;
_read_offset = _write_offset = 0;
_snd_msg.snd_reset();
return badge == (label & (~0UL << 2));
}
static unsigned long wait(Msgbuf_base &rcv_msg)
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
addr_t rcv_cap_sel = rcv_msg.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) {
l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP;
rcv_cap_sel += L4_CAP_SIZE;
}
l4_utcb_br()->bdr = 0;
l4_msgtag_t tag;
do {
l4_umword_t label = 0;
tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER);
rcv_msg.label(label);
} while (ipc_error(tag, DEBUG_MSG));
/* copy message from the UTCBs message registers to the receive buffer */
return extract_msg_from_utcb(tag, rcv_msg);
}
void Ipc_server::reply()
{
l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _exception_code.value);
l4_msgtag_t tag = copy_msgbuf_to_utcb(snd_msg, exc.value);
tag = l4_ipc_send(L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_SEND_TIMEOUT_0);
ipc_error(tag, DEBUG_MSG);
_snd_msg.snd_reset();
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
if (_reply_needed) {
addr_t rcv_cap_sel = _rcv_msg.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) {
Receive_window &rcv_window = Thread_base::myself()->native_thread().rcv_window;
for (;;) {
request_msg.reset();
/* prepare receive window in UTCB */
addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base();
for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) {
l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP;
rcv_cap_sel += L4_CAP_SIZE;
}
l4_utcb_br()->bdr &= ~L4_BDR_OFFSET_MASK;
l4_umword_t label = 0;
l4_msgtag_t request_tag;
l4_umword_t label = 0; /* kernel-protected label of invoked capability */
l4_msgtag_t const reply_tag =
copy_msgbuf_to_utcb(_snd_msg, _exception_code.value);
if (exc.value != Rpc_exception_code::INVALID_OBJECT) {
l4_msgtag_t const request_tag =
l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label,
L4_IPC_SEND_TIMEOUT_0);
l4_msgtag_t const reply_tag = copy_msgbuf_to_utcb(reply_msg, exc.value);
_rcv_msg.label(label);
if (ipc_error(request_tag, false)) {
/*
* The error conditions could be a message cut (which
* we want to ignore on the server side) or a reply failure
* (for example, if the caller went dead during the call.
* In both cases, we do not reflect the error condition to
* the user but want to wait for the next proper incoming
* message. So let's just wait now.
*/
_badge = wait(_rcv_msg);
request_tag = l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, L4_IPC_SEND_TIMEOUT_0);
} else {
/* copy request message from the UTCBs message registers */
_badge = extract_msg_from_utcb(request_tag, _rcv_msg);
request_tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER);
}
} else
_badge = wait(_rcv_msg);
_prepare_next_reply_wait();
if (ipc_error(request_tag, false))
continue;
/* copy request message from the UTCBs message registers */
unsigned long const badge =
extract_msg_from_utcb(request_tag, rcv_window, request_msg);
/* ignore request if we detect a forged badge */
if (!badge_matches_label(badge, label)) {
outstring("badge does not match label, ignoring request\n");
continue;
}
return Rpc_request(Native_capability(), badge);
}
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
Ipc_server::Ipc_server()
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]),
_rcv_cs(cs)
{ }
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE])
{
Thread_base::myself()->native_thread().rcv_window.init();
}
Ipc_server::~Ipc_server() { }

View File

@ -1,86 +0,0 @@
/*
* \brief Default version of platform-specific part of server framework
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2006-05-12
*
* This version is suitable for platforms similar to L4. Each platform
* for which this implementation is not suited contains a platform-
* specific version in its respective 'base-<platform>' repository.
*/
/*
* Copyright (C) 2006-2013 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.
*/
/* Genode includes */
#include <base/rpc_server.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
using namespace Genode;
/***********************
** Server entrypoint **
***********************/
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap);
/* add server object to object pool */
obj->cap(new_obj_cap);
insert(obj);
/* return capability that uses the object id as badge */
return new_obj_cap;
}
void Rpc_entrypoint::entry()
{
Native_connection_state cs;
Ipc_server srv(cs, _snd_buf, _rcv_buf);
_ipc_server = &srv;
_cap = srv;
_cap_valid.unlock();
/*
* Now, the capability of the server activation is initialized
* an can be passed around. However, the processing of capability
* invocations should not happen until activation-using server
* is completely initialized. Thus, we wait until the activation
* gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'.
*/
_delay_start.lock();
while (!_exit_handler.exit) {
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
apply(srv.badge(), [&] (Rpc_object_base *obj) {
if (!obj) return;
try {
srv.ret(obj->dispatch(opcode, srv, srv));
} catch(Blocking_canceled&) { }
});
}
/* answer exit call, thereby wake up '~Rpc_entrypoint' */
srv.reply();
/* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */
_delay_exit.lock();
}

View File

@ -0,0 +1,42 @@
/*
* \brief Kernel-specific RM-faulter wake-up mechanism
* \author Norman Feske
* \date 2016-04-12
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <pager.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/ipc.h>
}
using namespace Genode;
void Pager_object::wake_up()
{
using namespace Fiasco;
/*
* Issue IPC to pager, transmitting the pager-object pointer as 'IP'.
*/
l4_utcb_mr()->mr[0] = 0; /* fault address */
l4_utcb_mr()->mr[1] = (l4_umword_t)this; /* instruction pointer */
l4_ipc_call(cap().dst(), l4_utcb(), l4_msgtag(0, 2, 0, 0), L4_IPC_NEVER);
}
void Pager_object::unresolved_page_fault_occurred()
{
state.unresolved_page_fault = true;
}

View File

@ -140,8 +140,7 @@ void Platform_thread::resume()
/* Send a message to the exception handler, to unblock the client */
Msgbuf<16> snd, rcv;
Ipc_marshaller marshaller(snd);
marshaller.insert(_pager_obj);
snd.insert(_pager_obj);
ipc_call(_pager_obj->cap(), snd, rcv, 0);
}

View File

@ -63,7 +63,6 @@ vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core
vpath %.cc $(REP_DIR)/src/base/thread

View File

@ -1,140 +0,0 @@
/*
* \brief IPC message buffers
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-01-03
*/
/*
* Copyright (C) 2012-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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/native_capability.h>
#include <base/stdint.h>
#include <util/string.h>
namespace Genode {
class Native_utcb;
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
class Msgbuf_base;
/**
* Instance of IPC message buffer with specified buffer size
*
* 'Msgbuf_base' must be the last class this class inherits from.
*/
template <unsigned BUF_SIZE> class Msgbuf;
}
class Genode::Msgbuf_base
{
public:
enum { MAX_CAP_ARGS = 4 };
private:
friend class Native_utcb;
friend class Ipc_marshaller;
size_t const _capacity; /* buffer size in bytes */
size_t _data_size = 0; /* marshalled data in bytes */
Native_capability _caps[MAX_CAP_ARGS]; /* capability buffer */
size_t _snd_cap_cnt = 0; /* capability counter */
size_t _rcv_cap_cnt = 0; /* capability counter */
public:
/*************************************************
** 'buf' must be the last member of this class **
*************************************************/
char buf[]; /* begin of actual message buffer */
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
void const * base() const { return &buf; }
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; }
/**
* Return pointer of message data payload
*/
void *data() { return &buf[0]; }
void const *data() const { return &buf[0]; }
size_t data_size() const { return _data_size; }
/**
* Reset capability buffer.
*/
void reset()
{
_snd_cap_cnt = 0;
_rcv_cap_cnt = 0;
}
/**
* Return how many capabilities are accepted by this message buffer
*/
size_t cap_rcv_window() { return _rcv_cap_cnt; }
/**
* Set how many capabilities are accepted by this message buffer
*/
void cap_rcv_window(size_t cnt) { _rcv_cap_cnt = cnt; }
/**
* Add capability to buffer
*/
void cap_add(Native_capability const &cap)
{
if (_snd_cap_cnt < MAX_CAP_ARGS)
_caps[_snd_cap_cnt++] = cap;
}
/**
* Return last capability from buffer.
*/
Native_capability cap_get()
{
return (_rcv_cap_cnt < _snd_cap_cnt)
? _caps[_rcv_cap_cnt++] : Native_capability();
}
};
template <unsigned BUF_SIZE>
class Genode::Msgbuf : public Genode::Msgbuf_base
{
public:
/**************************************************
** 'buf' must be the first member of this class **
**************************************************/
char buf[BUF_SIZE];
/**
* Constructor
*/
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -35,16 +35,55 @@ namespace Hw { extern Genode::Untyped_capability _main_thread_cap; }
using namespace Genode;
/*****************************
** IPC marshalling support **
*****************************/
/**
* Copy data from the message buffer to UTCB
*/
static inline void copy_msg_to_utcb(Msgbuf_base const &snd_msg, Native_utcb &utcb)
{
/* copy capabilities */
size_t const num_caps = min((size_t)Msgbuf_base::MAX_CAPS_PER_MSG,
snd_msg.used_caps());
void Ipc_marshaller::insert(Native_capability const &cap) {
_snd_msg.cap_add(cap); }
for (unsigned i = 0; i < num_caps; i++)
utcb.cap_set(i, snd_msg.cap(i).dst());
utcb.cap_cnt(num_caps);
/* copy data payload */
size_t const data_size = min(snd_msg.data_size(),
min(snd_msg.capacity(), utcb.capacity()));
memcpy(utcb.data(), snd_msg.data(), data_size);
utcb.data_size(data_size);
}
void Ipc_unmarshaller::extract(Native_capability &cap) {
cap = _rcv_msg.cap_get(); }
/**
* Copy data from UTCB to the message buffer
*/
static inline void copy_utcb_to_msg(Native_utcb const &utcb, Msgbuf_base &rcv_msg)
{
/* copy capabilities */
size_t const num_caps = min((size_t)Msgbuf_base::MAX_CAPS_PER_MSG,
utcb.cap_cnt());
for (unsigned i = 0; i < num_caps; i++) {
rcv_msg.cap(i) = utcb.cap_get(i);
if (rcv_msg.cap(i).valid())
Kernel::ack_cap(rcv_msg.cap(i).dst());
}
rcv_msg.used_caps(num_caps);
/* copy data payload */
size_t const data_size = min(utcb.data_size(),
min(utcb.capacity(), rcv_msg.capacity()));
memcpy(rcv_msg.data(), utcb.data(), data_size);
rcv_msg.data_size(data_size);
}
/****************
@ -55,23 +94,19 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
rcv_msg.cap_rcv_window(rcv_caps);
Native_utcb &utcb = *Thread_base::myself()->utcb();
retry<Genode::Allocator::Out_of_memory>(
[&] () {
/* send request and receive corresponding reply */
Thread_base::myself()->utcb()->copy_from(snd_msg);
copy_msg_to_utcb(snd_msg, *Thread_base::myself()->utcb());
switch (Kernel::send_request_msg(dst.dst(),
rcv_msg.cap_rcv_window())) {
rcv_caps)) {
case -1: throw Blocking_canceled();
case -2: throw Allocator::Out_of_memory();
default:
rcv_msg.reset();
utcb.copy_to(rcv_msg);
copy_utcb_to_msg(utcb, rcv_msg);
}
},
@ -82,30 +117,36 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::reply()
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
Thread_base::myself()->utcb()->copy_from(_snd_msg);
_snd_msg.reset();
Native_utcb &utcb = *Thread_base::myself()->utcb();
copy_msg_to_utcb(snd_msg, utcb);
utcb.exception_code(exc.value);
snd_msg.reset();
Kernel::send_reply_msg(0, false);
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
Native_utcb &utcb = *Thread_base::myself()->utcb();
retry<Genode::Allocator::Out_of_memory>(
[&] () {
int ret = 0;
if (_reply_needed) {
utcb.copy_from(_snd_msg);
utcb.exception_code(_exception_code.value);
ret = Kernel::send_reply_msg(Msgbuf_base::MAX_CAP_ARGS, true);
if (exc.value != Rpc_exception_code::INVALID_OBJECT) {
copy_msg_to_utcb(reply_msg, utcb);
utcb.exception_code(exc.value);
ret = Kernel::send_reply_msg(Msgbuf_base::MAX_CAPS_PER_MSG, true);
} else {
ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAP_ARGS);
ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAPS_PER_MSG);
}
switch (ret) {
@ -116,27 +157,17 @@ void Ipc_server::reply_wait()
},
[&] () { upgrade_pd_session_quota(3*4096); });
_rcv_msg.reset();
_snd_msg.reset();
copy_utcb_to_msg(utcb, request_msg);
utcb.copy_to(_rcv_msg);
_badge = utcb.destination();
_reply_needed = true;
_read_offset = _write_offset = 0;
return Rpc_request(Native_capability(), utcb.destination());
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
Ipc_server::Ipc_server()
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Thread_base::myself() ? Thread_base::myself()->native_thread().cap
: Hw::_main_thread_cap),
_rcv_cs(cs)
{
_snd_msg.reset();
}
: Hw::_main_thread_cap)
{ }
Ipc_server::~Ipc_server() { }

View File

@ -1,85 +0,0 @@
/*
* \brief base-hw specific part of RPC framework
* \author Stefan Kalkowski
* \date 2015-03-05
*/
/*
* 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.
*/
/* Genode includes */
#include <base/rpc_server.h>
#include <base/sleep.h>
#include <base/env.h>
#include <util/retry.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
using namespace Genode;
/***********************
** Server entrypoint **
***********************/
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap);
/* add server object to object pool */
obj->cap(new_obj_cap);
insert(obj);
/* return capability that uses the object id as badge */
return new_obj_cap;
}
void Rpc_entrypoint::entry()
{
Native_connection_state cs;
Ipc_server srv(cs, _snd_buf, _rcv_buf);
_ipc_server = &srv;
_cap = srv;
_cap_valid.unlock();
/*
* Now, the capability of the server activation is initialized
* an can be passed around. However, the processing of capability
* invocations should not happen until activation-using server
* is completely initialized. Thus, we wait until the activation
* gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'.
*/
_delay_start.lock();
while (!_exit_handler.exit) {
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
/* atomically lookup and lock referenced object */
apply(srv.badge(), [&] (Rpc_object_base *curr_obj) {
if (!curr_obj) return;
/* dispatch request */
try { srv.ret(curr_obj->dispatch(opcode, srv, srv)); }
catch (Blocking_canceled) { }
});
}
/* answer exit call, thereby wake up '~Rpc_entrypoint' */
srv.reply();
/* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */
_delay_exit.lock();
}

View File

@ -124,7 +124,7 @@ void Signal_receiver::block_for_signal()
return;
}
/* read signal data */
const void * const utcb = Thread_base::myself()->utcb()->base();
const void * const utcb = Thread_base::myself()->utcb()->data();
Signal::Data * const data = (Signal::Data *)utcb;
Signal_context * const context = data->context;
{

View File

@ -66,7 +66,7 @@ class Kernel::Ipc_node : public Ipc_node_queue::Element
Ipc_node_queue _request_queue;
/* pre-allocation array for obkject identity references */
void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAP_ARGS];
void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG];
inline void copy_msg(Ipc_node * const sender);

View File

@ -70,7 +70,7 @@ void Thread::_await_signal(Signal_receiver * const receiver)
void Thread::_receive_signal(void * const base, size_t const size)
{
assert(_state == AWAITS_SIGNAL);
Genode::memcpy((void*)utcb()->base(), base, size);
Genode::memcpy(utcb()->data(), base, size);
_become_active();
}

View File

@ -48,7 +48,7 @@ void Pager_entrypoint::entry()
if (Kernel::await_signal(_cap.dst())) continue;
Untyped_capability cap =
(*(Pager_object**)Thread_base::myself()->utcb()->base())->cap();
(*(Pager_object**)Thread_base::myself()->utcb()->data())->cap();
/*
* Synchronize access and ensure that the object is still managed

View File

@ -16,6 +16,8 @@
#define _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_
/* Genode includes */
#include <util/misc_math.h>
#include <util/string.h>
#include <base/stdint.h>
#include <base/ipc_msgbuf.h>
@ -47,30 +49,37 @@ class Genode::Native_utcb
{
public:
enum { MAX_CAP_ARGS = Msgbuf_base::MAX_CAP_ARGS};
enum { MAX_CAP_ARGS = Msgbuf_base::MAX_CAPS_PER_MSG};
enum Offsets { THREAD_MYSELF, PARENT, UTCB_DATASPACE };
private:
Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */
/*
* Note thats the member variables are sorted from the largest to the
* smallest size to avoid padding. Otherwise, the dimensioning of
* '_data' would not yield a page-sized 'Native_utcb'.
*/
size_t _cap_cnt; /* capability counter */
size_t _size; /* bytes to transfer */
size_t _data_size; /* bytes to transfer */
long _exception_code; /* result code of RPC */
Kernel::capid_t _destination; /* invoked object */
uint8_t _buf[get_page_size() - sizeof(_caps) -
sizeof(_cap_cnt) - sizeof(_size) -
sizeof(_destination) - sizeof(_exception_code)];
Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */
uint8_t _data[get_page_size() - sizeof(_caps) -
sizeof(_cap_cnt) - sizeof(_data_size) -
sizeof(_destination) - sizeof(_exception_code)];
public:
Native_utcb& operator= (const Native_utcb &o)
Native_utcb& operator= (const Native_utcb &other)
{
_cap_cnt = 0;
_size = o._size;
_exception_code = o._exception_code;
_destination = o._destination;
memcpy(_buf, o._buf, _size);
_data_size = min(sizeof(_data), other._data_size);
_exception_code = other._exception_code;
_destination = other._destination;
memcpy(_data, other._data, _data_size);
return *this;
}
@ -91,7 +100,7 @@ class Genode::Native_utcb
/**
* Return the count of capabilities in the UTCB
*/
size_t cap_cnt() { return _cap_cnt; }
size_t cap_cnt() const { return _cap_cnt; }
/**
* Set the count of capabilities in the UTCB
@ -101,41 +110,43 @@ class Genode::Native_utcb
/**
* Return the start address of the payload data
*/
void const * base() const { return &_buf; }
void const *data() const { return &_data[0]; }
void *data() { return &_data[0]; }
/**
* Copy data from the message buffer 'snd_msg' to this UTCB
* Return maximum number of bytes for message payload
*/
void copy_from(Msgbuf_base const &snd_msg)
{
_size = min(snd_msg.data_size(), sizeof(_buf));
_cap_cnt = snd_msg._snd_cap_cnt;
for (unsigned i = 0; i < _cap_cnt; i++)
_caps[i] = snd_msg._caps[i].dst();
memcpy(_buf, snd_msg.buf, min(_size, snd_msg.capacity()));
}
size_t capacity() const { return sizeof(_data); }
/**
* Copy data from this UTCB to the message buffer 'o'
* Return size of message data in bytes
*/
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];
if (o._caps[i].valid()) Kernel::ack_cap(o._caps[i].dst());
}
size_t data_size() const { return _data_size; }
memcpy(o.buf, _buf, min(_size, o.capacity()));
/**
* Define size of message data to be transferred, in bytes
*/
void data_size(size_t data_size)
{
_data_size = min(data_size, sizeof(_data));
}
/**
* Return the capability id at index 'i'
*/
Kernel::capid_t cap_get(unsigned i) {
return (i < _cap_cnt) ? _caps[i] : Kernel::cap_id_invalid(); }
Kernel::capid_t cap_get(unsigned i) const
{
return (i < MAX_CAP_ARGS) ? _caps[i] : Kernel::cap_id_invalid();
}
/**
* Set the capability id at index 'i'
*/
void cap_set(unsigned i, Kernel::capid_t cap)
{
if (i < MAX_CAP_ARGS)
_caps[i] = cap;
}
/**
* Set the capability id 'cap_id' at the next index
@ -144,4 +155,7 @@ class Genode::Native_utcb
if (_cap_cnt < MAX_CAP_ARGS) _caps[_cap_cnt++] = cap_id; }
};
static_assert(sizeof(Genode::Native_utcb) == Genode::get_page_size(),
"Native_utcb is not page-sized");
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ */

View File

@ -1,129 +0,0 @@
/*
* \brief Linux-specific layout of IPC message buffer
* \author Norman Feske
* \date 2006-06-14
*/
/*
* Copyright (C) 2006-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/stdint.h>
namespace Genode {
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
class Msgbuf_base
{
public:
enum { MAX_CAPS_PER_MSG = 8 };
protected:
friend class Ipc_marshaller;
/*
* Capabilities (file descriptors) to be transferred
*/
int _caps[MAX_CAPS_PER_MSG];
Genode::size_t _used_caps = 0;
Genode::size_t _read_cap_index = 0;
/**
* Maximum size of plain-data message payload
*/
Genode::size_t const _capacity;
/**
* Actual size of plain-data message payload
*/
Genode::size_t _data_size = 0;
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
struct Headroom { long space[4]; } _headroom;
char _msg_start[]; /* symbol marks start of message buffer data */
/*
* No member variables are allowed beyond this point!
*/
public:
template <typename T>
T &header()
{
static_assert(sizeof(T) <= sizeof(Headroom),
"Header size exceeds message headroom");
return *reinterpret_cast<T *>(_msg_start - sizeof(T));
}
/**
* Return size of message buffer
*/
Genode::size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
void reset_caps() { _used_caps = 0; _read_cap_index = 0; }
bool append_cap(int cap)
{
if (_used_caps == MAX_CAPS_PER_MSG)
return false;
_caps[_used_caps++] = cap;
return true;
}
int read_cap()
{
if (_read_cap_index == _used_caps)
return -1;
return _caps[_read_cap_index++];
}
size_t used_caps() const { return _used_caps; }
int cap(unsigned index) const
{
return index < _used_caps ? _caps[index] : -1;
}
};
/**
* Pump up IPC message buffer to specified buffer size
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -19,7 +19,7 @@
/* base-internal includes */
#include <base/internal/platform_env.h>
#include <base/internal/native_connection_state.h>
#include <base/internal/native_thread.h>
using namespace Genode;
@ -180,24 +180,25 @@ Platform_env::Platform_env()
namespace Genode {
Native_connection_state server_socket_pair()
Socket_pair server_socket_pair()
{
Linux_native_cpu_client native_cpu(env()->cpu_session()->native_cpu());
Native_connection_state ncs;
Socket_pair socket_pair;
Thread_base *thread = Thread_base::myself();
if (thread) {
ncs.server_sd = native_cpu.server_sd(thread->cap()).dst().socket;
ncs.client_sd = native_cpu.client_sd(thread->cap()).dst().socket;
socket_pair.server_sd = native_cpu.server_sd(thread->cap()).dst().socket;
socket_pair.client_sd = native_cpu.client_sd(thread->cap()).dst().socket;
thread->native_thread().socket_pair = socket_pair;
}
return ncs;
return socket_pair;
}
void destroy_server_socket_pair(Native_connection_state const &ncs)
void destroy_server_socket_pair(Socket_pair socket_pair)
{
/* close local file descriptor if it is valid */
if (ncs.server_sd != -1) lx_close(ncs.server_sd);
if (ncs.client_sd != -1) lx_close(ncs.client_sd);
if (socket_pair.server_sd != -1) lx_close(socket_pair.server_sd);
if (socket_pair.client_sd != -1) lx_close(socket_pair.client_sd);
}
}

View File

@ -23,13 +23,13 @@
#include <base/internal/socket_descriptor_registry.h>
#include <base/internal/native_thread.h>
#include <base/internal/ipc_server.h>
#include <base/internal/server_socket_pair.h>
/* Linux includes */
#include <linux_syscalls.h>
#include <sys/un.h>
#include <sys/socket.h>
using namespace Genode;
@ -52,70 +52,20 @@ using namespace Genode;
*/
struct Protocol_header
{
/* badge of invoked object (on call) / exception code (on reply) */
unsigned long protocol_word;
size_t num_caps;
/* badges of the transferred capability arguments */
unsigned long badges[Msgbuf_base::MAX_CAPS_PER_MSG];
enum { INVALID_BADGE = ~0UL };
void *msg_start() { return &protocol_word; }
};
/*****************************
** IPC marshalling support **
*****************************/
void Ipc_marshaller::insert(Native_capability const &cap)
{
if (cap.valid()) {
insert(cap.local_name());
_snd_msg.append_cap(cap.dst().socket);
} else {
insert(-1L);
}
}
void Ipc_unmarshaller::extract(Native_capability &cap)
{
long local_name = 0;
extract(local_name);
if (local_name == -1) {
/* construct invalid capability */
cap = Genode::Native_capability();
} else {
/* construct valid capability */
int const socket = _rcv_msg.read_cap();
cap = Native_capability(Cap_dst_policy::Dst(socket), local_name);
}
}
namespace Genode {
/*
* Helper for obtaining a bound and connected socket pair
*
* For core, the implementation is just a wrapper around
* 'lx_server_socket_pair()'. For all other processes, the implementation
* requests the socket pair from the Env::CPU session interface using a
* Linux-specific interface extension.
*/
Native_connection_state server_socket_pair();
/*
* Helper to destroy the server socket pair
*
* For core, this is a no-op. For all other processes, the server and client
* sockets are closed.
*/
void destroy_server_socket_pair(Native_connection_state const &ncs);
}
/******************************
** File-descriptor registry **
******************************/
@ -205,7 +155,7 @@ namespace {
{
public:
enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG + 1 };
private:
@ -283,23 +233,51 @@ namespace {
} /* unnamed namespace */
static void insert_sds_into_message(Message &msg,
Protocol_header &header,
Genode::Msgbuf_base &snd_msgbuf)
{
for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++) {
Native_capability const &cap = snd_msgbuf.cap(i);
if (cap.valid()) {
msg.marshal_socket(cap.dst().socket);
header.badges[i] = cap.local_name();
} else {
header.badges[i] = Protocol_header::INVALID_BADGE;
}
}
header.num_caps = snd_msgbuf.used_caps();
}
/**
* Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf'
*/
static void extract_sds_from_message(unsigned start_index, Message const &msg,
static void extract_sds_from_message(unsigned start_index,
Message const &msg,
Protocol_header const &header,
Genode::Msgbuf_base &buf)
{
buf.reset_caps();
unsigned sd_cnt = 0;
for (unsigned i = 0; i < min(header.num_caps, Msgbuf_base::MAX_CAPS_PER_MSG); i++) {
/* start at offset 1 to skip the reply channel */
for (unsigned i = start_index; i < msg.num_sockets(); i++) {
unsigned long const badge = header.badges[i];
int const sd = msg.socket_at_index(i);
/* an invalid capabity was transferred */
if (badge == Protocol_header::INVALID_BADGE) {
buf.insert(Native_capability());
continue;
}
int const sd = msg.socket_at_index(start_index + sd_cnt++);
int const id = lookup_tid_by_client_socket(sd);
int const associated_sd = Genode::ep_sd_registry()->try_associate(sd, id);
buf.append_cap(associated_sd);
buf.insert(Native_capability(Cap_dst_policy::Dst(associated_sd), badge));
if ((associated_sd >= 0) && (associated_sd != sd)) {
@ -313,57 +291,6 @@ static void extract_sds_from_message(unsigned start_index, Message const &msg,
}
/**
* Return type of 'lx_wait'
*/
struct Request
{
/**
* Destination socket for sending the reply of the RPC function
*/
int reply_socket = 0;
/**
* Identity of invoked server object
*/
unsigned long badge = 0;
};
/**
* for request from client
*
* \return socket descriptor of reply capability
*/
static Request lx_wait(Genode::Native_connection_state &cs,
Genode::Msgbuf_base &rcv_msgbuf)
{
Protocol_header &header = rcv_msgbuf.header<Protocol_header>();
Message msg(header.msg_start(), sizeof(Protocol_header) + rcv_msgbuf.capacity());
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
int const ret = lx_recvmsg(cs.server_sd, msg.msg(), 0);
/* system call got interrupted by a signal */
if (ret == -LX_EINTR)
throw Genode::Blocking_canceled();
if (ret < 0) {
PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd);
throw Genode::Ipc_error();
}
Request request;
request.reply_socket = msg.socket_at_index(0);
request.badge = header.protocol_word;
extract_sds_from_message(1, msg, rcv_msgbuf);
return request;
}
/**
* Send reply to client
*/
@ -377,13 +304,10 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
Message msg(header.msg_start(), sizeof(Protocol_header) + snd_msgbuf.data_size());
/*
* Marshall capabilities to be transferred to the client
*/
for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++)
msg.marshal_socket(snd_msgbuf.cap(i));
/* marshall capabilities to be transferred to the client */
insert_sds_into_message(msg, header, snd_msgbuf);
int ret = lx_sendmsg(reply_socket, msg.msg(), 0);
int const ret = lx_sendmsg(reply_socket, msg.msg(), 0);
/* ignore reply send error caused by disappearing client */
if (ret >= 0 || ret == -LX_ECONNREFUSED) {
@ -392,7 +316,7 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
}
if (ret < 0)
PRAW("[%d] lx_sendmsg failed with %d in lx_reply()", lx_getpid(), ret);
PRAW("[%d] lx_sendmsg failed with %d in lx_reply() reply_socket=%d", lx_gettid(), ret, reply_socket);
}
@ -448,8 +372,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
snd_msg.marshal_socket(reply_channel.remote_socket());
/* marshal capabilities contained in 'snd_msgbuf' */
for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++)
snd_msg.marshal_socket(snd_msgbuf.cap(i));
insert_sds_into_message(snd_msg, snd_header, snd_msgbuf);
int const send_ret = lx_sendmsg(dst.dst().socket, snd_msg.msg(), 0);
if (send_ret < 0) {
@ -466,6 +389,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
sizeof(Protocol_header) + rcv_msgbuf.capacity());
rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
rcv_msgbuf.reset();
int const recv_ret = lx_recvmsg(reply_channel.local_socket(), rcv_msg.msg(), 0);
/* system call got interrupted by a signal */
@ -477,40 +401,31 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
throw Genode::Ipc_error();
}
extract_sds_from_message(0, rcv_msg, rcv_msgbuf);
extract_sds_from_message(0, rcv_msg, rcv_header, rcv_msgbuf);
return Rpc_exception_code(rcv_header.protocol_word);
}
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::_prepare_next_reply_wait()
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
_read_offset = _write_offset = 0;
/* reset capability slots of send message buffer */
_snd_msg.reset_caps();
try { lx_reply(caller.dst().socket, exc, snd_msg); } catch (Ipc_error) { }
}
void Ipc_server::reply()
{
try {
lx_reply(_caller.dst().socket, _exception_code, _snd_msg); }
catch (Ipc_error) { }
_prepare_next_reply_wait();
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
/* when first called, there was no request yet */
if (_reply_needed)
lx_reply(_caller.dst().socket, _exception_code, _snd_msg);
if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT)
lx_reply(last_caller.dst().socket, exc, reply_msg);
/*
* Block infinitely if called from the main thread. This may happen if the
@ -521,71 +436,86 @@ void Ipc_server::reply_wait()
for (;;) lx_nanosleep(&ts, 0);
}
try {
Request const request = lx_wait(_rcv_cs, _rcv_msg);
for (;;) {
Protocol_header &header = request_msg.header<Protocol_header>();
Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity());
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
Native_thread &native_thread = Thread_base::myself()->native_thread();
request_msg.reset();
int const ret = lx_recvmsg(native_thread.socket_pair.server_sd, msg.msg(), 0);
/* system call got interrupted by a signal */
if (ret == -LX_EINTR)
continue;
if (ret < 0) {
PRAW("lx_recvmsg failed with %d in ipc_reply_wait, sd=%d",
ret, native_thread.socket_pair.server_sd);
continue;
}
int const reply_socket = msg.socket_at_index(0);
unsigned long const badge = header.protocol_word;
/* start at offset 1 to skip the reply channel */
extract_sds_from_message(1, msg, header, request_msg);
/* remember reply capability */
enum { DUMMY_LOCAL_NAME = -1 };
typedef Native_capability::Dst Dst;
_caller = Native_capability(Dst(request.reply_socket), DUMMY_LOCAL_NAME);
_badge = request.badge;
_prepare_next_reply_wait();
} catch (Blocking_canceled) { }
_reply_needed = true;
return Rpc_request(Native_capability(Dst(reply_socket), ~0UL), badge);
}
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
Ipc_server::Ipc_server()
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Dst(-1), 0),
_rcv_cs(cs)
Native_capability(Dst(-1), 0)
{
Thread_base *thread = Thread_base::myself();
/*
* If 'thread' is 0, the constructor was called by the main thread. By
* definition, main is never an RPC entrypoint. However, the main thread
* may call 'sleep_forever()', which instantiates 'Ipc_server'.
*/
if (!Thread_base::myself())
return;
if (thread && thread->native_thread().is_ipc_server) {
Native_thread &native_thread = Thread_base::myself()->native_thread();
if (native_thread.is_ipc_server) {
PRAW("[%d] unexpected multiple instantiation of Ipc_server by one thread",
lx_gettid());
struct Ipc_server_multiple_instance { };
throw Ipc_server_multiple_instance();
}
if (thread) {
_rcv_cs = server_socket_pair();
thread->native_thread().is_ipc_server = true;
}
Socket_pair const socket_pair = server_socket_pair();
native_thread.socket_pair = socket_pair;
native_thread.is_ipc_server = true;
/* override capability initialization */
*static_cast<Native_capability *>(this) =
Native_capability(Native_capability::Dst(_rcv_cs.client_sd), 0);
_prepare_next_reply_wait();
Native_capability(Native_capability::Dst(socket_pair.client_sd), 0);
}
Ipc_server::~Ipc_server()
{
Genode::ep_sd_registry()->disassociate(_rcv_cs.client_sd);
if (!Thread_base::myself())
return;
/*
* Reset thread role to non-server such that we can enter 'sleep_forever'
* without getting a warning.
*/
Thread_base *thread = Thread_base::myself();
if (thread)
thread->native_thread().is_ipc_server = false;
Native_thread &native_thread = Thread_base::myself()->native_thread();
destroy_server_socket_pair(_rcv_cs);
_rcv_cs.client_sd = -1;
_rcv_cs.server_sd = -1;
Genode::ep_sd_registry()->disassociate(native_thread.socket_pair.client_sd);
native_thread.is_ipc_server = false;
destroy_server_socket_pair(native_thread.socket_pair);
native_thread.socket_pair = Socket_pair();
}

View File

@ -21,7 +21,7 @@
#include <cpu_session/cpu_session.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/server_socket_pair.h>
/* core includes */
#include <pager.h>
@ -68,7 +68,7 @@ namespace Genode {
/**
* Unix-domain socket pair bound to the thread
*/
Native_connection_state _ncs;
Socket_pair _socket_pair;
/*
* Dummy pager object that is solely used for storing the

View File

@ -21,6 +21,7 @@
/* base-internal includes */
#include <base/internal/socket_descriptor_registry.h>
#include <base/internal/server_socket_pair.h>
/* core-local includes */
#include <resource_path.h>
@ -43,25 +44,25 @@ struct Uds_addr : sockaddr_un
/**
* Utility: Create named socket pair for given unique ID
*/
static inline Genode::Native_connection_state create_server_socket_pair(long id)
static inline Genode::Socket_pair create_server_socket_pair(long id)
{
Genode::Native_connection_state ncs;
Genode::Socket_pair socket_pair;
/*
* Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for
* binding.
*/
if (id == -1)
return ncs;
return socket_pair;
Uds_addr addr(id);
/*
* Create server-side socket
*/
ncs.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ncs.server_sd < 0) {
PRAW("Error: Could not create server-side socket (ret=%d)", ncs.server_sd);
socket_pair.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (socket_pair.server_sd < 0) {
PRAW("Error: Could not create server-side socket (ret=%d)", socket_pair.server_sd);
class Server_socket_failed { };
throw Server_socket_failed();
}
@ -69,7 +70,7 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id)
/* make sure bind succeeds */
lx_unlink(addr.sun_path);
int const bind_ret = lx_bind(ncs.server_sd, (sockaddr *)&addr, sizeof(addr));
int const bind_ret = lx_bind(socket_pair.server_sd, (sockaddr *)&addr, sizeof(addr));
if (bind_ret < 0) {
PRAW("Error: Could not bind server socket (ret=%d)", bind_ret);
class Bind_failed { };
@ -79,21 +80,21 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id)
/*
* Create client-side socket
*/
ncs.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ncs.client_sd < 0) {
PRAW("Error: Could not create client-side socket (ret=%d)", ncs.client_sd);
socket_pair.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (socket_pair.client_sd < 0) {
PRAW("Error: Could not create client-side socket (ret=%d)", socket_pair.client_sd);
class Client_socket_failed { };
throw Client_socket_failed();
}
int const conn_ret = lx_connect(ncs.client_sd, (sockaddr *)&addr, sizeof(addr));
int const conn_ret = lx_connect(socket_pair.client_sd, (sockaddr *)&addr, sizeof(addr));
if (conn_ret < 0) {
PRAW("Error: Could not connect client-side socket (ret=%d)", conn_ret);
class Connect_failed { };
throw Connect_failed();
}
ncs.client_sd = Genode::ep_sd_registry()->try_associate(ncs.client_sd, id);
socket_pair.client_sd = Genode::ep_sd_registry()->try_associate(socket_pair.client_sd, id);
/*
* Wipe Unix domain socket from the file system. It will live as long as
@ -101,7 +102,7 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id)
*/
lx_unlink(addr.sun_path);
return ncs;
return socket_pair;
}
#endif /* _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_ */

View File

@ -158,19 +158,19 @@ void Core_parent::exit(int exit_value)
namespace Genode {
Native_connection_state server_socket_pair()
Socket_pair server_socket_pair()
{
return create_server_socket_pair(Thread_base::myself()->native_thread().tid);
}
void destroy_server_socket_pair(Native_connection_state const &ncs)
void destroy_server_socket_pair(Socket_pair socket_pair)
{
/*
* As entrypoints in core are never destructed, this function is only
* called on IPC-client destruction. In this case, it's a no-op in core
* as well as in Genode processes.
*/
if (ncs.server_sd != -1 || ncs.client_sd != -1)
if (socket_pair.server_sd != -1 || socket_pair.client_sd != -1)
PERR("%s called for IPC server which should never happen", __func__);
}
}

View File

@ -85,13 +85,13 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned, addr_t)
Platform_thread::~Platform_thread()
{
ep_sd_registry()->disassociate(_ncs.client_sd);
ep_sd_registry()->disassociate(_socket_pair.client_sd);
if (_ncs.client_sd)
lx_close(_ncs.client_sd);
if (_socket_pair.client_sd)
lx_close(_socket_pair.client_sd);
if (_ncs.server_sd)
lx_close(_ncs.server_sd);
if (_socket_pair.server_sd)
lx_close(_socket_pair.server_sd);
_registry()->remove(this);
}
@ -119,15 +119,15 @@ void Platform_thread::resume()
int Platform_thread::client_sd()
{
/* construct socket pair on first call */
if (_ncs.client_sd == -1)
_ncs = create_server_socket_pair(_tid);
if (_socket_pair.client_sd == -1)
_socket_pair = create_server_socket_pair(_tid);
return _ncs.client_sd;
return _socket_pair.client_sd;
}
int Platform_thread::server_sd()
{
client_sd();
return _ncs.server_sd;
return _socket_pair.server_sd;
}

View File

@ -1,28 +0,0 @@
/*
* \brief Connection state of incoming RPC request
* \author Norman Feske
* \date 2016-03-03
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#include <base/stdint.h>
namespace Genode { struct Native_connection_state; }
struct Genode::Native_connection_state
{
int server_sd = -1;
int client_sd = -1;
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */

View File

@ -15,6 +15,7 @@
#define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_
#include <base/stdint.h>
#include <base/internal/server_socket_pair.h>
namespace Genode { struct Native_thread; }
@ -45,6 +46,8 @@ struct Genode::Native_thread
*/
Meta_data *meta_data = nullptr;
Socket_pair socket_pair;
Native_thread() { }
};

View File

@ -0,0 +1,44 @@
/*
* \brief Socket pair used by RPC entrypoint
* \author Norman Feske
* \date 2016-03-25
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_
#define _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_
namespace Genode {
struct Socket_pair
{
int client_sd = -1;
int server_sd = -1;
};
/*
* Helper for obtaining a bound and connected socket pair
*
* For core, the implementation is just a wrapper around
* 'lx_server_socket_pair()'. For all other processes, the implementation
* requests the socket pair from the Env::CPU session interface using a
* Linux-specific interface extension.
*/
Socket_pair server_socket_pair();
/*
* Helper to destroy the server socket pair
*
* For core, this is a no-op. For all other processes, the server and client
* sockets are closed.
*/
void destroy_server_socket_pair(Socket_pair);
}
#endif /* _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_ */

View File

@ -1,453 +0,0 @@
/*
* \brief IPC message buffer layout for NOVA
* \author Norman Feske
* \author Alexander Boettcher
* \date 2009-10-02
*
* On NOVA, we use IPC to transmit plain data and for capability delegation
* and capability translation.
* Therefore the message buffer contains three categories of payload. The
* capability-specific part are the members '_snd_pt*' (sending capability
* selectors) and '_rcv_pt*' (receiving capability selectors).
*/
/*
* Copyright (C) 2009-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
namespace Genode {
class Ipc_marshaller;
class Msgbuf_base
{
public:
enum {
MAX_CAP_ARGS_LOG2 = 2,
MAX_CAP_ARGS = 1 << MAX_CAP_ARGS_LOG2
};
protected:
friend class Ipc_marshaller;
size_t const _capacity;
size_t _data_size = 0;
/**
* Number of portal-capability selectors to send
*/
size_t _snd_pt_sel_cnt = 0;
/**
* Portal capability selectors to delegate
*/
Native_capability _snd_pt_sel[MAX_CAP_ARGS];
/**
* Base of portal receive window
*/
addr_t _rcv_pt_base = 0;
struct {
addr_t sel = 0;
bool del = 0;
} _rcv_pt_sel[MAX_CAP_ARGS];
/**
* Normally the received capabilities start from the beginning of
* the receive window (_rcv_pt_base), densely packed ascending.
* However, a receiver may send invalid caps, which will cause
* capability-selector gaps in the receiver window. Or a
* misbehaving sender may even intentionally place a cap at the end
* of the receive window. The position of a cap within the receive
* window is fundamentally important to correctly maintain the
* component-local capability-selector reference count.
*
* Additionally, the position is also required to decide whether a
* kernel capability must be revoked during the receive window
* cleanup/re-usage. '_rcv_pt_cap_free' is used to track this
* information in order to free up and revoke selectors
* (message-buffer cleanup).
*
* Meanings of the enums:
* - FREE_INVALID - invalid cap selector, no cap_map entry
* - FREE_SEL - valid cap selector, invalid kernel capability
* - UNUSED_CAP - valid selector and cap, not read/used yet
* - USED_CAP - valid sel and cap, read/used by stream operator
*/
enum { FREE_INVALID, FREE_SEL, UNUSED_CAP, USED_CAP }
_rcv_pt_cap_free [MAX_CAP_ARGS];
/**
* Read counter for unmarshalling portal capability
* selectors
*/
unsigned short _rcv_pt_sel_cnt = 0;
unsigned short _rcv_pt_sel_max = 0;
unsigned short _rcv_wnd_log2 = 0;
char _msg_start[]; /* symbol marks start of message */
public:
enum { INVALID_INDEX = ~0UL };
/**
* Constructor
*/
Msgbuf_base(size_t capacity)
:
_capacity(capacity),
_rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2)
{
rcv_reset();
snd_reset();
}
~Msgbuf_base()
{
rcv_reset();
}
/*
* Begin of actual message buffer
*/
char buf[];
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; }
/**
* Return pointer of message data payload
*/
void *data() { return &_msg_start[0]; }
void const *data() const { return &_msg_start[0]; }
unsigned long &word(unsigned i)
{
return reinterpret_cast<unsigned long *>(buf)[i];
}
size_t data_size() const { return _data_size; }
/**
* Reset portal capability selector payload
*/
void snd_reset() {
for (unsigned i = 0; i < MAX_CAP_ARGS; i++) {
+_snd_pt_sel[i];
_snd_pt_sel[i] = Native_capability();
}
_snd_pt_sel_cnt = 0;
}
/**
* Append portal capability selector to message buffer
*/
bool snd_append_pt_sel(Native_capability const &cap)
{
if (_snd_pt_sel_cnt >= MAX_CAP_ARGS - 1)
return false;
_snd_pt_sel[_snd_pt_sel_cnt++ ] = cap;
return true;
}
/**
* Return number of marshalled portal-capability
* selectors
*/
size_t snd_pt_sel_cnt() const
{
return _snd_pt_sel_cnt;
}
/**
* Return portal capability selector
*
* \param i index (0 ... 'pt_sel_cnt()' - 1)
* \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) const
{
if (i >= _snd_pt_sel_cnt)
return Nova::Obj_crd();
trans_map = _snd_pt_sel[i].trans_map();
return Nova::Obj_crd(_snd_pt_sel[i].local_name(), 0,
_snd_pt_sel[i].dst().rights());
}
/**
* Request current portal-receive window
*/
addr_t rcv_pt_base() const { return _rcv_pt_base; }
/**
* Set log2 number of capabilities to be received during reply of
* a IPC call.
*/
void rcv_wnd(unsigned short const caps_log2)
{
if (caps_log2 > MAX_CAP_ARGS_LOG2)
nova_die();
_rcv_wnd_log2 = caps_log2;
}
/**
* Reset portal-capability receive window
*/
void rcv_reset()
{
if (!rcv_invalid()) { rcv_cleanup(false); }
_rcv_pt_sel_cnt = 0;
_rcv_pt_sel_max = 0;
_rcv_pt_base = INVALID_INDEX;
}
/**
* Return received portal-capability selector
*/
void 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 = Native_capability(_rcv_pt_sel[_rcv_pt_sel_cnt++].sel);
}
/**
* Return true if receive window must be re-initialized
*/
bool rcv_invalid() const
{
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.
*
* \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' - receive window must be re-initialized
* 'false' - portal selectors has been kept
*/
bool rcv_cleanup(bool keep, unsigned short const new_max = MAX_CAP_ARGS)
{
/* 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;
}
/**
* Initialize receive window for portal capability
* selectors
*
* \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_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'.
*/
bool prepare_rcv_window(Nova::Utcb *utcb,
addr_t rcv_window = INVALID_INDEX)
{
/* 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;
}
/**
* 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, addr_t const rcv_window = INVALID_INDEX)
{
using namespace Nova;
unsigned const rcv_items = (utcb->items >> 16) & 0xffffu;
_rcv_pt_sel_max = 0;
_rcv_pt_sel_cnt = 0;
unsigned short const max = 1U << utcb->crd_rcv.order();
if (max > MAX_CAP_ARGS)
nova_die();
for (unsigned short i = 0; i < MAX_CAP_ARGS; i++)
_rcv_pt_cap_free [i] = (i >= max) ? FREE_INVALID : FREE_SEL;
for (unsigned i = 0; i < rcv_items; i++) {
Nova::Utcb::Item * item = utcb->get_item(i);
if (!item)
break;
Nova::Crd cap(item->crd);
/* track which items we got mapped */
if (!cap.is_null() && item->is_del()) {
/* should never happen */
if (cap.base() < rcv_pt_base() ||
(cap.base() >= rcv_pt_base() + max))
nova_die();
_rcv_pt_cap_free [cap.base() - rcv_pt_base()] = UNUSED_CAP;
}
if (_rcv_pt_sel_max >= max) continue;
/* track the order of mapped and translated items */
if (cap.is_null()) {
_rcv_pt_sel[_rcv_pt_sel_max].sel = INVALID_INDEX;
_rcv_pt_sel[_rcv_pt_sel_max++].del = false;
} else {
_rcv_pt_sel[_rcv_pt_sel_max].sel = cap.base();
_rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del();
}
}
/*
* If a specific rcv_window has been specified,
* (see prepare_rcv_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 (rcv_window != INVALID_INDEX)
_rcv_pt_base = INVALID_INDEX;
utcb->crd_rcv = 0;
}
};
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -54,7 +54,6 @@ namespace Genode {
: dst(sel, 0, rights) { }
} _cap;
bool _trans_map;
addr_t _rcv_window;
enum { INVALID_INDEX = ~0UL };
@ -80,7 +79,7 @@ namespace Genode {
*/
Native_capability()
: _cap(), _trans_map(true), _rcv_window(INVALID_INDEX) {}
: _cap(), _rcv_window(INVALID_INDEX) {}
explicit
Native_capability(addr_t sel, unsigned rights = 0x1f)
@ -92,13 +91,12 @@ namespace Genode {
_inc();
}
_trans_map = true;
_rcv_window = INVALID_INDEX;
_rcv_window = INVALID_INDEX;
}
Native_capability(const Native_capability &o)
: _cap(o._cap), _trans_map(o._trans_map),
_rcv_window(o._rcv_window) { if (valid()) _inc(); }
: _cap(o._cap), _rcv_window(o._rcv_window)
{ if (valid()) _inc(); }
~Native_capability() { if (valid()) _dec(); }
@ -108,10 +106,13 @@ namespace Genode {
bool operator==(const Native_capability &o) const {
return local_name() == o.local_name(); }
Native_capability operator+ () const
/**
* Inhibit removal of capability from cap map if it's the last reference
*/
void keep_if_last_reference()
{
if (valid()) _inc(true);
return *this;
if (valid())
_inc(true);
}
/**
@ -126,7 +127,6 @@ namespace Genode {
if (valid()) _dec();
_cap = o._cap;
_trans_map = o._trans_map;
_rcv_window = o._rcv_window;
if (valid()) _inc();
@ -179,17 +179,6 @@ namespace Genode {
{
return Native_capability();
}
/**
* 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; }
};
}

View File

@ -20,6 +20,7 @@
#define _INCLUDE__NOVA__NATIVE_THREAD_H_
#include <base/stdint.h>
#include <nova/receive_window.h>
namespace Genode { struct Native_thread; }
@ -31,6 +32,9 @@ struct Genode::Native_thread
addr_t exc_pt_sel; /* base of event portal window */
bool is_vcpu;
/* receive window for capability selectors received at the server side */
Receive_window rcv_window;
Native_thread() : ec_sel(INVALID_INDEX),
exc_pt_sel(INVALID_INDEX), is_vcpu(false) { }
};

View File

@ -0,0 +1,338 @@
/*
* \brief Receive window for capability selectors
* \author Alexander Boettcher
* \author Norman Feske
* \date 2016-03-22
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__NOVA__RECEIVE_WINDOW_H_
#define _INCLUDE__NOVA__RECEIVE_WINDOW_H_
/* Genode includes */
#include <base/stdint.h>
#include <base/ipc_msgbuf.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
namespace Genode { struct Receive_window; }
struct Genode::Receive_window
{
public:
enum {
MAX_CAP_ARGS_LOG2 = 2,
MAX_CAP_ARGS = 1UL << MAX_CAP_ARGS_LOG2
};
static_assert(MAX_CAP_ARGS == (size_t)Msgbuf_base::MAX_CAPS_PER_MSG,
"Inconsistency between Receive_window and Msgbuf_base");
private:
/**
* Base of portal receive window
*/
addr_t _rcv_pt_base = 0;
struct {
addr_t sel = 0;
bool del = 0;
} _rcv_pt_sel[MAX_CAP_ARGS];
/**
* Normally the received capabilities start from the beginning of
* the receive window (_rcv_pt_base), densely packed ascending.
* However, a receiver may send invalid caps, which will cause
* capability-selector gaps in the receiver window. Or a
* misbehaving sender may even intentionally place a cap at the end
* of the receive window. The position of a cap within the receive
* window is fundamentally important to correctly maintain the
* component-local capability-selector reference count.
*
* Additionally, the position is also required to decide whether a
* kernel capability must be revoked during the receive window
* cleanup/re-usage. '_rcv_pt_cap_free' is used to track this
* information in order to free up and revoke selectors
* (message-buffer cleanup).
*
* Meanings of the enums:
* - FREE_INVALID - invalid cap selector, no cap_map entry
* - FREE_SEL - valid cap selector, invalid kernel capability
* - UNUSED_CAP - valid selector and cap, not read/used yet
* - USED_CAP - valid sel and cap, read/used by stream operator
*/
enum { FREE_INVALID, FREE_SEL, UNUSED_CAP, USED_CAP }
_rcv_pt_cap_free [MAX_CAP_ARGS];
/**
* Read counter for unmarshalling portal capability
* selectors
*/
unsigned short _rcv_pt_sel_cnt = 0;
unsigned short _rcv_pt_sel_max = 0;
unsigned short _rcv_wnd_log2 = 0;
/**
* Reset portal-capability receive window
*/
void _rcv_reset()
{
if (!rcv_invalid()) { rcv_cleanup(false); }
_rcv_pt_sel_cnt = 0;
_rcv_pt_sel_max = 0;
_rcv_pt_base = INVALID_INDEX;
}
public:
enum { INVALID_INDEX = ~0UL };
Receive_window()
:
_rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2)
{
_rcv_reset();
}
~Receive_window()
{
_rcv_reset();
}
/**
* Set log2 number of capabilities to be received during reply of
* a IPC call.
*/
void rcv_wnd(unsigned short const caps_log2)
{
if (caps_log2 > MAX_CAP_ARGS_LOG2)
nova_die();
_rcv_wnd_log2 = caps_log2;
}
/**
* Return received portal-capability selector
*/
void 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 = Native_capability(_rcv_pt_sel[_rcv_pt_sel_cnt++].sel);
}
/**
* Return true if receive window must be re-initialized
*/
bool rcv_invalid() const
{
return _rcv_pt_base == INVALID_INDEX;
}
unsigned num_received_caps() const { return _rcv_pt_sel_max; }
/**
* 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.
*
* \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' - receive window must be re-initialized
* 'false' - portal selectors has been kept
*/
bool rcv_cleanup(bool keep, unsigned short const new_max = MAX_CAP_ARGS)
{
/* 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;
}
/**
* Initialize receive window for portal capability
* selectors
*
* \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_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'.
*/
bool prepare_rcv_window(Nova::Utcb &utcb,
addr_t rcv_window = INVALID_INDEX)
{
/* 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;
}
/**
* 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, addr_t const rcv_window = INVALID_INDEX)
{
using namespace Nova;
unsigned const rcv_items = (utcb.items >> 16) & 0xffffu;
_rcv_pt_sel_max = 0;
_rcv_pt_sel_cnt = 0;
unsigned short const max = 1U << utcb.crd_rcv.order();
if (max > MAX_CAP_ARGS)
nova_die();
for (unsigned short i = 0; i < MAX_CAP_ARGS; i++)
_rcv_pt_cap_free [i] = (i >= max) ? FREE_INVALID : FREE_SEL;
for (unsigned i = 0; i < rcv_items; i++) {
Nova::Utcb::Item * item = utcb.get_item(i);
if (!item)
break;
Nova::Crd cap(item->crd);
/* track which items we got mapped */
if (!cap.is_null() && item->is_del()) {
/* should never happen */
if (cap.base() < _rcv_pt_base ||
(cap.base() >= _rcv_pt_base + max))
nova_die();
_rcv_pt_cap_free [cap.base() - _rcv_pt_base] = UNUSED_CAP;
}
if (_rcv_pt_sel_max >= max) continue;
/* track the order of mapped and translated items */
if (cap.is_null()) {
_rcv_pt_sel[_rcv_pt_sel_max].sel = INVALID_INDEX;
_rcv_pt_sel[_rcv_pt_sel_max++].del = false;
} else {
_rcv_pt_sel[_rcv_pt_sel_max].sel = cap.base();
_rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del();
}
}
/*
* If a specific rcv_window has been specified,
* (see prepare_rcv_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 (rcv_window != INVALID_INDEX)
_rcv_pt_base = INVALID_INDEX;
utcb.crd_rcv = 0;
}
};
#endif /* _INCLUDE__NOVA__RECEIVE_WINDOW_H_ */

View File

@ -51,7 +51,7 @@ inline void request_event_portal(Genode::Native_capability const &cap,
utcb->crd_rcv = orig_crd;
if (res)
PERR("request of event (%lu) capability selector failed", event);
PERR("request of event (%lu) capability selector failed (res=%u)", event, res);
}

View File

@ -71,18 +71,29 @@ namespace Genode {
Signal wait_for_signal() override
{
/*
* Block on semaphore, will be unblocked if
* signal is available
*/
using namespace Nova;
mword_t value = 0;
mword_t count = 0;
if (uint8_t res = si_ctrl(_sem.local_name(), SEMAPHORE_DOWN,
value, count))
PWRN("signal reception failed - error %u", res);
return Signal(value, count);
mword_t imprint, count;
do {
/*
* We set an invalid imprint (0) to detect a spurious
* unblock. In this case, NOVA does not block
* SEMAPHORE_DOWN nor touch our input values if the
* deblocking (chained) semaphore was dequeued before we
* intend to block.
*/
imprint = 0;
count = 0;
/* block on semaphore until signal context was submitted */
if (uint8_t res = si_ctrl(_sem.local_name(), SEMAPHORE_DOWN,
imprint, count))
PWRN("signal reception failed - error %u", res);
} while (imprint == 0);
return Signal(imprint, count);
}
};
}

View File

@ -17,117 +17,9 @@
#include <base/printf.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <base/internal/ipc.h>
using namespace Genode;
using namespace Nova;
/*****************************
** IPC marshalling support **
*****************************/
void Ipc_marshaller::insert(Native_capability const &cap)
{
_snd_msg.snd_append_pt_sel(cap);
}
void Ipc_unmarshaller::extract(Native_capability &cap)
{
_rcv_msg.rcv_pt_sel(cap);
}
/***************
** Utilities **
***************/
/**
* Copy message registers from UTCB to destination message buffer
*
* \return protocol word delivered via the first UTCB message register
*
* The caller of this function must ensure that utcb->msg_words is greater
* than 0.
*/
static mword_t copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base &rcv_msg)
{
size_t num_msg_words = utcb->msg_words();
/*
* Handle the reception of a malformed message. This should never happen
* because the utcb->msg_words is checked by the caller of this function.
*/
if (num_msg_words < 1)
return 0;
/* the UTCB contains the protocol word followed by the message data */
mword_t const protocol_word = utcb->msg[0];
size_t num_data_words = num_msg_words - 1;
if (num_data_words*sizeof(mword_t) > rcv_msg.capacity()) {
PERR("receive message buffer too small msg size=%zx, buf size=%zd",
num_data_words*sizeof(mword_t), rcv_msg.capacity());
num_data_words = rcv_msg.capacity()/sizeof(mword_t);
}
/* read message payload into destination message buffer */
mword_t *src = (mword_t *)(void *)(&utcb->msg[1]);
mword_t *dst = (mword_t *)rcv_msg.data();
for (unsigned i = 0; i < num_data_words; i++)
*dst++ = *src++;
return protocol_word;
}
/**
* Copy message payload to UTCB message registers
*/
static bool copy_msgbuf_to_utcb(Nova::Utcb *utcb, Msgbuf_base const &snd_msg,
mword_t protocol_value)
{
/* look up address and size of message payload */
mword_t *msg_buf = (mword_t *)snd_msg.data();
/* size of message payload in machine words */
size_t const num_data_words = snd_msg.data_size()/sizeof(mword_t);
/* account for protocol value in front of the message */
size_t num_msg_words = 1 + num_data_words;
enum { NUM_MSG_REGS = 256 };
if (num_msg_words > NUM_MSG_REGS) {
PERR("Message does not fit into UTCB message registers\n");
num_msg_words = NUM_MSG_REGS;
}
utcb->msg[0] = protocol_value;
/* store message into UTCB message registers */
mword_t *src = (mword_t *)&msg_buf[0];
mword_t *dst = (mword_t *)(void *)&utcb->msg[1];
for (unsigned i = 0; i < num_data_words; i++)
*dst++ = *src++;
utcb->set_msg_word(num_msg_words);
/* append portal capability selectors */
for (unsigned i = 0; i < snd_msg.snd_pt_sel_cnt(); i++) {
bool trans_map = true;
Nova::Obj_crd crd = snd_msg.snd_pt_sel(i, trans_map);
if (crd.base() == ~0UL) continue;
if (!utcb->append_item(crd, i, false, false, trans_map))
return false;
}
return true;
}
/****************
@ -138,6 +30,9 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
Receive_window rcv_window;
rcv_msg.reset();
/* update receive window for capability selectors if needed */
if (rcv_caps != ~0UL) {
@ -145,10 +40,10 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
unsigned short log2_max = rcv_caps ? log2(rcv_caps) : 0;
if ((1U << log2_max) < rcv_caps) log2_max ++;
rcv_msg.rcv_wnd(log2_max);
rcv_window.rcv_wnd(log2_max);
}
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb();
/* the protocol value is unused as the badge is delivered by the kernel */
if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) {
@ -157,7 +52,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
}
/* if we can't setup receive window, die in order to recognize the issue */
if (!rcv_msg.prepare_rcv_window(utcb, dst.rcv_window()))
if (!rcv_window.prepare_rcv_window(utcb, dst.rcv_window()))
/* printf doesn't work here since for IPC also rcv_prepare* is used */
nova_die();
@ -165,67 +60,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
uint8_t res = Nova::call(dst.local_name());
if (res != Nova::NOVA_OK) {
/* If an error occurred, reset word&item count (not done by kernel). */
utcb->set_msg_word(0);
utcb.set_msg_word(0);
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
}
rcv_msg.post_ipc(utcb, dst.rcv_window());
rcv_window.post_ipc(utcb, dst.rcv_window());
/* handle malformed reply from a server */
if (utcb->msg_words() < 1)
if (utcb.msg_words() < 1)
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_msg));
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_window, rcv_msg));
}
/****************
** Ipc_server **
****************/
void Ipc_server::reply()
{
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
copy_msgbuf_to_utcb(utcb, _snd_msg, _exception_code.value);
_snd_msg.snd_reset();
Nova::reply(Thread_base::myself()->stack_top());
}
void Ipc_server::reply_wait()
{
/*
* This function is only called by the portal dispatcher of server
* entrypoint'. When the dispatcher is called, the incoming message already
* arrived so that we do not need to block. The only remaining thing to do
* is unmarshalling the arguments.
*/
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
_rcv_msg.post_ipc(utcb);
/* handle ill-formed message */
if (utcb->msg_words() < 2) {
_rcv_msg.word(0) = ~0UL; /* invalid opcode */
} else {
copy_utcb_to_msgbuf(utcb, _rcv_msg);
}
_read_offset = _write_offset = 0;
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _rcv_cs(cs)
{
_read_offset = _write_offset = 0;
}
Ipc_server::~Ipc_server() { }

View File

@ -20,11 +20,12 @@
/* base-internal includes */
#include <base/internal/stack.h>
#include <base/internal/ipc_server.h>
#include <base/internal/ipc.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
#include <nova/native_thread.h>
using namespace Genode;
@ -106,6 +107,14 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
}
static void reply(Nova::Utcb &utcb, Rpc_exception_code exc, Msgbuf_base &snd_msg)
{
copy_msgbuf_to_utcb(utcb, snd_msg, exc.value);
Nova::reply(Thread_base::myself()->stack_top());
}
void Rpc_entrypoint::_activation_entry()
{
/* retrieve portal id from eax/rdi */
@ -115,32 +124,38 @@ void Rpc_entrypoint::_activation_entry()
addr_t id_pt; asm volatile ("" : "=a" (id_pt));
#endif
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(Thread_base::myself());
Rpc_entrypoint &ep = *static_cast<Rpc_entrypoint *>(Thread_base::myself());
Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb();
/* required to decrease ref count of capability used during last reply */
ep->_snd_buf.snd_reset();
Receive_window &rcv_window = ep.native_thread().rcv_window;
rcv_window.post_ipc(utcb);
/* prepare ipc server object (copying utcb content to message buffer */
Rpc_opcode opcode(0);
Native_connection_state cs;
Ipc_server srv(cs, ep->_snd_buf, ep->_rcv_buf);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(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->_rcv_buf.prepare_rcv_window((Nova::Utcb *)ep->utcb()))
PWRN("out of capability selectors for handling server requests");
srv.reply();
/* handle ill-formed message */
if (utcb.msg_words() < 2) {
ep._rcv_buf.word(0) = ~0UL; /* invalid opcode */
} else {
copy_utcb_to_msgbuf(utcb, rcv_window, ep._rcv_buf);
}
Ipc_unmarshaller unmarshaller(ep._rcv_buf);
Rpc_opcode opcode(0);
unmarshaller.extract(opcode);
/* default return value */
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 (!rcv_window.prepare_rcv_window(utcb))
PWRN("out of capability selectors for handling server requests");
ep._rcv_buf.reset();
reply(utcb, exc, ep._snd_buf);
}
{
/* potentially delay start */
Lock::Guard lock_guard(ep->_delay_start);
Lock::Guard lock_guard(ep._delay_start);
}
/* atomically lookup and lock referenced object */
@ -151,16 +166,27 @@ void Rpc_entrypoint::_activation_entry()
return;
}
/*
* Inhibit removal of capabilities sent as results of client requests.
* This prevents the recursive revocation of NOVA portal caps and,
* therefore, permits clients to use result capabilities after server
* code dropped all references.
*/
for (unsigned i = 0; i < ep._snd_buf.used_caps(); ++i)
ep._snd_buf.cap(i).keep_if_last_reference();
/* dispatch request */
try { srv.ret(obj->dispatch(opcode, srv, srv)); }
ep._snd_buf.reset();
try { exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); }
catch (Blocking_canceled) { }
};
ep->apply(id_pt, lambda);
ep.apply(id_pt, lambda);
if (!ep->_rcv_buf.prepare_rcv_window((Nova::Utcb *)ep->utcb()))
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)ep.utcb()))
PWRN("out of capability selectors for handling server requests");
srv.reply();
ep._rcv_buf.reset();
reply(utcb, exc, ep._snd_buf);
}
@ -220,8 +246,10 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
if (!_cap.valid())
throw Cpu_session::Thread_creation_failed();
Receive_window &rcv_window = Thread_base::native_thread().rcv_window;
/* prepare portal receive window of new thread */
if (!_rcv_buf.prepare_rcv_window((Nova::Utcb *)&_stack->utcb()))
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb()))
throw Cpu_session::Thread_creation_failed();
if (start_on_construction)

View File

@ -33,6 +33,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
using namespace Genode;
using namespace Nova;

View File

@ -0,0 +1,123 @@
/*
* \brief IPC utility functions
* \author Norman Feske
* \date 2016-03-08
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__IPC_H_
#define _INCLUDE__BASE__INTERNAL__IPC_H_
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/native_thread.h>
/**
* Copy message registers from UTCB to destination message buffer
*
* \return protocol word delivered via the first UTCB message register
*
* The caller of this function must ensure that utcb.msg_words is greater
* than 0.
*/
static inline Nova::mword_t copy_utcb_to_msgbuf(Nova::Utcb &utcb,
Genode::Receive_window &rcv_window,
Genode::Msgbuf_base &rcv_msg)
{
using namespace Genode;
using namespace Nova;
size_t num_msg_words = utcb.msg_words();
/*
* Handle the reception of a malformed message. This should never happen
* because the utcb.msg_words is checked by the caller of this function.
*/
if (num_msg_words < 1)
return 0;
/* the UTCB contains the protocol word followed by the message data */
mword_t const protocol_word = utcb.msg[0];
size_t num_data_words = num_msg_words - 1;
if (num_data_words*sizeof(mword_t) > rcv_msg.capacity()) {
PERR("receive message buffer too small msg size=%zx, buf size=%zd",
num_data_words*sizeof(mword_t), rcv_msg.capacity());
num_data_words = rcv_msg.capacity()/sizeof(mword_t);
}
/* read message payload into destination message buffer */
mword_t *src = (mword_t *)(void *)(&utcb.msg[1]);
mword_t *dst = (mword_t *)rcv_msg.data();
for (unsigned i = 0; i < num_data_words; i++)
*dst++ = *src++;
/* extract caps from UTCB */
for (unsigned i = 0; i < rcv_window.num_received_caps(); i++) {
Native_capability cap;
rcv_window.rcv_pt_sel(cap);
rcv_msg.insert(cap);
}
return protocol_word;
}
/**
* Copy message payload to UTCB message registers
*/
static inline bool copy_msgbuf_to_utcb(Nova::Utcb &utcb,
Genode::Msgbuf_base const &snd_msg,
Nova::mword_t protocol_value)
{
using namespace Genode;
using namespace Nova;
/* look up address and size of message payload */
mword_t *msg_buf = (mword_t *)snd_msg.data();
/* size of message payload in machine words */
size_t const num_data_words = snd_msg.data_size()/sizeof(mword_t);
/* account for protocol value in front of the message */
size_t num_msg_words = 1 + num_data_words;
enum { NUM_MSG_REGS = 256 };
if (num_msg_words > NUM_MSG_REGS) {
PERR("Message does not fit into UTCB message registers\n");
num_msg_words = NUM_MSG_REGS;
}
utcb.msg[0] = protocol_value;
/* store message into UTCB message registers */
mword_t *src = (mword_t *)&msg_buf[0];
mword_t *dst = (mword_t *)(void *)&utcb.msg[1];
for (unsigned i = 0; i < num_data_words; i++)
*dst++ = *src++;
utcb.set_msg_word(num_msg_words);
/* append portal capability selectors */
for (unsigned i = 0; i < snd_msg.used_caps(); i++) {
Native_capability const &cap = snd_msg.cap(i);
Nova::Obj_crd crd(cap.local_name(), 0, cap.dst().rights());
if (crd.base() == ~0UL) continue;
if (!utcb.append_item(crd, i, false, false, true))
return false;
}
return true;
}
#endif /* _INCLUDE__BASE__INTERNAL__IPC_H_ */

View File

@ -161,6 +161,9 @@ void test_server_oom()
PINF("received %u. cap", i);
}
/* XXX this code does does no longer work since the removal of 'solely_map' */
#if 0
/* case that during send we get oom */
for (unsigned i = 0; i < 20000; i++) {
/* be evil and switch translation off - server ever uses a new selector */
@ -176,6 +179,7 @@ void test_server_oom()
if (i % 5000 == 4999)
PINF("sent %u. cap", i);
}
#endif
ep.dissolve(&component);
}

View File

@ -81,8 +81,13 @@ bool Test::Component::cap_void(Genode::Native_capability got_cap) {
Genode::Native_capability Test::Component::void_cap() {
Genode::Native_capability send_cap = cap();
/* XXX this code does does no longer work since the removal of 'solely_map' */
#if 0
/* be evil and switch translation off - client ever uses a new selector */
send_cap.solely_map();
#endif
return send_cap;
}

View File

@ -1,76 +0,0 @@
/*
* \brief OKL4-specific layout of IPC message buffer
* \author Norman Feske
* \date 2009-03-25
*
* On OKL4, we do not directly use the a kernel-specific message-buffer layout.
* The IPC goes through the UTCBs of the sending and receiving threads. Because
* on Genode, message buffers are decoupled from threads, we need to copy-in
* and copy-out the message payload between the message buffers and the used
* UTCBs.
*/
/*
* Copyright (C) 2009-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/stdint.h>
#include <base/printf.h>
namespace Genode {
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
class Msgbuf_base
{
protected:
size_t _data_size = 0;
size_t _capacity;
char _msg_start[]; /* symbol marks start of message */
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
friend class Ipc_marshaller;
public:
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
};
/**
* Instance of IPC message buffer with specified buffer size
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -7,7 +7,7 @@
LIBS += cxx startup
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc
SRC_CC += ipc/ipc.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
SRC_CC += allocator/allocator_avl.cc

View File

@ -53,7 +53,9 @@ static void kdb_emergency_print(const char *s)
* The message tag contains the information about the number of message words
* to send. The tag is always supplied in message register 0. Message register
* 1 is used for the local name (when the client calls the server) or the
* exception code (when the server replies to the client). All subsequent
* exception code (when the server replies to the client). Message register
* 2 holds the number of transferred capability arguments. It is followed
* by a tuple of (thread ID, local name) for each capability. All subsequent
* message registers hold the message payload.
*/
@ -64,43 +66,79 @@ static void kdb_emergency_print(const char *s)
*/
static L4_Word_t extract_msg_from_utcb(L4_MsgTag_t rcv_tag, Msgbuf_base &rcv_msg)
{
unsigned num_msg_words = (int)L4_UntypedWords(rcv_tag);
rcv_msg.reset();
if (num_msg_words*sizeof(L4_Word_t) > rcv_msg.capacity()) {
PERR("receive message buffer too small msg size=%zd, buf size=%zd",
num_msg_words*sizeof(L4_Word_t), rcv_msg.capacity());
num_msg_words = rcv_msg.capacity()/sizeof(L4_Word_t);
unsigned const num_msg_words = (int)L4_UntypedWords(rcv_tag);
if (num_msg_words < 3)
return Rpc_exception_code::INVALID_OBJECT;
L4_Word_t protocol_word = 0;
L4_StoreMR(1, &protocol_word);
L4_Word_t num_caps = 0;
L4_StoreMR(2, &num_caps);
/* each capability is represened as two message words (tid, local name) */
for (unsigned i = 0; i < num_caps; i++) {
L4_Word_t local_name = 0;
L4_ThreadId_t tid;
L4_StoreMR(3 + 2*i, &tid.raw);
L4_StoreMR(3 + 2*i + 1, &local_name);
rcv_msg.insert(Native_capability(tid, local_name));
}
L4_Word_t local_name = 0;
L4_StoreMR(1, &local_name);
unsigned const data_start_idx = 3 + 2*num_caps;
if (num_msg_words < data_start_idx)
return Rpc_exception_code::INVALID_OBJECT;
unsigned const num_data_words = num_msg_words - data_start_idx;
if (num_data_words*sizeof(L4_Word_t) > rcv_msg.capacity()) {
PERR("receive message buffer too small msg size=%zd, buf size=%zd",
num_data_words*sizeof(L4_Word_t), rcv_msg.capacity());
return Rpc_exception_code::INVALID_OBJECT;
}
/* read message payload into destination message buffer */
L4_StoreMRs(2, num_msg_words - 2, (L4_Word_t *)rcv_msg.data());
L4_StoreMRs(data_start_idx, num_data_words, (L4_Word_t *)rcv_msg.data());
return local_name;
rcv_msg.data_size(sizeof(num_data_words));
return protocol_word;
}
/**
* Copy message payload to UTCB message registers
*/
static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, unsigned num_msg_words,
L4_Word_t local_name)
static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, L4_Word_t local_name)
{
num_msg_words += 2;
unsigned const num_header_words = 3 + 2*snd_msg.used_caps();
unsigned const num_data_words = snd_msg.data_size()/sizeof(L4_Word_t);
unsigned const num_msg_words = num_data_words + num_header_words;
if (num_msg_words >= L4_GetMessageRegisters()) {
kdb_emergency_print("Message does not fit into UTCB message registers\n");
num_msg_words = L4_GetMessageRegisters() - 1;
L4_LoadMR(0, 0);
return;
}
L4_MsgTag_t snd_tag;
snd_tag.raw = 0;
snd_tag.X.u = num_msg_words;
L4_LoadMR (0, snd_tag.raw);
L4_LoadMR (1, local_name);
L4_LoadMRs(2, num_msg_words - 2, (L4_Word_t *)snd_msg.data());
L4_LoadMR(0, snd_tag.raw);
L4_LoadMR(1, local_name);
L4_LoadMR(2, snd_msg.used_caps());
for (unsigned i = 0; i < snd_msg.used_caps(); i++) {
L4_LoadMR(3 + i*2, snd_msg.cap(i).dst().raw);
L4_LoadMR(3 + i*2 + 1, snd_msg.cap(i).local_name());
}
L4_LoadMRs(num_header_words, num_data_words, (L4_Word_t *)snd_msg.data());
}
@ -113,8 +151,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
size_t)
{
/* copy call message to the UTCBs message registers */
copy_msg_to_utcb(snd_msg, snd_msg.data_size()/sizeof(L4_Word_t),
dst.local_name());
copy_msg_to_utcb(snd_msg, dst.local_name());
L4_Accept(L4_UntypedWordsAcceptor);
@ -136,54 +173,46 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
_reply_needed = true;
_read_offset = _write_offset = 0;
}
void Ipc_server::reply()
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
/* copy reply to the UTCBs message registers */
copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_exception_code.value);
copy_msg_to_utcb(snd_msg, exc.value);
/* perform non-blocking IPC send operation */
L4_MsgTag_t rcv_tag = L4_Reply(_caller.dst());
L4_MsgTag_t rcv_tag = L4_Reply(caller.dst());
if (L4_IpcFailed(rcv_tag))
PERR("ipc error in _reply - gets ignored");
_prepare_next_reply_wait();
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
L4_MsgTag_t rcv_tag;
if (_reply_needed) {
Okl4::L4_ThreadId_t caller = L4_nilthread;
if (last_caller.valid()) {
/* copy reply to the UTCBs message registers */
copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_exception_code.value);
copy_msg_to_utcb(reply_msg, exc.value);
rcv_tag = L4_ReplyWait(_caller.dst(), &_rcv_cs.caller);
rcv_tag = L4_ReplyWait(last_caller.dst(), &caller);
} else {
rcv_tag = L4_Wait(&_rcv_cs.caller);
rcv_tag = L4_Wait(&caller);
}
/* copy request message from the UTCBs message registers */
_badge = extract_msg_from_utcb(rcv_tag, _rcv_msg);
unsigned long const badge = extract_msg_from_utcb(rcv_tag, request_msg);
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_prepare_next_reply_wait();
return Rpc_request(Native_capability(caller, 0), badge);
}
@ -202,14 +231,7 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
:
Ipc_marshaller(snd_msg),
Ipc_unmarshaller(rcv_msg),
Native_capability(thread_get_my_global_id(), 0),
_rcv_cs(cs)
{ }
Ipc_server::Ipc_server() : Native_capability(thread_get_my_global_id(), 0) { }
Ipc_server::~Ipc_server() { }

View File

@ -0,0 +1,50 @@
/*
* \brief Kernel-specific RM-faulter wake-up mechanism
* \author Norman Feske
* \date 2016-04-12
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <pager.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
#include <l4/message.h>
#include <l4/ipc.h>
} }
using namespace Genode;
void Pager_object::wake_up()
{
using namespace Okl4;
/*
* Issue IPC to pager, transmitting the pager-object pointer as 'IP'.
*/
L4_Accept(L4_UntypedWordsAcceptor);
L4_MsgTag_t snd_tag;
snd_tag.raw = 0;
snd_tag.X.u = 2;
L4_LoadMR(0, snd_tag.raw);
L4_LoadMR(1, 0); /* fault address */
L4_LoadMR(2, (unsigned long)this); /* instruction pointer */
L4_Call(cap().dst());
}
void Pager_object::unresolved_page_fault_occurred()
{
state.unresolved_page_fault = true;
}

View File

@ -62,7 +62,6 @@ vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core
vpath core_printf.cc $(BASE_DIR)/src/base/console

View File

@ -1,27 +0,0 @@
/*
* \brief Connection state
* \author Norman Feske
* \date 2016-03-11
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#include <base/stdint.h>
namespace Genode { struct Native_connection_state; }
struct Genode::Native_connection_state
{
Okl4::L4_ThreadId_t caller;
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */

View File

@ -1,74 +0,0 @@
/*
* \brief Pistachio-specific layout of IPC message buffer
* \author Julian Stecklina
* \date 2007-01-10
*/
/*
* Copyright (C) 2007-2013 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
namespace Genode {
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
class Msgbuf_base
{
protected:
friend class Ipc_marshaller;
size_t const _capacity;
size_t _data_size = 0;
char _msg_start[]; /* symbol marks start of message */
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
public:
/*
* Begin of message buffer layout
*/
Pistachio::L4_Fpage_t rcv_fpage;
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
};
/**
* Instance of IPC message buffer with specified buffer size
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -7,7 +7,7 @@
LIBS += cxx startup syscall
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc
SRC_CC += ipc/ipc.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
SRC_CC += allocator/allocator_avl.cc

View File

@ -68,19 +68,62 @@ static inline void check_ipc_result(L4_MsgTag_t result, L4_Word_t error_code)
throw Genode::Ipc_error();
}
if (L4_UntypedWords(result) != 1) {
PERR("Error in thread %08lx. Expected one untyped word (local_name), but got %lu.\n",
if (L4_UntypedWords(result) < 2) {
PERR("Error in thread %08lx. Expected at leat two untyped words, but got %lu.\n",
L4_Myself().raw, L4_UntypedWords(result));
throw Genode::Ipc_error();
}
}
PERR("This should not happen. Inspect!");
throw Genode::Ipc_error();
/**
* Configure L4 receive buffer according to Genode receive buffer
*/
static void extract_caps(L4_Msg_t &msg, Msgbuf_base &rcv_msg)
{
using namespace Pistachio;
L4_Word_t const num_caps = min((unsigned)Msgbuf_base::MAX_CAPS_PER_MSG,
L4_Get(&msg, 1));
for (unsigned i = 0; i < num_caps; i++) {
L4_ThreadId_t tid;
tid.raw = L4_Get(&msg, 2 + i*2);
L4_Word_t const local_name = L4_Get(&msg, 2 + i*2 + 1);
rcv_msg.insert(Native_capability(tid, local_name));
}
if (L4_TypedWords(result) != 2) {
PERR("Error. Expected two typed words (a string item). but got %lu.\n",
L4_TypedWords(result));
PERR("This should not happen. Inspect!");
throw Genode::Ipc_error();
}
/**
* Configure L4 message descriptor according to Genode send buffer
*/
static void prepare_send(L4_Word_t protocol_value, L4_Msg_t &msg,
Msgbuf_base &snd_msg)
{
L4_Clear(&msg);
L4_Append(&msg, protocol_value);
L4_Append(&msg, (L4_Word_t)snd_msg.used_caps());
for (unsigned i = 0; i < snd_msg.used_caps(); i++) {
L4_Append(&msg, (L4_Word_t)snd_msg.cap(i).dst().raw);
L4_Append(&msg, (L4_Word_t)snd_msg.cap(i).local_name());
}
L4_Append(&msg, L4_StringItem(snd_msg.data_size(), snd_msg.data()));
L4_Load(&msg);
}
static void prepare_receive(L4_MsgBuffer_t &l4_msgbuf, Msgbuf_base &rcv_msg)
{
L4_Clear(&l4_msgbuf);
L4_Append(&l4_msgbuf, L4_StringItem(rcv_msg.capacity(), rcv_msg.data()));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &l4_msgbuf);
}
@ -92,23 +135,13 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
{
L4_Msg_t msg;
L4_StringItem_t sitem = L4_StringItem(snd_msg.data_size(), snd_msg.data());
L4_Word_t const local_name = dst.local_name();
/* prepare receive message buffer */
L4_MsgBuffer_t msgbuf;
/* prepare message buffer */
L4_Clear (&msgbuf);
L4_Append (&msgbuf, L4_StringItem (rcv_msg.capacity(), rcv_msg.data()));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &msgbuf);
prepare_receive(msgbuf, rcv_msg);
/* prepare sending parameters */
L4_Clear(&msg);
L4_Append(&msg, local_name);
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_Msg_t msg;
prepare_send(dst.local_name(), msg, snd_msg);
L4_MsgTag_t result = L4_Call(dst.dst());
@ -117,67 +150,56 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
check_ipc_result(result, L4_ErrorCode());
extract_caps(msg, rcv_msg);
return Rpc_exception_code(L4_Get(&msg, 0));
}
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
_reply_needed = true;
_read_offset = _write_offset = 0;
}
void Ipc_server::reply()
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
L4_Msg_t msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data());
L4_Word_t const local_name = _caller.local_name();
prepare_send(exc.value, msg, snd_msg);
L4_Clear(&msg);
L4_Append(&msg, local_name);
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_MsgTag_t result = L4_Reply(_caller.dst());
L4_MsgTag_t result = L4_Reply(caller.dst());
if (L4_IpcFailed(result))
PERR("ipc error in _reply, ignored");
_prepare_next_reply_wait();
snd_msg.reset();
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
bool need_to_wait = true;
L4_MsgTag_t request_tag;
/* prepare request message buffer */
L4_MsgBuffer_t request_msgbuf;
L4_Clear(&request_msgbuf);
L4_Append(&request_msgbuf, L4_StringItem (_rcv_msg.capacity(), _rcv_msg.data()));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &request_msgbuf);
request_msg.reset();
if (_reply_needed) {
/* prepare receive buffer for request */
L4_MsgBuffer_t request_msgbuf;
prepare_receive(request_msgbuf, request_msg);
L4_ThreadId_t caller = L4_nilthread;
if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT) {
/* prepare reply massage */
L4_Msg_t reply_msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data());
L4_Clear(&reply_msg);
L4_Append(&reply_msg, (L4_Word_t)_exception_code.value);
L4_Append(&reply_msg, sitem);
L4_Load(&reply_msg);
L4_Msg_t reply_l4_msg;
prepare_send(exc.value, reply_l4_msg, reply_msg);
/* send reply and wait for new request message */
request_tag = L4_Ipc(_caller.dst(), L4_anythread,
L4_Timeouts(L4_ZeroTime, L4_Never), &_rcv_cs.caller);
request_tag = L4_Ipc(last_caller.dst(), L4_anythread,
L4_Timeouts(L4_ZeroTime, L4_Never), &caller);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
@ -186,7 +208,7 @@ void Ipc_server::reply_wait()
while (need_to_wait) {
/* wait for new request message */
request_tag = L4_Wait(&_rcv_cs.caller);
request_tag = L4_Wait(&caller);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
@ -196,26 +218,14 @@ void Ipc_server::reply_wait()
L4_Msg_t msg;
L4_Clear(&msg);
L4_Store(request_tag, &msg);
extract_caps(msg, request_msg);
/* remember badge of invoked object */
_badge = L4_Get(&msg, 0);
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_prepare_next_reply_wait();
unsigned long const badge = L4_Get(&msg, 0);
return Rpc_request(Native_capability(caller, 0), badge);
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Pistachio::L4_Myself(), 0),
_rcv_cs(cs)
{
_read_offset = _write_offset = 0;
}
Ipc_server::Ipc_server() : Native_capability(Pistachio::L4_Myself(), 0) { }
Ipc_server::~Ipc_server() { }

View File

@ -132,10 +132,7 @@ void Ipc_pager::reply_and_wait_for_fault()
void Ipc_pager::acknowledge_wakeup()
{
PERR("acknowledge_wakeup called, not yet implemented");
// /* answer wakeup call from one of core's region-manager sessions */
// l4_msgdope_t result;
// l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
L4_Reply(_last);
}

View File

@ -0,0 +1,50 @@
/*
* \brief Kernel-specific RM-faulter wake-up mechanism
* \author Norman Feske
* \date 2016-04-12
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <pager.h>
/* Pistachio includes */
namespace Pistachio {
#include <l4/types.h>
#include <l4/ipc.h>
}
using namespace Genode;
void Pager_object::wake_up()
{
using namespace Pistachio;
/*
* Issue IPC to pager, transmitting the pager-object pointer as 'IP'.
*/
L4_Accept(L4_UntypedWordsAcceptor);
L4_MsgTag_t snd_tag;
snd_tag.raw = 0;
snd_tag.X.u = 2;
L4_LoadMR(0, snd_tag.raw);
L4_LoadMR(1, 0); /* fault address */
L4_LoadMR(2, (unsigned long)this); /* instruction pointer */
L4_Call(cap().dst());
}
void Pager_object::unresolved_page_fault_occurred()
{
state.unresolved_page_fault = true;
}

View File

@ -61,7 +61,6 @@ vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath kip.cc $(REP_DIR)/src/base/kip
vpath %.cc $(REP_DIR)/src/core

View File

@ -1,30 +0,0 @@
/*
* \brief Connection state
* \author Norman Feske
* \date 2016-03-11
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
/* Pistachio includes */
namespace Pistachio {
#include <l4/types.h>
}
namespace Genode { struct Native_connection_state; }
struct Genode::Native_connection_state
{
Pistachio::L4_ThreadId_t caller;
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */

View File

@ -1,150 +0,0 @@
/*
* \brief IPC message buffer layout
* \author Norman Feske
* \date 2015-05-10
*/
/*
* 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/native_types.h>
namespace Genode {
class Msgbuf_base;
template <unsigned> struct Msgbuf;
class Ipc_marshaller;
}
class Genode::Msgbuf_base
{
public:
enum { MAX_CAPS_PER_MSG = 3 };
protected:
friend class Ipc_marshaller;
/*
* Resolve ambiguity if the header is included from a libc-using
* program.
*/
typedef Genode::size_t size_t;
/*
* Capabilities to be transferred
*/
Native_capability _caps[MAX_CAPS_PER_MSG];
size_t _used_caps = 0;
size_t _read_cap_index = 0;
/**
* Maximum size of plain-data message payload
*/
size_t const _capacity;
/**
* Actual size of plain-data message payload
*/
size_t _data_size = 0;
char _msg_start[]; /* symbol marks start of message buffer data */
/*
* No member variables are allowed beyond this point!
*/
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
public:
char buf[];
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; };
void reset_caps()
{
for (Genode::size_t i = 0; i < _used_caps; i++)
_caps[i] = Native_capability();
_used_caps = 0;
}
void reset_read_cap_index()
{
_read_cap_index = 0;
}
/**
* Return pointer to start of message-buffer content
*/
void const *data() const { return &_msg_start[0]; };
void *data() { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
/**
* Exception type
*/
class Too_many_caps : public Exception { };
/**
* Called from '_marshal_capability'
*/
void append_cap(Native_capability const &cap)
{
if (_used_caps == MAX_CAPS_PER_MSG)
throw Too_many_caps();
_caps[_used_caps++] = cap;
}
/**
* Called from '_unmarshal_capability'
*/
Native_capability extract_cap()
{
if (_read_cap_index == _used_caps)
return Native_capability();
return _caps[_read_cap_index++];
}
/**
* Return number of marshalled capabilities
*/
size_t used_caps() const { return _used_caps; }
Native_capability &cap(unsigned index) { return _caps[index]; }
Native_capability const &cap(unsigned index) const { return _caps[index]; }
};
template <unsigned BUF_SIZE>
struct Genode::Msgbuf : Msgbuf_base
{
/**
* Pump up IPC message buffer to specified buffer size
*
* XXX remove padding of 16
*/
char buf[BUF_SIZE + 16];
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -63,11 +63,9 @@ static unsigned &rcv_sel()
/**
* Convert Genode::Msgbuf_base content into seL4 message
*
* \param msg source message buffer
* \param data_length size of message data in bytes
* \param msg source message buffer
*/
static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg,
size_t const data_length)
static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg)
{
/*
* Supply capabilities to kernel IPC message
@ -107,7 +105,7 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg,
* Supply data payload
*/
size_t const num_data_mwords =
align_natural(data_length) / sizeof(umword_t);
align_natural(msg.data_size()) / sizeof(umword_t);
umword_t const *src = (umword_t const *)msg.data();
for (size_t i = 0; i < num_data_mwords; i++)
@ -129,7 +127,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
/*
* Extract Genode capabilities from seL4 IPC message
*/
dst_msg.reset_caps();
dst_msg.reset();
size_t const num_caps = seL4_GetMR(MR_IDX_NUM_CAPS);
size_t curr_sel4_cap_idx = 0;
@ -153,7 +151,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* Hence it is meaningless as a key.
*/
if (!rpc_obj_key.valid() && seL4_MessageInfo_get_extraCaps(msg_info) == 0) {
dst_msg.append_cap(Native_capability());
dst_msg.insert(Native_capability());
continue;
}
@ -185,7 +183,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
Native_capability arg_cap = Capability_space::lookup(rpc_obj_key);
dst_msg.append_cap(arg_cap);
dst_msg.insert(arg_cap);
} else {
@ -224,14 +222,14 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
Capability_space::reset_sel(rcv_sel());
dst_msg.append_cap(arg_cap);
dst_msg.insert(arg_cap);
} else {
Capability_space::Ipc_cap_data const
ipc_cap_data(rpc_obj_key, rcv_sel());
dst_msg.append_cap(Capability_space::import(ipc_cap_data));
dst_msg.insert(Capability_space::import(ipc_cap_data));
/*
* Since we keep using the received selector, we need to
@ -247,25 +245,21 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* Extract message data payload
*/
size_t const num_msg_words = seL4_MessageInfo_get_length(msg_info);
/* detect malformed message with too small header */
if (num_msg_words < MR_IDX_DATA)
return;
/* copy data payload */
size_t const max_words = dst_msg.capacity()/sizeof(umword_t);
size_t const num_data_words = min(num_msg_words - MR_IDX_DATA, max_words);
umword_t *dst = (umword_t *)dst_msg.data();
for (size_t i = 0; i < seL4_MessageInfo_get_length(msg_info); i++)
for (size_t i = 0; i < num_data_words; i++)
*dst++ = seL4_GetMR(MR_IDX_DATA + i);
}
/*****************************
** IPC marshalling support **
*****************************/
void Ipc_marshaller::insert(Native_capability const &cap)
{
_snd_msg.append_cap(cap);
}
void Ipc_unmarshaller::extract(Native_capability &cap)
{
cap = _rcv_msg.extract_cap();
dst_msg.data_size(num_data_words*sizeof(umword_t));
}
@ -285,8 +279,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
if (!rcv_sel())
rcv_sel() = Capability_space::alloc_rcv_sel();
seL4_MessageInfo_t const request_msg_info =
new_seL4_message(snd_msg, snd_msg.data_size());
seL4_MessageInfo_t const request_msg_info = new_seL4_message(snd_msg);
unsigned const dst_sel = Capability_space::ipc_cap_data(dst).sel.value();
@ -300,55 +293,51 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
/****************
** Ipc_server **
** IPC server **
****************/
void Ipc_server::reply()
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
ASSERT(false);
}
void Ipc_server::reply_wait()
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
if (!_reply_needed) {
seL4_Word badge = 0;
seL4_MessageInfo_t const msg_info =
seL4_Recv(Thread_base::myself()->native_thread().ep_sel,
(seL4_Word *)&_badge);
if (exc.value == Rpc_exception_code::INVALID_OBJECT) {
decode_seL4_message(msg_info, _rcv_msg);
seL4_MessageInfo_t const request_msg_info =
seL4_Recv(Thread_base::myself()->native_thread().ep_sel, &badge);
decode_seL4_message(request_msg_info, request_msg);
} else {
seL4_MessageInfo_t const reply_msg_info =
new_seL4_message(_snd_msg, _write_offset);
seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg);
seL4_SetMR(MR_IDX_EXC_CODE, _exception_code.value);
seL4_SetMR(MR_IDX_EXC_CODE, exc.value);
seL4_MessageInfo_t const request_msg_info =
seL4_ReplyRecv(Thread_base::myself()->native_thread().ep_sel,
reply_msg_info, (seL4_Word *)&_badge);
reply_msg_info, &badge);
decode_seL4_message(request_msg_info, _rcv_msg);
decode_seL4_message(request_msg_info, request_msg);
}
_reply_needed = true;
_read_offset = _write_offset = 0;
_rcv_msg.reset_read_cap_index();
_snd_msg.reset_caps();
return Rpc_request(Native_capability(), badge);
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
Ipc_server::Ipc_server()
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _rcv_cs(cs)
{
*static_cast<Native_capability *>(this) =
Native_capability(Capability_space::create_ep_cap(*Thread_base::myself()));
}
Native_capability(Capability_space::create_ep_cap(*Thread_base::myself()))
{ }
Ipc_server::~Ipc_server() { }

View File

@ -1,89 +0,0 @@
/*
* \brief Default version of platform-specific part of server framework
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2006-05-12
*
* This version is suitable for platforms similar to L4. Each platform
* for which this implementation is not suited contains a platform-
* specific version in its respective 'base-<platform>' repository.
*/
/*
* Copyright (C) 2006-2013 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.
*/
/* Genode includes */
#include <base/rpc_server.h>
/* base-internal includes */
#include <base/internal/capability_space_sel4.h>
#include <base/internal/ipc_server.h>
using namespace Genode;
/***********************
** Server entrypoint **
***********************/
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap);
/* add server object to object pool */
obj->cap(new_obj_cap);
insert(obj);
/* return capability that uses the object id as badge */
return new_obj_cap;
}
void Rpc_entrypoint::entry()
{
Native_connection_state cs;
Ipc_server srv(cs, _snd_buf, _rcv_buf);
_ipc_server = &srv;
_cap = srv;
_cap_valid.unlock();
/*
* Now, the capability of the server activation is initialized
* an can be passed around. However, the processing of capability
* invocations should not happen until activation-using server
* is completely initialized. Thus, we wait until the activation
* gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'.
*/
_delay_start.lock();
while (!_exit_handler.exit) {
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
/* atomically lookup and lock referenced object */
auto lambda = [&] (Rpc_object_base *obj) {
if (!obj) return;
/* dispatch request */
try { srv.ret(obj->dispatch(opcode, srv, srv)); }
catch (Blocking_canceled) { }
};
apply(srv.badge(), lambda);
}
/* answer exit call, thereby wake up '~Rpc_entrypoint' */
srv.reply();
/* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */
_delay_exit.lock();
}

View File

@ -25,8 +25,8 @@ namespace Genode {
/**
* Forward declaration needed for internal interfaces of 'Capability'
*/
class Ipc_marshaller;
class Ipc_unmarshaller;
class Msgbuf_base;
/**
@ -58,9 +58,9 @@ class Genode::Capability : public Untyped_capability
* Insert RPC arguments into the message buffer
*/
template <typename ATL>
void _marshal_args(Ipc_marshaller &, ATL &args) const;
void _marshal_args(Msgbuf_base &, ATL &args) const;
void _marshal_args(Ipc_marshaller &, Meta::Empty &) const { }
void _marshal_args(Msgbuf_base &, Meta::Empty &) const { }
/**
* Unmarshal single RPC argument from the message buffer

View File

@ -14,19 +14,14 @@
#ifndef _INCLUDE__BASE__IPC_H_
#define _INCLUDE__BASE__IPC_H_
#include <util/misc_math.h>
#include <util/string.h>
#include <util/noncopyable.h>
#include <base/exception.h>
#include <base/capability.h>
#include <base/ipc_msgbuf.h>
#include <base/rpc_args.h>
#include <base/printf.h>
namespace Genode {
class Ipc_error;
class Ipc_marshaller;
struct Ipc_error : Exception { };
class Ipc_unmarshaller;
/**
@ -46,84 +41,6 @@ namespace Genode {
}
/**
* Exception type
*/
class Genode::Ipc_error : public Exception { };
/**
* Marshal arguments into send message buffer
*/
class Genode::Ipc_marshaller : Noncopyable
{
protected:
Msgbuf_base &_snd_msg;
size_t &_write_offset = _snd_msg._data_size;
private:
char *_snd_buf = (char *)_snd_msg.data();
size_t const _snd_buf_size = _snd_msg.capacity();
public:
/**
* Write value to send buffer
*/
template <typename T>
void insert(T const &value)
{
/* check buffer range */
if (_write_offset + sizeof(T) >= _snd_buf_size) return;
/* write integer to buffer */
*reinterpret_cast<T *>(&_snd_buf[_write_offset]) = value;
/* increment write pointer to next dword-aligned value */
_write_offset += align_natural(sizeof(T));
}
template <size_t MAX_BUFFER_SIZE>
void insert(Rpc_in_buffer<MAX_BUFFER_SIZE> const &b)
{
size_t const size = b.size();
insert(size);
insert(b.base(), size);
}
/**
* Write bytes to send buffer
*/
void insert(char const *src_addr, unsigned num_bytes)
{
/* check buffer range */
if (_write_offset + num_bytes >= _snd_buf_size) return;
/* copy buffer */
memcpy(&_snd_buf[_write_offset], src_addr, num_bytes);
/* increment write pointer to next dword-aligned value */
_write_offset += align_natural(num_bytes);
}
/**
* Insert capability to message buffer
*/
void insert(Native_capability const &cap);
template <typename IT>
void insert(Capability<IT> const &typed_cap)
{
Native_capability untyped_cap = typed_cap;
insert(untyped_cap);
}
Ipc_marshaller(Msgbuf_base &snd_msg) : _snd_msg(snd_msg) { }
};
/**
* Unmarshal arguments from receive buffer
*/
@ -131,8 +48,9 @@ class Genode::Ipc_unmarshaller : Noncopyable
{
protected:
Msgbuf_base &_rcv_msg;
unsigned _read_offset = 0;
Msgbuf_base &_rcv_msg;
unsigned _read_offset = 0;
unsigned _read_cap_index = 0;
private:
@ -141,6 +59,9 @@ class Genode::Ipc_unmarshaller : Noncopyable
public:
/**
* Obtain typed capability from message buffer
*/
template <typename IT>
void extract(Capability<IT> &typed_cap)
{
@ -149,6 +70,16 @@ class Genode::Ipc_unmarshaller : Noncopyable
typed_cap = reinterpret_cap_cast<IT>(untyped_cap);
}
/**
* Obtain capability from message buffer
*/
void extract(Native_capability &cap)
{
cap = _read_cap_index < _rcv_msg.used_caps()
? _rcv_msg.cap(_read_cap_index) : Native_capability();
_read_cap_index++;
}
/**
* Read 'Rpc_in_buffer' from receive buffer
*/
@ -165,7 +96,7 @@ class Genode::Ipc_unmarshaller : Noncopyable
* Note: The addr of the Rpc_in_buffer_base is a null pointer when this
* condition triggers.
*/
if (_read_offset + size >= _rcv_buf_size) {
if (_read_offset + size > _rcv_buf_size) {
PERR("message buffer overrun");
return;
}
@ -174,11 +105,6 @@ class Genode::Ipc_unmarshaller : Noncopyable
_read_offset += align_natural(size);
}
/**
* Obtain capability from message buffer
*/
void extract(Native_capability &cap);
/**
* Read value of type T from buffer
*/
@ -186,7 +112,7 @@ class Genode::Ipc_unmarshaller : Noncopyable
void extract(T &value)
{
/* check receive buffer range */
if (_read_offset + sizeof(T) >= _rcv_buf_size) return;
if (_read_offset + sizeof(T) > _rcv_buf_size) return;
/* return value from receive buffer */
value = *reinterpret_cast<T *>(&_rcv_buf[_read_offset]);
@ -195,8 +121,6 @@ class Genode::Ipc_unmarshaller : Noncopyable
_read_offset += align_natural(sizeof(T));
}
public:
Ipc_unmarshaller(Msgbuf_base &rcv_msg) : _rcv_msg(rcv_msg) { }
};

View File

@ -0,0 +1,244 @@
/*
* \brief IPC message buffer layout
* \author Norman Feske
* \date 2015-05-10
*/
/*
* 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.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <util/noncopyable.h>
#include <base/native_types.h>
#include <base/capability.h>
#include <base/exception.h>
#include <base/rpc_args.h>
namespace Genode {
class Msgbuf_base;
template <unsigned> class Msgbuf;
}
class Genode::Msgbuf_base : Noncopyable
{
public:
enum { MAX_CAPS_PER_MSG = 4 };
private:
/*
* Resolve ambiguity if the header is included from a libc-using
* program.
*/
typedef Genode::size_t size_t;
/*
* Capabilities to be transferred
*/
Native_capability _caps[MAX_CAPS_PER_MSG];
/**
* Number of marshalled capabilities
*/
size_t _used_caps = 0;
/**
* Pointer to buffer for data payload
*/
char * const _data;
/**
* Maximum size of plain-data message payload
*/
size_t const _capacity;
/**
* Actual size of plain-data message payload
*/
size_t _data_size = 0;
char *_data_last() { return &_data[_data_size]; }
void _clear(size_t const num_bytes)
{
size_t const num_words = min(num_bytes, _capacity)/sizeof(long);
for (unsigned i = 0; i < num_words; i++)
word(i) = 0;
}
protected:
struct Headroom { long space[16]; };
Msgbuf_base(char *buf, size_t capacity)
:
_data(buf), _capacity(capacity)
{
_clear(capacity);
}
public:
/**
* Return reference to platform-specific header in front of the message
*/
template <typename T>
T &header()
{
static_assert(sizeof(T) <= sizeof(Headroom),
"Header size exceeds message headroom");
return *reinterpret_cast<T *>(_data - sizeof(T));
}
/**
* Return reference to the message word at the specified index
*/
unsigned long &word(unsigned i)
{
return reinterpret_cast<unsigned long *>(_data)[i];
}
/**
* Return size of message buffer
*/
size_t capacity() const { return _capacity; }
/**
* Reset message buffer
*
* This function is used at the server side for reusing the same
* message buffer for subsequent requests.
*/
void reset()
{
for (Genode::size_t i = 0; i < _used_caps; i++)
_caps[i] = Native_capability();
_clear(_data_size);
_used_caps = 0;
_data_size = 0;
}
/**
* Return pointer to start of message-buffer content
*/
void const *data() const { return _data; }
void *data() { return _data; }
/**
* Return size of marshalled data payload in bytes
*/
size_t data_size() const { return _data_size; }
void data_size(size_t data_size) { _data_size = data_size; }
/**
* Exception type
*/
class Too_many_caps : public Exception { };
/**
* Return number of marshalled capabilities
*/
size_t used_caps() const { return _used_caps; }
void used_caps(size_t used_caps) { _used_caps = used_caps; }
Native_capability &cap(unsigned i) { return _caps[i]; }
Native_capability const &cap(unsigned i) const { return _caps[i]; }
/**
* Append value to message buffer
*/
template <typename T>
void insert(T const &value)
{
/* check buffer range */
if (_data_size + sizeof(T) > _capacity) return;
/* write value to buffer */
*reinterpret_cast<T *>(_data_last()) = value;
/* increment write pointer to next dword-aligned value */
_data_size += align_natural(sizeof(T));
}
/**
* Insert content of 'Rpc_in_buffer' into message buffer
*/
template <size_t MAX_BUFFER_SIZE>
void insert(Rpc_in_buffer<MAX_BUFFER_SIZE> const &b)
{
size_t const size = b.size();
insert(size);
insert(b.base(), size);
}
/**
* Write bytes to message buffer
*/
void insert(char const *src_addr, unsigned num_bytes)
{
/* check buffer range */
if (_data_size + num_bytes > _capacity) return;
/* copy buffer */
memcpy(_data_last(), src_addr, num_bytes);
/* increment write pointer to next dword-aligned value */
_data_size += align_natural(num_bytes);
}
/**
* Insert capability to message buffer
*/
void insert(Native_capability const &cap)
{
if (_used_caps == MAX_CAPS_PER_MSG)
throw Too_many_caps();
_caps[_used_caps++] = cap;
}
/**
* Insert typed capability into message buffer
*/
template <typename IT>
void insert(Capability<IT> const &typed_cap)
{
Native_capability untyped_cap = typed_cap;
insert(untyped_cap);
}
};
template <unsigned BUF_SIZE>
struct Genode::Msgbuf : Msgbuf_base
{
/**
* Headroom in front of the actual message payload
*
* This space is used on some platforms to prepend the message with a
* protocol header.
*/
Headroom headroom;
/**
* Buffer for data payload
*/
char buf[BUF_SIZE];
Msgbuf() : Msgbuf_base(buf, BUF_SIZE) { }
};
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -58,12 +58,12 @@ namespace Genode {
template <typename RPC_INTERFACE>
template <typename ATL>
void Capability<RPC_INTERFACE>::
_marshal_args(Ipc_marshaller &marshaller, ATL &args) const
_marshal_args(Msgbuf_base &msg, ATL &args) const
{
if (Trait::Rpc_direction<typename ATL::Head>::Type::IN)
marshaller.insert(args.get());
msg.insert(args.get());
_marshal_args(marshaller, args._2);
_marshal_args(msg, args._2);
}
@ -129,9 +129,8 @@ namespace Genode {
Rpc_opcode opcode(static_cast<int>(Meta::Index_of<Rpc_functions, IF>::Value));
/* marshal opcode and RPC input arguments */
Ipc_marshaller marshaller(call_buf);
marshaller.insert(opcode);
_marshal_args(marshaller, args);
call_buf.insert(opcode);
_marshal_args(call_buf, args);
{
Trace::Rpc_call trace_event(IF::name(), call_buf);

View File

@ -74,7 +74,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
void _read_args(Ipc_unmarshaller &, Meta::Empty) { }
template <typename ARG_LIST>
void _write_results(Ipc_marshaller &msg, ARG_LIST &args)
void _write_results(Msgbuf_base &msg, ARG_LIST &args)
{
if (Trait::Rpc_direction<typename ARG_LIST::Head>::Type::OUT)
msg.insert(args._1);
@ -82,7 +82,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
_write_results(msg, args._2);
}
void _write_results(Ipc_marshaller &, Meta::Empty) { }
void _write_results(Msgbuf_base &, Meta::Empty) { }
template <typename RPC_FUNCTION, typename EXC_TL>
Rpc_exception_code _do_serve(typename RPC_FUNCTION::Server_args &args,
@ -111,7 +111,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
template <typename RPC_FUNCTIONS_TO_CHECK>
Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &in, Ipc_marshaller &out,
Ipc_unmarshaller &in, Msgbuf_base &out,
Meta::Overload_selector<RPC_FUNCTIONS_TO_CHECK>)
{
using namespace Meta;
@ -158,7 +158,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
}
Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &, Ipc_marshaller &,
Ipc_unmarshaller &, Msgbuf_base &,
Meta::Overload_selector<Meta::Empty>)
{
PERR("invalid opcode %ld\n", opcode.value);
@ -169,7 +169,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
* Handle corner case of having an RPC interface with no RPC functions
*/
Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &, Ipc_marshaller &,
Ipc_unmarshaller &, Msgbuf_base &,
Meta::Overload_selector<Meta::Type_list<> >)
{
return Rpc_exception_code(Rpc_exception_code::SUCCESS);
@ -185,7 +185,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
public:
Rpc_exception_code dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &in, Ipc_marshaller &out)
Ipc_unmarshaller &in, Msgbuf_base &out)
{
return _do_dispatch(opcode, in, out,
Meta::Overload_selector<Rpc_functions>());
@ -207,7 +207,7 @@ class Genode::Rpc_object_base : public Object_pool<Rpc_object_base>::Entry
* \param out outgoing message for storing method results
*/
virtual Rpc_exception_code
dispatch(Rpc_opcode op, Ipc_unmarshaller &in, Ipc_marshaller &out) = 0;
dispatch(Rpc_opcode op, Ipc_unmarshaller &in, Msgbuf_base &out) = 0;
};
@ -225,7 +225,7 @@ struct Genode::Rpc_object : Rpc_object_base, Rpc_dispatcher<RPC_INTERFACE, SERVE
** Server-object interface **
*****************************/
Rpc_exception_code dispatch(Rpc_opcode opcode, Ipc_unmarshaller &in, Ipc_marshaller &out)
Rpc_exception_code dispatch(Rpc_opcode opcode, Ipc_unmarshaller &in, Msgbuf_base &out)
{
return Rpc_dispatcher<RPC_INTERFACE, SERVER>::dispatch(opcode, in, out);
}
@ -287,13 +287,13 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool<Rpc_object_base>
protected:
Ipc_server *_ipc_server;
Lock _cap_valid; /* thread startup synchronization */
Lock _delay_start; /* delay start of request dispatching */
Lock _delay_exit; /* delay destructor until server settled */
Pd_session &_pd_session; /* for creating capabilities */
Exit_handler _exit_handler;
Capability<Exit> _exit_cap;
Native_capability _caller;
Lock _cap_valid; /* thread startup synchronization */
Lock _delay_start; /* delay start of request dispatching */
Lock _delay_exit; /* delay destructor until server settled */
Pd_session &_pd_session; /* for creating capabilities */
Exit_handler _exit_handler;
Capability<Exit> _exit_cap;
/**
* Access to kernel-specific part of the PD session interface
@ -402,7 +402,7 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool<Rpc_object_base>
* Typically, a capability obtained via this method is used as
* argument of 'intermediate_reply'.
*/
Untyped_capability reply_dst();
Untyped_capability reply_dst() { return _caller; }
/**
* Prevent reply of current request
@ -417,7 +417,7 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool<Rpc_object_base>
* request. At a later time, the server may chose to unblock the
* client via the 'intermedate_reply' method.
*/
void omit_reply();
void omit_reply() { _caller = Native_capability(); }
/**
* Send a reply out of the normal call-reply order

View File

@ -1,4 +1,4 @@
if {[have_spec linux] || [have_spec pistachio]} {
if {[have_spec linux]} {
puts "Platform does not support managed dataspaces"; exit }
build "core init test/rm_fault"
@ -30,4 +30,4 @@ build_boot_image "core init test-rm_fault"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-rm_fault" exited with exit value 0.*} 10
run_genode_until {child "test-rm_fault" exited with exit value 0.*} 300

View File

@ -1,36 +0,0 @@
/*
* \brief Marshalling/unmarshalling of plain-data capabilities
* \author Norman Feske
* \date 2013-02-13
*/
/*
* Copyright (C) 2013 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/ipc.h>
using namespace Genode;
/**
* Marshalling of capabilities as plain data representation
*/
void Ipc_marshaller::insert(Native_capability const &cap)
{
insert((char const *)&cap, sizeof(Native_capability));
}
/**
* Unmarshalling of capabilities as plain data representation
*/
void Ipc_unmarshaller::extract(Native_capability &cap)
{
struct Raw { char buf[sizeof(Native_capability)]; } raw;
extract(raw);
(Raw &)(cap) = raw;
}

View File

@ -43,35 +43,12 @@ void Rpc_entrypoint::_block_until_cap_valid()
}
Untyped_capability Rpc_entrypoint::reply_dst()
{
return _ipc_server ? _ipc_server->caller() : Untyped_capability();
}
void Rpc_entrypoint::omit_reply()
{
/* set current destination to an invalid capability */
if (_ipc_server) _ipc_server->caller(Untyped_capability());
}
void Rpc_entrypoint::reply_signal_info(Untyped_capability reply_cap,
unsigned long imprint, unsigned long cnt)
{
if (!_ipc_server) return;
/* backup reply capability of current request */
Untyped_capability last_reply_cap = _ipc_server->caller();
/* direct ipc server to the specified reply destination */
_ipc_server->ret(Rpc_exception_code(Rpc_exception_code::SUCCESS));
_ipc_server->caller(reply_cap);
_ipc_server->insert(Signal_source::Signal(imprint, cnt));
_ipc_server->reply();
/* restore reply capability of the original request */
_ipc_server->caller(last_reply_cap);
Msgbuf<sizeof(Signal_source::Signal)> snd_buf;
snd_buf.insert(Signal_source::Signal(imprint, cnt));
ipc_reply(reply_cap, Rpc_exception_code(Rpc_exception_code::SUCCESS), snd_buf);
}

View File

@ -2,22 +2,18 @@
* \brief Default version of platform-specific part of RPC framework
* \author Norman Feske
* \date 2006-05-12
*
* This version is suitable for platforms similar to L4. Each platform
* for which this implementation is not suited contains a platform-
* specific version in its respective 'base-<platform>' repository.
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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.
*/
/* Genode includes */
#include <util/retry.h>
#include <base/rpc_server.h>
#include <base/sleep.h>
#include <base/printf.h>
/* base-internal includes */
@ -32,8 +28,7 @@ using namespace Genode;
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
Untyped_capability ep_cap = Native_capability(_cap.dst(), 0);
Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, ep_cap);
Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap);
/* add server object to object pool */
obj->cap(new_obj_cap);
@ -46,11 +41,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
void Rpc_entrypoint::entry()
{
using Pool = Object_pool<Rpc_object_base>;
Native_connection_state cs;
Ipc_server srv(cs, _snd_buf, _rcv_buf);
_ipc_server = &srv;
Ipc_server srv;
_cap = srv;
_cap_valid.unlock();
@ -63,27 +54,32 @@ void Rpc_entrypoint::entry()
*/
_delay_start.lock();
Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
while (!_exit_handler.exit) {
Rpc_opcode opcode(0);
Rpc_request const request = ipc_reply_wait(_caller, exc, _snd_buf, _rcv_buf);
_caller = request.caller;
srv.reply_wait();
srv.extract(opcode);
Ipc_unmarshaller unmarshaller(_rcv_buf);
Rpc_opcode opcode(0);
unmarshaller.extract(opcode);
/* set default return value */
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
_snd_buf.reset();
Pool::apply(srv.badge(), [&] (Rpc_object_base *obj)
apply(request.badge, [&] (Rpc_object_base *obj)
{
if (!obj) { return;}
try {
srv.ret(obj->dispatch(opcode, srv, srv));
} catch(Blocking_canceled&) { }
try { exc = obj->dispatch(opcode, unmarshaller, _snd_buf); }
catch(Blocking_canceled&) { }
});
}
/* answer exit call, thereby wake up '~Rpc_entrypoint' */
srv.reply();
Msgbuf<16> snd_buf;
ipc_reply(_caller, Rpc_exception_code(Rpc_exception_code::SUCCESS), snd_buf);
/* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */
_delay_exit.lock();

View File

@ -15,6 +15,7 @@
#include <base/env.h>
#include <base/signal.h>
#include <base/thread.h>
#include <base/sleep.h>
#include <base/trace/events.h>
#include <signal_source/client.h>
#include <util/volatile_object.h>
@ -278,6 +279,11 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source)
/* look up context as pointed to by the signal imprint */
Signal_context *context = (Signal_context *)(source_signal.imprint());
if (!context) {
PERR("received null signal imprint, stop signal handling");
sleep_forever();
}
if (!signal_context_registry()->test_and_lock(context)) {
PWRN("encountered dead signal context");
continue;

View File

@ -11,6 +11,9 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* core includes */
#include <pager.h>
@ -19,11 +22,7 @@ using namespace Genode;
void Pager_object::wake_up()
{
/* notify pager to wake up faulter */
Msgbuf<16> snd, rcv;
Ipc_marshaller marshaller(snd);
marshaller.insert(this);
ipc_call(cap(), snd, rcv, 0);
PWRN("user-level page fault handling is not supported on this platform");
}

View File

@ -18,73 +18,43 @@
#include <base/stdint.h>
#include <base/ipc.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
namespace Genode {
class Native_connection_state;
class Ipc_server;
struct Ipc_server;
/**
* Send reply to caller
*/
void ipc_reply(Native_capability caller, Rpc_exception_code,
Msgbuf_base &snd_msg);
typedef Native_capability Reply_capability;
struct Rpc_request
{
Reply_capability caller;
unsigned long badge = ~0;
Rpc_request() { }
Rpc_request(Reply_capability caller, unsigned long badge)
: caller(caller), badge(badge) { }
};
/**
* Send result of previous RPC request and wait for new one
*/
Rpc_request ipc_reply_wait(Reply_capability const &caller,
Rpc_exception_code reply_exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg);
}
class Genode::Ipc_server : public Ipc_marshaller, public Ipc_unmarshaller,
public Native_capability
struct Genode::Ipc_server : Native_capability
{
private:
bool _reply_needed = false; /* false for the first reply_wait */
Native_capability _caller;
Native_connection_state &_rcv_cs;
void _prepare_next_reply_wait();
unsigned long _badge = 0;
Rpc_exception_code _exception_code { 0 };
public:
/**
* Constructor
*/
Ipc_server(Native_connection_state &,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg);
~Ipc_server();
/**
* Send reply to destination
*/
void reply();
/**
* Send result of previous RPC request and wait for new one
*/
void reply_wait();
/**
* Set return value of server call
*/
void ret(Rpc_exception_code code) { _exception_code = code; }
/**
* Read badge that was supplied with the message
*/
unsigned long badge() const { return _badge; }
/**
* Set reply destination
*/
void caller(Native_capability const &caller)
{
_caller = caller;
_reply_needed = caller.valid();
}
Native_capability caller() const { return _caller; }
Ipc_server();
~Ipc_server();
};
#endif /* _INCLUDE__BASE__INTERNAL__IPC_SERVER_H_ */

View File

@ -1,21 +0,0 @@
/*
* \brief Dummy connection state
* \author Norman Feske
* \date 2016-03-03
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_
#include <base/stdint.h>
namespace Genode { struct Native_connection_state { }; }
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */