base: simplification of the IPC code

This commit replaces the stateful 'Ipc_client' type with the plain
function 'ipc_call' that takes all the needed state as arguments.
The stateful 'Ipc_server' class is retained but it moved from the public
API to the internal ipc_server.h header. The kernel-specific
implementations were cleaned up and simplified. E.g., the 'wait'
function does no longer exist. The badge and exception code are no
longer carried in the message buffers but are handled in kernel-specific
ways.

Issue #610
Issue #1832
This commit is contained in:
Norman Feske 2016-03-15 20:01:59 +01:00 committed by Christian Helmuth
parent 47878bd3e1
commit cda07b7da0
33 changed files with 1106 additions and 1115 deletions

View File

@ -14,42 +14,60 @@
#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:
Genode::size_t _size;
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:
/*
* Begin of message buffer layout
*/
template <typename T>
T &header()
{
static_assert(sizeof(T) <= sizeof(Headroom),
"Header size exceeds message headroom");
return *reinterpret_cast<T *>(buf - sizeof(T));
}
Fiasco::l4_fpage_t rcv_fpage;
Fiasco::l4_msgdope_t size_dope;
Fiasco::l4_msgdope_t send_dope;
char buf[];
unsigned long &word(unsigned i)
{
return reinterpret_cast<unsigned long *>(buf)[i];
}
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; };
/**
* Return address of message buffer
*/
inline void *msg_start() { return &rcv_fpage; };
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
inline void *data() { return buf; };
void *data() { return buf; };
void const *data() const { return buf; };
size_t data_size() const { return _data_size; }
};
@ -63,7 +81,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -17,7 +17,7 @@
#include <base/blocking.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
/* Fiasco includes */
namespace Fiasco {
@ -26,30 +26,89 @@ namespace Fiasco {
#include <l4/sys/kdebug.h>
}
class Msg_header
{
private:
/* kernel-defined message header */
Fiasco::l4_fpage_t rcv_fpage; /* unused */
Fiasco::l4_msgdope_t size_dope;
Fiasco::l4_msgdope_t send_dope;
/*
* 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..
*/
Fiasco::l4_umword_t protocol_word;
public:
void *msg_start() { return &rcv_fpage; }
/**
* Define message size for sending
*/
void snd_size(Genode::size_t size)
{
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);
}
/**
* Define size of receive buffer
*/
void rcv_capacity(Genode::size_t capacity)
{
using namespace Fiasco;
size_dope = L4_IPC_DOPE(capacity/sizeof(l4_umword_t), 0);
}
void *msg_type(Genode::size_t size)
{
using namespace Fiasco;
return size <= sizeof(l4_umword_t) ? L4_IPC_SHORT_MSG : msg_start();
}
};
using namespace Genode;
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
{
using namespace Fiasco;
Msg_header &snd_header = snd_msg.header<Msg_header>();
snd_header.snd_size(snd_msg.data_size());
Msg_header &rcv_header = rcv_msg.header<Msg_header>();
rcv_header.rcv_capacity(rcv_msg.capacity());
l4_msgdope_t ipc_result;
long rec_badge;
_snd_msg.send_dope = L4_IPC_DOPE((_write_offset + 2*sizeof(umword_t) - 1)>>2, 0);
_rcv_msg.size_dope = L4_IPC_DOPE(_rcv_msg.size()>>2, 0);
l4_ipc_call(_dst.dst(),
_write_offset <= 2*sizeof(umword_t) ? L4_IPC_SHORT_MSG : _snd_msg.msg_start(),
_dst.local_name(),
*reinterpret_cast<l4_umword_t *>(&_snd_msg.buf[sizeof(umword_t)]),
_rcv_msg.msg_start(),
reinterpret_cast<l4_umword_t *>(&rec_badge),
reinterpret_cast<l4_umword_t *>(&_rcv_msg.buf[sizeof(umword_t)]),
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),
rcv_header.msg_start(),
&exception_code,
&rcv_msg.word(0),
L4_IPC_NEVER, &ipc_result);
if (L4_IPC_IS_ERROR(ipc_result)) {
@ -61,25 +120,7 @@ void Ipc_client::_call()
throw Genode::Ipc_error();
}
/*
* Reset buffer read and write offsets. We shadow the first mword of the
* send message buffer (filled via '_write_offset') with the local name of
* the invoked remote object. We shadow the first mword of the receive
* buffer (retrieved via '_read_offset') with the local name of the reply
* capability ('rec_badge'), which is bogus in the L4/Fiasco case. In both
* cases, we skip the shadowed message mword when reading/writing the
* message payload.
*/
_write_offset = _read_offset = sizeof(umword_t);
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_read_offset = _write_offset = sizeof(umword_t);
return Rpc_exception_code(exception_code);
}
@ -89,55 +130,39 @@ Ipc_client::Ipc_client(Native_capability const &dst,
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for return value at the beginning of the msgbuf */
_write_offset = 2*sizeof(umword_t);
/* receive buffer offset */
_read_offset = sizeof(umword_t);
_read_offset = _write_offset = 0;
}
void Ipc_server::wait()
static umword_t wait(Native_connection_state &rcv_cs, Msgbuf_base &rcv_msg)
{
/* wait for new server request */
try {
using namespace Fiasco;
using namespace Fiasco;
l4_msgdope_t result;
umword_t badge = 0;
l4_msgdope_t result;
/*
* 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());
/*
* 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 {
_rcv_msg.size_dope = L4_IPC_DOPE(_rcv_msg.size()>>2, 0);
l4_ipc_wait(&rcv_cs.caller, rcv_header.msg_start(),
&badge,
&rcv_msg.word(0),
L4_IPC_NEVER, &result);
l4_ipc_wait(&_rcv_cs.caller, _rcv_msg.msg_start(),
reinterpret_cast<l4_umword_t *>(&_rcv_msg.buf[0]),
reinterpret_cast<l4_umword_t *>(&_rcv_msg.buf[sizeof(umword_t)]),
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
/* reset buffer read offset */
_read_offset = sizeof(umword_t);
} catch (Blocking_canceled) { }
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, 0);
_badge = reinterpret_cast<unsigned long *>(&_rcv_msg.buf)[0];
_prepare_next_reply_wait();
return badge;
}
@ -145,12 +170,13 @@ void Ipc_server::reply()
{
using namespace Fiasco;
_snd_msg.send_dope = L4_IPC_DOPE((_write_offset + sizeof(umword_t) - 1)>>2, 0);
Msg_header &snd_header = _snd_msg.header<Msg_header>();
snd_header.snd_size(_snd_msg.data_size());
l4_msgdope_t result;
l4_ipc_send(_caller.dst(), _snd_msg.msg_start(),
_caller.local_name(),
*reinterpret_cast<l4_umword_t *>(&_snd_msg.buf[sizeof(umword_t)]),
l4_ipc_send(_caller.dst(), snd_header.msg_start(),
_exception_code.value,
_snd_msg.word(0),
L4_IPC_SEND_TIMEOUT_0, &result);
if (L4_IPC_IS_ERROR(result))
@ -168,22 +194,24 @@ void Ipc_server::reply_wait()
l4_msgdope_t ipc_result;
_snd_msg.send_dope = L4_IPC_DOPE((_write_offset + sizeof(umword_t) - 1)>>2, 0);
_rcv_msg.size_dope = L4_IPC_DOPE(_rcv_msg.size()>>2, 0);
Msg_header &snd_header = _snd_msg.header<Msg_header>();
snd_header.snd_size(_snd_msg.data_size());
Msg_header &rcv_header = _rcv_msg.header<Msg_header>();
rcv_header.rcv_capacity(_rcv_msg.capacity());
/*
* Use short IPC for reply if possible.
* This is the common case of returning
* an integer as RPC result.
* 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(),
_write_offset <= 2*sizeof(umword_t) ? L4_IPC_SHORT_MSG : _snd_msg.msg_start(),
_caller.local_name(),
*reinterpret_cast<l4_umword_t *>(&_snd_msg.buf[sizeof(umword_t)]),
&_rcv_cs.caller, _rcv_msg.msg_start(),
reinterpret_cast<l4_umword_t *>(&_rcv_msg.buf[0]),
reinterpret_cast<l4_umword_t *>(&_rcv_msg.buf[sizeof(umword_t)]),
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);
if (L4_IPC_IS_ERROR(ipc_result)) {
@ -197,14 +225,14 @@ void Ipc_server::reply_wait()
* the user but want to wait for the next proper incoming
* message. So let's just wait now.
*/
wait();
_badge = wait(_rcv_cs, _rcv_msg);
}
} else wait();
} else {
_badge = wait(_rcv_cs, _rcv_msg);
}
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, 0);
_badge = reinterpret_cast<unsigned long *>(_rcv_msg.buf)[0];
_prepare_next_reply_wait();
}
@ -215,10 +243,8 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Fiasco::l4_myself(), 0),
_reply_needed(false), _rcv_cs(cs)
{
_read_offset = _write_offset = sizeof(umword_t);
}
_rcv_cs(cs)
{ }
Ipc_server::~Ipc_server() { }

View File

@ -28,6 +28,8 @@ namespace Fiasco {
namespace Genode {
class Ipc_marshaller;
class Msgbuf_base
{
public:
@ -36,12 +38,16 @@ namespace Genode {
protected:
size_t _size;
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;
size_t _snd_cap_sel_cnt = 0;
/**
* Capability selectors to delegate.
@ -51,31 +57,35 @@ namespace Genode {
/**
* Base of capability receive window.
*/
Cap_index* _rcv_idx_base;
Cap_index* _rcv_idx_base = nullptr;
/**
* Read counter for unmarshalling portal capability selectors
*/
addr_t _rcv_cap_sel_cnt;
addr_t _rcv_cap_sel_cnt = 0;
unsigned long _label;
unsigned long _label = 0;
char _msg_start[]; /* symbol marks start of message */
public:
/**
* Constructor
*/
Msgbuf_base()
: _rcv_idx_base(cap_idx_alloc()->alloc_range(MAX_CAP_ARGS)), _label(0)
Msgbuf_base(size_t capacity)
:
_capacity(capacity),
_rcv_idx_base(cap_idx_alloc()->alloc_range(MAX_CAP_ARGS))
{
rcv_reset();
snd_reset();
}
~Msgbuf_base() {
cap_idx_alloc()->free(_rcv_idx_base, MAX_CAP_ARGS); }
public:
~Msgbuf_base()
{
cap_idx_alloc()->free(_rcv_idx_base, MAX_CAP_ARGS);
}
/*
* Begin of actual message buffer
@ -85,22 +95,30 @@ namespace Genode {
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; };
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
inline void *data() { return &_msg_start[0]; };
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
*/
inline void snd_reset() { _snd_cap_sel_cnt = 0; }
void snd_reset() { _snd_cap_sel_cnt = 0; }
/**
* Append capability selector to message buffer
*/
inline bool snd_append_cap_sel(addr_t cap_sel)
bool snd_append_cap_sel(addr_t cap_sel)
{
if (_snd_cap_sel_cnt >= MAX_CAP_ARGS)
return false;
@ -112,7 +130,7 @@ namespace Genode {
/**
* Return number of marshalled capability selectors
*/
inline size_t snd_cap_sel_cnt() { return _snd_cap_sel_cnt; }
size_t snd_cap_sel_cnt() const { return _snd_cap_sel_cnt; }
/**
* Return capability selector to send.
@ -120,7 +138,7 @@ namespace Genode {
* \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) {
addr_t snd_cap_sel(unsigned i) const {
return i < _snd_cap_sel_cnt ? _snd_cap_sel[i] : 0; }
/**
@ -153,7 +171,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -1,6 +1,7 @@
/*
* \brief Implementation of the IPC API for Fiasco.OC
* \author Stefan Kalkowski
* \author Norman Feske
* \date 2009-12-03
*/
@ -29,6 +30,7 @@
/* base-internal includes */
#include <base/internal/lock_helper.h> /* for 'thread_get_my_native_id()' */
#include <base/internal/ipc_server.h>
/* Fiasco.OC includes */
namespace Fiasco {
@ -92,7 +94,7 @@ void Ipc_unmarshaller::extract(Native_capability &cap)
***************/
enum Debug {
DEBUG_MSG = 0,
DEBUG_MSG = 1,
HALT_ON_ERROR = 0
};
@ -116,104 +118,109 @@ static inline bool ipc_error(l4_msgtag_t tag, bool print)
/**
* Copy message registers from UTCB to destination message buffer
*
* \return protocol word (local name or exception code)
*/
static void copy_utcb_to_msgbuf(l4_msgtag_t tag, Msgbuf_base &rcv_msg)
static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, Msgbuf_base &rcv_msg)
{
unsigned num_msg_words = l4_msgtag_words(tag);
unsigned num_cap_sel = l4_msgtag_items(tag);
if (num_msg_words == 0 && num_cap_sel == 0)
return;
unsigned const num_msg_words = l4_msgtag_words(tag);
unsigned const num_cap_sel = l4_msgtag_items(tag);
/* look up and validate destination message buffer to receive the payload */
l4_mword_t *msg_buf = (l4_mword_t *)rcv_msg.buf;
if (num_msg_words*sizeof(l4_mword_t) > rcv_msg.size()) {
/* each message has at least the protocol word */
if (num_msg_words < 2 && num_cap_sel == 0)
return 0;
/* the first message word is reserved for the protocol word */
unsigned num_data_msg_words = num_msg_words - 1;
if ((num_data_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) {
if (DEBUG_MSG)
outstring("receive message buffer too small");
num_msg_words = rcv_msg.size()/sizeof(l4_mword_t);
num_data_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t);
}
/* read message payload into destination message buffer */
l4_mword_t *src = (l4_mword_t *)l4_utcb_mr();
l4_mword_t *dst = (l4_mword_t *)&msg_buf[0];
for (unsigned i = 0; i < num_msg_words; i++)
/* read protocol word from first UTCB message register */
unsigned long const protocol_word = l4_utcb_mr()->mr[0];
/* 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++;
rcv_msg.rcv_reset();
return protocol_word;
}
/**
* Copy message registers from message buffer to UTCB and create message tag.
*
* \param protocol_word badge of invoked object (when a client calls a server)
* or the exception code (when a server replies to a
* client)
*/
static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg, unsigned offset,
Native_capability dst)
static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg,
unsigned long protocol_word)
{
l4_mword_t *msg_buf = (l4_mword_t *)snd_msg.buf;
unsigned num_msg_words = offset/sizeof(l4_mword_t);
unsigned num_cap_sel = snd_msg.snd_cap_sel_cnt();
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();
if (num_msg_words + 2 * num_cap_sel > L4_UTCB_GENERIC_DATA_SIZE) {
/* 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");
throw Ipc_error();
}
/* first copy target label to message buffer */
msg_buf[0] = dst.local_name();
/* copy badge / exception code to UTCB message register */
l4_utcb_mr()->mr[0] = protocol_word;
/* store message into UTCB message registers */
for (unsigned i = 0; i < num_msg_words; i++)
l4_utcb_mr()->mr[i] = msg_buf[i];
/* 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 idx = num_msg_words + 2*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;
}
/* we have consumed capability selectors, reset message buffer */
snd_msg.snd_reset();
return l4_msgtag(0, num_msg_words, num_cap_sel, 0);
}
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
/* copy call message to the UTCBs message registers */
l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _write_offset, _dst);
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();
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;
}
tag = l4_ipc_call(_dst.dst(), l4_utcb(), tag, L4_IPC_NEVER);
if (l4_ipc_error(tag, l4_utcb()) == L4_IPC_RECANCELED)
l4_msgtag_t const reply_tag =
l4_ipc_call(dst.dst(), l4_utcb(), call_tag, L4_IPC_NEVER);
if (l4_ipc_error(reply_tag, l4_utcb()) == L4_IPC_RECANCELED)
throw Genode::Blocking_canceled();
if (ipc_error(tag, DEBUG_MSG))
if (ipc_error(reply_tag, DEBUG_MSG))
throw Genode::Ipc_error();
/* copy request message from the UTCBs message registers */
copy_utcb_to_msgbuf(tag, _rcv_msg);
_write_offset = _read_offset = sizeof(umword_t);
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_read_offset = _write_offset = sizeof(l4_mword_t);
return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_msg));
}
@ -223,54 +230,42 @@ Ipc_client::Ipc_client(Native_capability const &dst,
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
_read_offset = _write_offset = 0;
/* leave space for return value at the beginning of the msgbuf */
_write_offset = 2*sizeof(umword_t);
/* receive buffer offset */
_read_offset = sizeof(umword_t);
_snd_msg.snd_reset();
}
void Ipc_server::wait()
static unsigned long wait(Msgbuf_base &rcv_msg)
{
/* wait for new server request */
try {
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;
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));
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 */
copy_utcb_to_msgbuf(tag, _rcv_msg);
/* reset unmarshaller */
_read_offset = sizeof(l4_mword_t);
} catch (Blocking_canceled) { }
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
_prepare_next_reply_wait();
/* 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, _write_offset, Native_capability());
l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _exception_code.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();
}
@ -287,10 +282,16 @@ void Ipc_server::reply_wait()
l4_umword_t label = 0;
l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _write_offset, Native_capability());
tag = l4_ipc_reply_and_wait(l4_utcb(), tag, &label, L4_IPC_SEND_TIMEOUT_0);
l4_msgtag_t const reply_tag =
copy_msgbuf_to_utcb(_snd_msg, _exception_code.value);
l4_msgtag_t const request_tag =
l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label,
L4_IPC_SEND_TIMEOUT_0);
_rcv_msg.label(label);
if (ipc_error(tag, false)) {
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
@ -299,16 +300,14 @@ void Ipc_server::reply_wait()
* the user but want to wait for the next proper incoming
* message. So let's just wait now.
*/
wait();
_badge = wait(_rcv_msg);
} else {
/* copy request message from the UTCBs message registers */
copy_utcb_to_msgbuf(tag, _rcv_msg);
_badge = extract_msg_from_utcb(request_tag, _rcv_msg);
}
} else
wait();
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
_badge = wait(_rcv_msg);
_prepare_next_reply_wait();
}
@ -319,10 +318,8 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]),
_reply_needed(false), _rcv_cs(cs)
{
_read_offset = _write_offset = sizeof(l4_mword_t);
}
_rcv_cs(cs)
{ }
Ipc_server::~Ipc_server() { }

View File

@ -20,7 +20,7 @@
#include <base/rpc_server.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
using namespace Genode;
@ -61,13 +61,13 @@ void Rpc_entrypoint::entry()
while (!_exit_handler.exit) {
int opcode = 0;
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Ipc_client::ERR_INVALID_OBJECT);
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
apply(srv.badge(), [&] (Rpc_object_base *obj) {
if (!obj) return;

View File

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

View File

@ -16,12 +16,15 @@
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <base/native_capability.h>
#include <base/stdint.h>
#include <util/string.h>
namespace Genode
{
namespace Genode {
class Native_utcb;
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
@ -45,11 +48,13 @@ class Genode::Msgbuf_base
private:
friend class Native_utcb;
friend class Ipc_marshaller;
size_t _size; /* buffer size 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 */
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:
@ -59,19 +64,22 @@ class Genode::Msgbuf_base
char buf[]; /* begin of actual message buffer */
Msgbuf_base(size_t size) : _size(size) { }
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
void const * base() const { return &buf; }
/**
* Return size of message buffer
*/
size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
/**
* Return pointer of message data payload
*/
void *data() { return &buf[0]; }
void *data() { return &buf[0]; }
void const *data() const { return &buf[0]; }
size_t data_size() const { return _data_size; }
/**
* Reset capability buffer.

View File

@ -24,6 +24,7 @@
/* base-internal includes */
#include <base/internal/native_utcb.h>
#include <base/internal/native_thread.h>
#include <base/internal/ipc_server.h>
/* base-hw includes */
#include <kernel/interface.h>
@ -33,19 +34,6 @@ namespace Hw { extern Genode::Untyped_capability _main_thread_cap; }
using namespace Genode;
enum
{
/* size of the callee-local name of a targeted RPC object */
RPC_OBJECT_ID_SIZE = sizeof(Kernel::capid_t),
/*
* The RPC framework marshalls a return value into reply messages to
* deliver exceptions, wich occured during the RPC call to the caller.
* This defines the size of this value.
*/
RPC_RETURN_VALUE_SIZE = sizeof(umword_t),
};
/*****************************
** IPC marshalling support **
@ -60,47 +48,36 @@ void Ipc_unmarshaller::extract(Native_capability &cap) {
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
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, _write_offset);
Thread_base::myself()->utcb()->copy_from(snd_msg);
switch (Kernel::send_request_msg(_dst.dst(),
_rcv_msg.cap_rcv_window())) {
switch (Kernel::send_request_msg(dst.dst(),
rcv_msg.cap_rcv_window())) {
case -1: throw Blocking_canceled();
case -2: throw Allocator::Out_of_memory();
default:
_rcv_msg.reset();
_snd_msg.reset();
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
/* reset unmarshaller */
_write_offset = _read_offset =
align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
rcv_msg.reset();
utcb.copy_to(rcv_msg);
}
},
[&] () { upgrade_pd_session_quota(3*4096); });
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
unsigned short rcv_caps)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
_snd_msg.reset();
_rcv_msg.cap_rcv_window(rcv_caps);
return Rpc_exception_code(utcb.exception_code());
}
@ -108,46 +85,9 @@ Ipc_client::Ipc_client(Native_capability const &dst,
** Ipc_server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for RPC method return value */
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE +
RPC_RETURN_VALUE_SIZE);
/* reset unmarshaller */
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
}
void Ipc_server::wait()
{
retry<Genode::Allocator::Out_of_memory>(
[&] () {
/* receive request */
switch (Kernel::await_request_msg(Msgbuf_base::MAX_CAP_ARGS)) {
case -1: throw Blocking_canceled();
case -2: throw Allocator::Out_of_memory();
default:
_rcv_msg.reset();
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
/* update server state */
_prepare_next_reply_wait();
}
},
[&] () { upgrade_pd_session_quota(3*4096); });
}
void Ipc_server::reply()
{
Thread_base::myself()->utcb()->copy_from(_snd_msg, _write_offset);
Thread_base::myself()->utcb()->copy_from(_snd_msg);
_snd_msg.reset();
Kernel::send_reply_msg(0, false);
}
@ -155,31 +95,35 @@ void Ipc_server::reply()
void Ipc_server::reply_wait()
{
/* if there is no reply, wait for request */
if (!_reply_needed) {
wait();
return;
}
Native_utcb &utcb = *Thread_base::myself()->utcb();
retry<Genode::Allocator::Out_of_memory>(
[&] () {
/* send reply and receive next request */
Thread_base::myself()->utcb()->copy_from(_snd_msg, _write_offset);
switch (Kernel::send_reply_msg(Msgbuf_base::MAX_CAP_ARGS, true)) {
case -1: throw Blocking_canceled();
case -2: throw Allocator::Out_of_memory();
default:
_rcv_msg.reset();
_snd_msg.reset();
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
/* update server state */
_prepare_next_reply_wait();
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);
} else {
ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAP_ARGS);
}
switch (ret) {
case -1: throw Blocking_canceled();
case -2: throw Allocator::Out_of_memory();
default: break;
}
},
[&] () { upgrade_pd_session_quota(3*4096); });
_rcv_msg.reset();
_snd_msg.reset();
utcb.copy_to(_rcv_msg);
_badge = utcb.destination();
_reply_needed = true;
_read_offset = _write_offset = 0;
}
@ -189,10 +133,8 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Thread_base::myself() ? Thread_base::myself()->native_thread().cap
: Hw::_main_thread_cap),
_reply_needed(false), _rcv_cs(cs)
_rcv_cs(cs)
{
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
_snd_msg.reset();
}

View File

@ -18,7 +18,7 @@
#include <util/retry.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
using namespace Genode;
@ -59,13 +59,13 @@ void Rpc_entrypoint::entry()
while (!_exit_handler.exit) {
int opcode = 0;
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Ipc_client::ERR_INVALID_OBJECT);
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
/* atomically lookup and lock referenced object */
apply(srv.badge(), [&] (Rpc_object_base *curr_obj) {

View File

@ -56,15 +56,20 @@ class Genode::Native_utcb
Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */
size_t _cap_cnt; /* capability counter */
size_t _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(_cap_cnt) - sizeof(_size) -
sizeof(_destination) - sizeof(_exception_code)];
public:
Native_utcb& operator= (const Native_utcb &o)
{
_cap_cnt = 0;
_size = o._size;
_cap_cnt = 0;
_size = o._size;
_exception_code = o._exception_code;
_destination = o._destination;
memcpy(_buf, o._buf, _size);
return *this;
}
@ -72,8 +77,16 @@ class Genode::Native_utcb
/**
* Set the destination capability id (server object identity)
*/
void destination(Kernel::capid_t id) {
*reinterpret_cast<long*>(_buf) = id; }
void destination(Kernel::capid_t id) { _destination = id; }
/**
* Return identity of invoked server object
*/
Kernel::capid_t destination() const { return _destination; }
void exception_code(long code) { _exception_code = code; }
long exception_code() const { return _exception_code; }
/**
* Return the count of capabilities in the UTCB
@ -91,17 +104,17 @@ class Genode::Native_utcb
void const * base() const { return &_buf; }
/**
* Copy data from the message buffer 'o' to this UTCB
* Copy data from the message buffer 'snd_msg' to this UTCB
*/
void copy_from(Msgbuf_base &o, size_t size)
void copy_from(Msgbuf_base const &snd_msg)
{
_size = size;
_size = min(snd_msg.data_size(), sizeof(_buf));
_cap_cnt = o._snd_cap_cnt;
_cap_cnt = snd_msg._snd_cap_cnt;
for (unsigned i = 0; i < _cap_cnt; i++)
_caps[i] = o._caps[i].dst();
_caps[i] = snd_msg._caps[i].dst();
memcpy(_buf, o.buf, min(_size, o._size));
memcpy(_buf, snd_msg.buf, min(_size, snd_msg.capacity()));
}
/**
@ -115,7 +128,7 @@ class Genode::Native_utcb
if (o._caps[i].valid()) Kernel::ack_cap(o._caps[i].dst());
}
memcpy(o.buf, _buf, min(_size, o._size));
memcpy(o.buf, _buf, min(_size, o.capacity()));
}
/**

View File

@ -14,8 +14,12 @@
#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
*/
@ -27,22 +31,28 @@ namespace Genode {
protected:
friend class Ipc_marshaller;
/*
* Capabilities (file descriptors) to be transferred
*/
int _caps[MAX_CAPS_PER_MSG];
Genode::size_t _used_caps;
Genode::size_t _read_cap_index;
Genode::size_t _used_caps = 0;
Genode::size_t _read_cap_index = 0;
/**
* Maximum size of plain-data message payload
*/
Genode::size_t _size;
Genode::size_t const _capacity;
/**
* Actual size of plain-data message payload
*/
Genode::size_t _used_size;
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 */
@ -52,19 +62,26 @@ namespace Genode {
public:
char buf[];
Msgbuf_base() { reset_caps(); }
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
*/
inline Genode::size_t size() const { return _size; };
Genode::size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
inline void *data() { return &_msg_start[0]; };
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; }
@ -104,7 +121,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -3,21 +3,6 @@
* \author Norman Feske
* \author Christian Helmuth
* \date 2011-10-11
*
* The current request message layout is:
*
* long server_local_name;
* int opcode;
* ...payload...
*
* Response messages look like this:
*
* long scratch_word;
* int exc_code;
* ...payload...
*
* All fields are naturally aligned, i.e., aligend on 4 or 8 byte boundaries on
* 32-bit resp. 64-bit systems.
*/
/*
@ -37,7 +22,7 @@
/* base-internal includes */
#include <base/internal/socket_descriptor_registry.h>
#include <base/internal/native_thread.h>
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
/* Linux includes */
#include <linux_syscalls.h>
@ -48,6 +33,32 @@
using namespace Genode;
/*
* The request message layout is:
*
* long local_name;
* ...call arguments, starting with the opcode...
*
* Response messages look like this:
*
* long exception code
* ...call results...
*
* 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..
*/
struct Protocol_header
{
unsigned long protocol_word;
void *msg_start() { return &protocol_word; }
};
/*****************************
** IPC marshalling support **
*****************************/
@ -303,14 +314,101 @@ static void extract_sds_from_message(unsigned start_index, Message const &msg,
/**
* Send request to server and wait for reply
* Return type of 'lx_wait'
*/
static inline void lx_call(int dst_sd,
Genode::Msgbuf_base &send_msgbuf, Genode::size_t send_msg_len,
Genode::Msgbuf_base &recv_msgbuf)
struct Request
{
int ret;
Message send_msg(send_msgbuf.buf, send_msg_len);
/**
* 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
*/
static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
Genode::Msgbuf_base &snd_msgbuf)
{
Protocol_header &header = snd_msgbuf.header<Protocol_header>();
header.protocol_word = exception_code.value;
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));
int ret = lx_sendmsg(reply_socket, msg.msg(), 0);
/* ignore reply send error caused by disappearing client */
if (ret >= 0 || ret == -LX_ECONNREFUSED) {
lx_close(reply_socket);
return;
}
if (ret < 0)
PRAW("[%d] lx_sendmsg failed with %d in lx_reply()", lx_getpid(), ret);
}
/****************
** IPC client **
****************/
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msgbuf, Msgbuf_base &rcv_msgbuf,
size_t)
{
Protocol_header &snd_header = snd_msgbuf.header<Protocol_header>();
snd_header.protocol_word = dst.local_name();
Message snd_msg(snd_header.msg_start(),
sizeof(Protocol_header) + snd_msgbuf.data_size());
/*
* Create reply channel
@ -347,123 +445,41 @@ static inline void lx_call(int dst_sd,
/* assemble message */
/* marshal reply capability */
send_msg.marshal_socket(reply_channel.remote_socket());
snd_msg.marshal_socket(reply_channel.remote_socket());
/* marshal capabilities contained in 'send_msgbuf' */
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
send_msg.marshal_socket(send_msgbuf.cap(i));
/* marshal capabilities contained in 'snd_msgbuf' */
for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++)
snd_msg.marshal_socket(snd_msgbuf.cap(i));
ret = lx_sendmsg(dst_sd, send_msg.msg(), 0);
if (ret < 0) {
int const send_ret = lx_sendmsg(dst.dst().socket, snd_msg.msg(), 0);
if (send_ret < 0) {
PRAW("[%d] lx_sendmsg to sd %d failed with %d in lx_call()",
lx_getpid(), dst_sd, ret);
lx_getpid(), dst.dst().socket, send_ret);
throw Genode::Ipc_error();
}
/* receive reply */
Protocol_header &rcv_header = rcv_msgbuf.header<Protocol_header>();
rcv_header.protocol_word = 0;
Message recv_msg(recv_msgbuf.buf, recv_msgbuf.size());
recv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
Message rcv_msg(rcv_header.msg_start(),
sizeof(Protocol_header) + rcv_msgbuf.capacity());
rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
ret = lx_recvmsg(reply_channel.local_socket(), recv_msg.msg(), 0);
int const recv_ret = lx_recvmsg(reply_channel.local_socket(), rcv_msg.msg(), 0);
/* system call got interrupted by a signal */
if (ret == -LX_EINTR)
if (recv_ret == -LX_EINTR)
throw Genode::Blocking_canceled();
if (ret < 0) {
PRAW("[%d] lx_recvmsg failed with %d in lx_call()", lx_getpid(), ret);
if (recv_ret < 0) {
PRAW("[%d] lx_recvmsg failed with %d in lx_call()", lx_getpid(), recv_ret);
throw Genode::Ipc_error();
}
extract_sds_from_message(0, recv_msg, recv_msgbuf);
}
extract_sds_from_message(0, rcv_msg, rcv_msgbuf);
/**
* for request from client
*
* \return socket descriptor of reply capability
*/
static inline int lx_wait(Genode::Native_connection_state &cs,
Genode::Msgbuf_base &recv_msgbuf)
{
Message msg(recv_msgbuf.buf, recv_msgbuf.size());
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
int 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();
}
int const reply_socket = msg.socket_at_index(0);
extract_sds_from_message(1, msg, recv_msgbuf);
return reply_socket;
}
/**
* Send reply to client
*/
static inline void lx_reply(int reply_socket,
Genode::Msgbuf_base &send_msgbuf,
Genode::size_t msg_len)
{
Message msg(send_msgbuf.buf, msg_len);
/*
* Marshall capabilities to be transferred to the client
*/
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
msg.marshal_socket(send_msgbuf.cap(i));
int ret = lx_sendmsg(reply_socket, msg.msg(), 0);
/* ignore reply send error caused by disappearing client */
if (ret >= 0 || ret == -LX_ECONNREFUSED) {
lx_close(reply_socket);
return;
}
if (ret < 0)
PRAW("[%d] lx_sendmsg failed with %d in lx_reply()", lx_getpid(), ret);
}
/****************
** Ipc_client **
****************/
void Ipc_client::_call()
{
lx_call(_dst.dst().socket, _snd_msg, _write_offset, _rcv_msg);
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
/* prepare next request in buffer */
long const local_name = _dst.local_name();
/* prepare response buffer */
_read_offset = sizeof(long);
_write_offset = 0;
insert(local_name);
_snd_msg.reset_caps();
return Rpc_exception_code(rcv_header.protocol_word);
}
@ -473,25 +489,28 @@ Ipc_client::Ipc_client(Native_capability const &dst,
void Ipc_server::_prepare_next_reply_wait()
{
/* skip server-local name */
_read_offset = sizeof(long);
/* prepare next reply */
_write_offset = 0;
long local_name = _caller.local_name();
insert(local_name); /* XXX unused, needed by de/marshaller */
/* leave space for exc code at the beginning of the msgbuf */
_write_offset += align_natural(sizeof(int));
_read_offset = _write_offset = 0;
/* reset capability slots of send message buffer */
_snd_msg.reset_caps();
}
void Ipc_server::wait()
void Ipc_server::reply()
{
_reply_needed = true;
try {
lx_reply(_caller.dst().socket, _exception_code, _snd_msg); }
catch (Ipc_error) { }
_prepare_next_reply_wait();
}
void Ipc_server::reply_wait()
{
/* when first called, there was no request yet */
if (_reply_needed)
lx_reply(_caller.dst().socket, _exception_code, _snd_msg);
/*
* Block infinitely if called from the main thread. This may happen if the
@ -503,42 +522,19 @@ void Ipc_server::wait()
}
try {
int const reply_socket = lx_wait(_rcv_cs, _rcv_msg);
Request const request = lx_wait(_rcv_cs, _rcv_msg);
/*
* Remember reply capability
*
* The 'local_name' of a capability is meaningful for addressing server
* objects only. Because a reply capabilities does not address a server
* object, the 'local_name' is meaningless.
*/
/* remember reply capability */
enum { DUMMY_LOCAL_NAME = -1 };
typedef Native_capability::Dst Dst;
_caller = Native_capability(Dst(reply_socket), DUMMY_LOCAL_NAME);
_badge = reinterpret_cast<unsigned long *>(_rcv_msg.data())[0];
_caller = Native_capability(Dst(request.reply_socket), DUMMY_LOCAL_NAME);
_badge = request.badge;
_prepare_next_reply_wait();
} catch (Blocking_canceled) { }
}
void Ipc_server::reply()
{
try {
lx_reply(_caller.dst().socket, _snd_msg, _write_offset); }
catch (Ipc_error) { }
_prepare_next_reply_wait();
}
void Ipc_server::reply_wait()
{
/* when first called, there was no request yet */
if (_reply_needed)
lx_reply(_caller.dst().socket, _snd_msg, _write_offset);
wait();
_reply_needed = true;
}
@ -547,7 +543,7 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Dst(-1), 0),
_reply_needed(false), _rcv_cs(cs)
_rcv_cs(cs)
{
Thread_base *thread = Thread_base::myself();

View File

@ -27,6 +27,8 @@
namespace Genode {
class Ipc_marshaller;
class Msgbuf_base
{
public:
@ -38,27 +40,31 @@ namespace Genode {
protected:
size_t _size;
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;
size_t _snd_pt_sel_cnt = 0;
/**
* Portal capability selectors to delegate
*/
Native_capability _snd_pt_sel [MAX_CAP_ARGS];
Native_capability _snd_pt_sel[MAX_CAP_ARGS];
/**
* Base of portal receive window
*/
addr_t _rcv_pt_base;
addr_t _rcv_pt_base = 0;
struct {
addr_t sel;
bool del;
} _rcv_pt_sel [MAX_CAP_ARGS];
addr_t sel = 0;
bool del = 0;
} _rcv_pt_sel[MAX_CAP_ARGS];
/**
* Normally the received capabilities start from the beginning of
@ -89,9 +95,9 @@ namespace Genode {
* Read counter for unmarshalling portal capability
* selectors
*/
unsigned short _rcv_pt_sel_cnt;
unsigned short _rcv_pt_sel_max;
unsigned short _rcv_wnd_log2;
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 */
@ -102,8 +108,10 @@ namespace Genode {
/**
* Constructor
*/
Msgbuf_base()
: _rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2)
Msgbuf_base(size_t capacity)
:
_capacity(capacity),
_rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2)
{
rcv_reset();
snd_reset();
@ -122,17 +130,25 @@ namespace Genode {
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
/**
* Return pointer of message data payload
*/
inline void *data() { return &_msg_start[0]; }
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
*/
inline void snd_reset() {
void snd_reset() {
for (unsigned i = 0; i < MAX_CAP_ARGS; i++) {
+_snd_pt_sel[i];
@ -145,7 +161,7 @@ namespace Genode {
/**
* Append portal capability selector to message buffer
*/
inline bool snd_append_pt_sel(Native_capability const &cap)
bool snd_append_pt_sel(Native_capability const &cap)
{
if (_snd_pt_sel_cnt >= MAX_CAP_ARGS - 1)
return false;
@ -158,7 +174,7 @@ namespace Genode {
* Return number of marshalled portal-capability
* selectors
*/
inline size_t snd_pt_sel_cnt() const
size_t snd_pt_sel_cnt() const
{
return _snd_pt_sel_cnt;
}
@ -430,7 +446,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -14,9 +14,11 @@
/* Genode includes */
#include <base/ipc.h>
#include <base/thread.h>
#include <base/printf.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
/* NOVA includes */
#include <nova/syscalls.h>
@ -46,52 +48,70 @@ void Ipc_unmarshaller::extract(Native_capability &cap)
/**
* 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 void copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base &rcv_msg)
static mword_t copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base &rcv_msg)
{
size_t num_msg_words = utcb->msg_words();
if (num_msg_words == 0) return;
/* look up and validate destination message buffer to receive the payload */
mword_t *msg_buf = (mword_t *)rcv_msg.buf;
if (num_msg_words*sizeof(mword_t) > rcv_msg.size()) {
/*
* 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_msg_words*sizeof(mword_t), rcv_msg.size());
num_msg_words = rcv_msg.size()/sizeof(mword_t);
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[0]);
mword_t *dst = (mword_t *)&msg_buf[0];
for (unsigned i = 0; i < num_msg_words; i++)
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 &snd_msg,
unsigned num_msg_words, mword_t local_name)
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.buf;
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;
/*
* XXX determine correct number of message registers
*/
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;
}
msg_buf[0] = local_name;
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[0];
for (unsigned i = 0; i < num_msg_words; i++)
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);
@ -106,66 +126,56 @@ static bool copy_msgbuf_to_utcb(Nova::Utcb *utcb, Msgbuf_base &snd_msg,
return false;
}
/* we have consumed portal capability selectors, reset message buffer */
snd_msg.snd_reset();
return true;
}
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps)
{
/* update receive window for capability selectors if needed */
if (rcv_caps != ~0UL) {
/* calculate max order of caps to be received during reply */
unsigned short log2_max = rcv_caps ? log2(rcv_caps) : 0;
if ((1U << log2_max) < rcv_caps) log2_max ++;
rcv_msg.rcv_wnd(log2_max);
}
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
if (!copy_msgbuf_to_utcb(utcb, _snd_msg, _write_offset/sizeof(mword_t),
_dst.local_name())) {
/* the protocol value is unused as the badge is delivered by the kernel */
if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) {
PERR("could not setup IPC");
return;
throw Ipc_error();
}
/* 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_msg.prepare_rcv_window(utcb, dst.rcv_window()))
/* printf doesn't work here since for IPC also rcv_prepare* is used */
nova_die();
/* establish the mapping via a portal traversal */
uint8_t res = Nova::call(_dst.local_name());
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);
/* set return value for ipc_generic part if call failed */
ret(ERR_INVALID_OBJECT);
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
}
_rcv_msg.post_ipc(utcb, _dst.rcv_window());
copy_utcb_to_msgbuf(utcb, _rcv_msg);
_snd_msg.snd_reset();
rcv_msg.post_ipc(utcb, dst.rcv_window());
_write_offset = _read_offset = sizeof(mword_t);
}
/* handle malformed reply from a server */
if (utcb->msg_words() < 1)
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
unsigned short const rcv_caps)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
if (rcv_caps == ~0)
/* use default values for rcv_wnd */
return;
/* calculate max order of caps to be received during reply */
unsigned short log2_max = rcv_caps ? log2(rcv_caps) : 0;
if ((1U << log2_max) < rcv_caps) log2_max ++;
rcv_msg.rcv_wnd(log2_max);
_read_offset = _write_offset = sizeof(mword_t);
return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_msg));
}
@ -173,7 +183,19 @@ Ipc_client::Ipc_client(Native_capability const &dst,
** Ipc_server **
****************/
void Ipc_server::wait()
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
@ -185,33 +207,24 @@ void Ipc_server::wait()
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
_rcv_msg.post_ipc(utcb);
copy_utcb_to_msgbuf(utcb, _rcv_msg);
/* reset unmarshaller */
_read_offset = sizeof(mword_t);
_write_offset = 2*sizeof(mword_t); /* leave space for the return value */
/* 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;
}
void Ipc_server::reply()
{
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
copy_msgbuf_to_utcb(utcb, _snd_msg, _write_offset/sizeof(mword_t), 0);
Nova::reply(Thread_base::myself()->stack_top());
}
void Ipc_server::reply_wait() { }
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 = sizeof(mword_t);
_read_offset = _write_offset = 0;
}

View File

@ -20,7 +20,7 @@
/* base-internal includes */
#include <base/internal/stack.h>
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
/* NOVA includes */
#include <nova/syscalls.h>
@ -119,15 +119,15 @@ void Rpc_entrypoint::_activation_entry()
ep->_snd_buf.snd_reset();
/* prepare ipc server object (copying utcb content to message buffer */
int opcode = 0;
Rpc_opcode opcode(0);
Native_connection_state cs;
Ipc_server srv(cs, ep->_snd_buf, ep->_rcv_buf);
srv.wait();
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Ipc_client::ERR_INVALID_OBJECT);
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) {

View File

@ -20,8 +20,13 @@
#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
*/
@ -29,25 +34,28 @@ namespace Genode {
{
protected:
size_t _size;
size_t _data_size = 0;
size_t _capacity;
char _msg_start[]; /* symbol marks start of message */
public:
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
/*
* Begin of actual message buffer
*/
char buf[];
friend class Ipc_marshaller;
public:
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; };
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
inline void *data() { return &_msg_start[0]; };
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
};
@ -61,7 +69,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -18,7 +18,7 @@
#include <base/blocking.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
@ -47,43 +47,48 @@ static void kdb_emergency_print(const char *s)
Okl4::L4_KDB_PrintChar(*s);
}
/*
* Message layout within the UTCB
*
* 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
* message registers hold the message payload.
*/
/**
* Copy message registers from UTCB to destination message buffer
*
* \return local name / exception code
*/
static void copy_utcb_to_msgbuf(L4_MsgTag_t rcv_tag, Msgbuf_base &rcv_msg)
static L4_Word_t extract_msg_from_utcb(L4_MsgTag_t rcv_tag, Msgbuf_base &rcv_msg)
{
int num_msg_words = (int)L4_UntypedWords(rcv_tag);
if (num_msg_words <= 0) return;
unsigned num_msg_words = (int)L4_UntypedWords(rcv_tag);
/* look up and validate destination message buffer to receive the payload */
L4_Word_t *msg_buf = (L4_Word_t *)rcv_msg.buf;
if (num_msg_words*sizeof(L4_Word_t) > rcv_msg.size()) {
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.size());
num_msg_words = rcv_msg.size()/sizeof(L4_Word_t);
num_msg_words*sizeof(L4_Word_t), rcv_msg.capacity());
num_msg_words = rcv_msg.capacity()/sizeof(L4_Word_t);
}
L4_Word_t local_name = 0;
L4_StoreMR(1, &local_name);
/* read message payload into destination message buffer */
L4_StoreMRs(1, num_msg_words, msg_buf);
L4_StoreMRs(2, num_msg_words - 2, (L4_Word_t *)rcv_msg.data());
return local_name;
}
/**
* Copy message payload to UTCB message registers
*
* 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. All subsequent message registers hold the
* message payload.
*/
static void copy_msgbuf_to_utcb(Msgbuf_base &snd_msg, unsigned num_msg_words,
L4_Word_t local_name)
static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, unsigned num_msg_words,
L4_Word_t local_name)
{
/* look up address and size of message payload */
L4_Word_t *msg_buf = (L4_Word_t *)snd_msg.buf;
num_msg_words += 1;
num_msg_words += 2;
if (num_msg_words >= L4_GetMessageRegisters()) {
kdb_emergency_print("Message does not fit into UTCB message registers\n");
@ -95,22 +100,25 @@ static void copy_msgbuf_to_utcb(Msgbuf_base &snd_msg, unsigned num_msg_words,
snd_tag.X.u = num_msg_words;
L4_LoadMR (0, snd_tag.raw);
L4_LoadMR (1, local_name);
L4_LoadMRs(2, num_msg_words - 1, msg_buf + 1);
L4_LoadMRs(2, num_msg_words - 2, (L4_Word_t *)snd_msg.data());
}
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
{
/* copy call message to the UTCBs message registers */
copy_msgbuf_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_dst.local_name());
copy_msg_to_utcb(snd_msg, snd_msg.data_size()/sizeof(L4_Word_t),
dst.local_name());
L4_Accept(L4_UntypedWordsAcceptor);
L4_MsgTag_t rcv_tag = L4_Call(_dst.dst());
L4_MsgTag_t rcv_tag = L4_Call(dst.dst());
enum { ERROR_MASK = 0xe, ERROR_CANCELED = 3 << 1 };
if (L4_IpcFailed(rcv_tag) &&
@ -119,23 +127,11 @@ void Ipc_client::_call()
if (L4_IpcFailed(rcv_tag)) {
kdb_emergency_print("Ipc failed\n");
/* set return value for ipc_generic part if call failed */
ret(ERR_INVALID_OBJECT);
return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT);
}
/* copy request message from the UTCBs message registers */
copy_utcb_to_msgbuf(rcv_tag, _rcv_msg);
_write_offset = _read_offset = sizeof(umword_t);
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_write_offset = _read_offset = sizeof(umword_t);
return Rpc_exception_code(extract_msg_from_utcb(rcv_tag, rcv_msg));
}
@ -145,50 +141,16 @@ Ipc_client::Ipc_client(Native_capability const &dst,
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for return value at the beginning of the msgbuf */
_write_offset = 2*sizeof(umword_t);
/* receive buffer offset */
_read_offset = sizeof(umword_t);
}
void Ipc_server::wait()
{
/* wait for new server request */
try {
/*
* Wait for IPC message
*
* The message tag (holding the size of the message) is located at
* message register 0 and implicitly addressed by 'L4_UntypedWords()'.
*/
L4_MsgTag_t rcv_tag = L4_Wait(&_rcv_cs.caller);
/* copy message from the UTCBs message registers to the receive buffer */
copy_utcb_to_msgbuf(rcv_tag, _rcv_msg);
/* reset unmarshaller */
_read_offset = sizeof(umword_t);
} catch (Blocking_canceled) { }
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_badge = reinterpret_cast<unsigned long *>(_rcv_msg.data())[0];
_prepare_next_reply_wait();
_read_offset = _write_offset = 0;
}
void Ipc_server::reply()
{
/* copy reply to the UTCBs message registers */
copy_msgbuf_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_caller.local_name());
copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_exception_code.value);
/* perform non-blocking IPC send operation */
L4_MsgTag_t rcv_tag = L4_Reply(_caller.dst());
@ -202,29 +164,26 @@ void Ipc_server::reply()
void Ipc_server::reply_wait()
{
L4_MsgTag_t rcv_tag;
if (_reply_needed) {
/* copy reply to the UTCBs message registers */
copy_msgbuf_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_caller.local_name());
copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t),
_exception_code.value);
L4_MsgTag_t rcv_tag = L4_ReplyWait(_caller.dst(), &_rcv_cs.caller);
rcv_tag = L4_ReplyWait(_caller.dst(), &_rcv_cs.caller);
} else {
rcv_tag = L4_Wait(&_rcv_cs.caller);
}
/*
* TODO: Check for IPC error
*/
/* copy request message from the UTCBs message registers */
_badge = extract_msg_from_utcb(rcv_tag, _rcv_msg);
/* copy request message from the UTCBs message registers */
copy_utcb_to_msgbuf(rcv_tag, _rcv_msg);
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_badge = reinterpret_cast<unsigned long *>(_rcv_msg.data())[0];
_prepare_next_reply_wait();
} else
wait();
_prepare_next_reply_wait();
}
@ -249,9 +208,8 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
Ipc_marshaller(snd_msg),
Ipc_unmarshaller(rcv_msg),
Native_capability(thread_get_my_global_id(), 0),
_reply_needed(false), _rcv_cs(cs)
{
_read_offset = _write_offset = sizeof(umword_t);
}
_rcv_cs(cs)
{ }
Ipc_server::~Ipc_server() { }

View File

@ -16,6 +16,8 @@
namespace Genode {
class Ipc_marshaller;
/**
* IPC message buffer layout
*/
@ -23,8 +25,15 @@ namespace Genode {
{
protected:
size_t _size;
char _msg_start[]; /* symbol marks start of message */
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:
@ -33,17 +42,18 @@ namespace Genode {
*/
Pistachio::L4_Fpage_t rcv_fpage;
char buf[];
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; };
size_t capacity() const { return _capacity; };
/**
* Return pointer of message data payload
*/
inline void *data() { return &_msg_start[0]; };
void *data() { return &_msg_start[0]; };
void const *data() const { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
};
@ -57,7 +67,7 @@ namespace Genode {
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
Msgbuf() : Msgbuf_base(BUF_SIZE) { }
};
}

View File

@ -19,7 +19,7 @@
#include <base/sleep.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
/* Pistachio includes */
namespace Pistachio {
@ -85,20 +85,22 @@ static inline void check_ipc_result(L4_MsgTag_t result, L4_Word_t error_code)
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
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(_write_offset, _snd_msg.buf);
L4_Word_t const local_name = _dst.local_name();
L4_StringItem_t sitem = L4_StringItem(snd_msg.data_size(), snd_msg.data());
L4_Word_t const local_name = dst.local_name();
L4_MsgBuffer_t msgbuf;
/* prepare message buffer */
L4_Clear (&msgbuf);
L4_Append (&msgbuf, L4_StringItem (_rcv_msg.size(), _rcv_msg.buf));
L4_Append (&msgbuf, L4_StringItem (rcv_msg.capacity(), rcv_msg.data()));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &msgbuf);
@ -108,20 +110,14 @@ void Ipc_client::_call()
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_MsgTag_t result = L4_Call(_dst.dst());
L4_MsgTag_t result = L4_Call(dst.dst());
_write_offset = _read_offset = sizeof(umword_t);
L4_Clear(&msg);
L4_Store(result, &msg);
check_ipc_result(result, L4_ErrorCode());
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_read_offset = _write_offset = sizeof(umword_t);
return Rpc_exception_code(L4_Get(&msg, 0));
}
@ -131,63 +127,15 @@ Ipc_client::Ipc_client(Native_capability const &dst,
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for return value at the beginning of the msgbuf */
_write_offset = 2*sizeof(umword_t);
/* receive buffer offset */
_read_offset = sizeof(umword_t);
}
void Ipc_server::wait()
{
/* wait for new server request */
try {
L4_MsgTag_t result;
L4_MsgBuffer_t msgbuf;
do {
IPCDEBUG("_wait loop start (more than once means IpcError)\n");
L4_Clear (&msgbuf);
L4_Append (&msgbuf, L4_StringItem (_rcv_msg.size(), _rcv_msg.buf));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &msgbuf);
/* wait for message */
result = L4_Wait(&_rcv_cs.caller);
} while (L4_IpcFailed(result));
L4_Msg_t msg;
L4_Store(result, &msg);
check_ipc_result(result, L4_ErrorCode());
/* remember badge of invoked object */
_badge = L4_Get(&msg, 0);
_read_offset = sizeof(umword_t);
} catch (Blocking_canceled) { }
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_prepare_next_reply_wait();
_read_offset = _write_offset = 0;
}
void Ipc_server::reply()
{
L4_Msg_t msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.buf);
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data());
L4_Word_t const local_name = _caller.local_name();
L4_Clear(&msg);
@ -205,65 +153,57 @@ void Ipc_server::reply()
void Ipc_server::reply_wait()
{
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);
if (_reply_needed) {
/* prepare massage */
L4_Msg_t msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.buf);
L4_Word_t const local_name = _caller.local_name();
/* prepare reply massage */
L4_Msg_t reply_msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data());
L4_Clear(&msg);
L4_Append(&msg, local_name);
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_Clear(&reply_msg);
L4_Append(&reply_msg, (L4_Word_t)_exception_code.value);
L4_Append(&reply_msg, sitem);
L4_Load(&reply_msg);
/* Prepare message buffer */
L4_MsgBuffer_t msgbuf;
L4_Clear(&msgbuf);
L4_Append(&msgbuf, L4_StringItem (_rcv_msg.size(), _rcv_msg.buf));
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &msgbuf);
/* 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);
L4_MsgTag_t result = L4_Ipc(_caller.dst(), L4_anythread,
L4_Timeouts(L4_ZeroTime, L4_Never), &_rcv_cs.caller);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
}
/* error handling - check whether send or receive failed */
if (L4_IpcFailed(result)) {
L4_Word_t errcode = L4_ErrorCode();
L4_Word_t phase = errcode & 1;
L4_Word_t error = (errcode & 0xF) >> 1;
while (need_to_wait) {
PERR("IPC %s error %02lx, offset %08lx -> _wait() instead.",
phase ? "receive" : "send", error, errcode >> 4);
wait();
return;
}
/* wait for new request message */
request_tag = L4_Wait(&_rcv_cs.caller);
L4_Clear(&msg);
L4_Store(result, &msg);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
}
try {
check_ipc_result(result, L4_ErrorCode());
} catch (...) {
/*
* If something went wrong, just call _wait instead of relaying
* the error to the user.
*/
IPCDEBUG("Bad IPC content -> _wait() instead.\n");
wait();
return;
}
/* extract request parameters */
L4_Msg_t msg;
L4_Clear(&msg);
L4_Store(request_tag, &msg);
/* remember badge of invoked object */
_badge = L4_Get(&msg, 0);
/* remember badge of invoked object */
_badge = L4_Get(&msg, 0);
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_prepare_next_reply_wait();
} else
wait();
_prepare_next_reply_wait();
}
@ -272,9 +212,9 @@ Ipc_server::Ipc_server(Native_connection_state &cs,
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
Native_capability(Pistachio::L4_Myself(), 0),
_reply_needed(false), _rcv_cs(cs)
_rcv_cs(cs)
{
_read_offset = _write_offset = sizeof(umword_t);
_read_offset = _write_offset = 0;
}

View File

@ -20,6 +20,8 @@ namespace Genode {
class Msgbuf_base;
template <unsigned> struct Msgbuf;
class Ipc_marshaller;
}
@ -31,6 +33,8 @@ class Genode::Msgbuf_base
protected:
friend class Ipc_marshaller;
/*
* Resolve ambiguity if the header is included from a libc-using
* program.
@ -47,12 +51,12 @@ class Genode::Msgbuf_base
/**
* Maximum size of plain-data message payload
*/
size_t const _size;
size_t const _capacity;
/**
* Actual size of plain-data message payload
*/
size_t _used_size = 0;
size_t _data_size = 0;
char _msg_start[]; /* symbol marks start of message buffer data */
@ -60,7 +64,7 @@ class Genode::Msgbuf_base
* No member variables are allowed beyond this point!
*/
Msgbuf_base(size_t size) : _size(size) { }
Msgbuf_base(size_t capacity) : _capacity(capacity) { }
public:
@ -69,7 +73,7 @@ class Genode::Msgbuf_base
/**
* Return size of message buffer
*/
size_t size() const { return _size; };
size_t capacity() const { return _capacity; };
void reset_caps()
{
@ -90,6 +94,8 @@ class Genode::Msgbuf_base
void const *data() const { return &_msg_start[0]; };
void *data() { return &_msg_start[0]; };
size_t data_size() const { return _data_size; }
/**
* Exception type
*/
@ -122,10 +128,8 @@ class Genode::Msgbuf_base
*/
size_t used_caps() const { return _used_caps; }
Native_capability &cap(unsigned index)
{
return _caps[index];
}
Native_capability &cap(unsigned index) { return _caps[index]; }
Native_capability const &cap(unsigned index) const { return _caps[index]; }
};

View File

@ -21,6 +21,7 @@
/* base-internal includes */
#include <base/internal/capability_space_sel4.h>
#include <base/internal/kernel_debugger.h>
#include <base/internal/ipc_server.h>
/* seL4 includes */
#include <sel4/sel4.h>
@ -32,8 +33,9 @@ using namespace Genode;
* Message-register definitions
*/
enum {
MR_IDX_NUM_CAPS = 0,
MR_IDX_CAPS = 1,
MR_IDX_EXC_CODE = 0,
MR_IDX_NUM_CAPS = 1,
MR_IDX_CAPS = 2,
MR_IDX_DATA = MR_IDX_CAPS + Msgbuf_base::MAX_CAPS_PER_MSG,
};
@ -64,7 +66,7 @@ static unsigned &rcv_sel()
* \param msg source message buffer
* \param data_length size of message data in bytes
*/
static seL4_MessageInfo_t new_seL4_message(Msgbuf_base &msg,
static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg,
size_t const data_length)
{
/*
@ -74,7 +76,7 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base &msg,
size_t sel4_sel_cnt = 0;
for (size_t i = 0; i < msg.used_caps(); i++) {
Native_capability &cap = msg.cap(i);
Native_capability const &cap = msg.cap(i);
if (cap.valid()) {
Capability_space::Ipc_cap_data const ipc_cap_data =
@ -268,12 +270,14 @@ void Ipc_unmarshaller::extract(Native_capability &cap)
/****************
** Ipc_client **
** IPC client **
****************/
void Ipc_client::_call()
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
{
if (!_dst.valid()) {
if (!dst.valid()) {
PERR("Trying to invoke an invalid capability, stop.");
kernel_debugger_panic("IPC destination is invalid");
}
@ -282,26 +286,16 @@ void Ipc_client::_call()
rcv_sel() = Capability_space::alloc_rcv_sel();
seL4_MessageInfo_t const request_msg_info =
new_seL4_message(_snd_msg, _write_offset);
new_seL4_message(snd_msg, snd_msg.data_size());
unsigned const dst_sel = Capability_space::ipc_cap_data(_dst).sel.value();
unsigned const dst_sel = Capability_space::ipc_cap_data(dst).sel.value();
seL4_MessageInfo_t const reply_msg_info =
seL4_Call(dst_sel, request_msg_info);
decode_seL4_message(reply_msg_info, _rcv_msg);
decode_seL4_message(reply_msg_info, rcv_msg);
_write_offset = _read_offset = sizeof(umword_t);
}
Ipc_client::Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
unsigned short)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
{
_read_offset = _write_offset = sizeof(umword_t);
return Rpc_exception_code(seL4_GetMR(MR_IDX_EXC_CODE));
}
@ -309,34 +303,6 @@ Ipc_client::Ipc_client(Native_capability const &dst,
** Ipc_server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for return value at the beginning of the msgbuf */
_write_offset = 2*sizeof(umword_t);
/* receive buffer offset */
_read_offset = sizeof(umword_t);
_rcv_msg.reset_read_cap_index();
_snd_msg.reset_caps();
}
void Ipc_server::wait()
{
seL4_MessageInfo_t const msg_info =
seL4_Recv(Thread_base::myself()->native_thread().ep_sel,
(seL4_Word *)&_badge);
decode_seL4_message(msg_info, _rcv_msg);
_prepare_next_reply_wait();
}
void Ipc_server::reply()
{
ASSERT(false);
@ -347,13 +313,19 @@ void Ipc_server::reply_wait()
{
if (!_reply_needed) {
wait();
seL4_MessageInfo_t const msg_info =
seL4_Recv(Thread_base::myself()->native_thread().ep_sel,
(seL4_Word *)&_badge);
decode_seL4_message(msg_info, _rcv_msg);
} else {
seL4_MessageInfo_t const reply_msg_info =
new_seL4_message(_snd_msg, _write_offset);
seL4_SetMR(MR_IDX_EXC_CODE, _exception_code.value);
seL4_MessageInfo_t const request_msg_info =
seL4_ReplyRecv(Thread_base::myself()->native_thread().ep_sel,
reply_msg_info, (seL4_Word *)&_badge);
@ -361,20 +333,21 @@ void Ipc_server::reply_wait()
decode_seL4_message(request_msg_info, _rcv_msg);
}
_prepare_next_reply_wait();
_reply_needed = true;
_read_offset = _write_offset = 0;
_rcv_msg.reset_read_cap_index();
_snd_msg.reset_caps();
}
Ipc_server::Ipc_server(Native_connection_state &cs,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg)
:
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg),
_reply_needed(false), _rcv_cs(cs)
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()));
_read_offset = _write_offset = sizeof(umword_t);
}

View File

@ -21,7 +21,7 @@
/* base-internal includes */
#include <base/internal/capability_space_sel4.h>
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
using namespace Genode;
@ -62,13 +62,13 @@ void Rpc_entrypoint::entry()
while (!_exit_handler.exit) {
int opcode = 0;
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Ipc_client::ERR_INVALID_OBJECT);
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
/* atomically lookup and lock referenced object */
auto lambda = [&] (Rpc_object_base *obj) {

View File

@ -25,7 +25,8 @@ namespace Genode {
/**
* Forward declaration needed for internal interfaces of 'Capability'
*/
class Ipc_client;
class Ipc_marshaller;
class Ipc_unmarshaller;
/**
@ -57,32 +58,32 @@ class Genode::Capability : public Untyped_capability
* Insert RPC arguments into the message buffer
*/
template <typename ATL>
void _marshal_args(Ipc_client &ipc_client, ATL &args) const;
void _marshal_args(Ipc_marshaller &, ATL &args) const;
void _marshal_args(Ipc_client &, Meta::Empty &) const { }
void _marshal_args(Ipc_marshaller &, Meta::Empty &) const { }
/**
* Unmarshal single RPC argument from the message buffer
*/
template <typename T>
void _unmarshal_result(Ipc_client &ipc_client, T &arg,
void _unmarshal_result(Ipc_unmarshaller &, T &arg,
Meta::Overload_selector<Rpc_arg_out>) const;
template <typename T>
void _unmarshal_result(Ipc_client &ipc_client, T &arg,
void _unmarshal_result(Ipc_unmarshaller &, T &arg,
Meta::Overload_selector<Rpc_arg_inout>) const;
template <typename T>
void _unmarshal_result(Ipc_client &, T &,
void _unmarshal_result(Ipc_unmarshaller &, T &,
Meta::Overload_selector<Rpc_arg_in>) const { }
/**
* Read RPC results from the message buffer
*/
template <typename ATL>
void _unmarshal_results(Ipc_client &ipc_client, ATL &args) const;
void _unmarshal_results(Ipc_unmarshaller &, ATL &args) const;
void _unmarshal_results(Ipc_client &, Meta::Empty &) const { }
void _unmarshal_results(Ipc_unmarshaller &, Meta::Empty &) const { }
/**
* Check RPC return code for the occurrence of exceptions
@ -97,9 +98,10 @@ class Genode::Capability : public Untyped_capability
void _check_for_exceptions(Rpc_exception_code const exc_code,
Meta::Overload_selector<EXC_TL>) const
{
enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length<EXC_TL>::Value };
enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE
- Meta::Length<EXC_TL>::Value };
if (exc_code == EXCEPTION_CODE)
if (exc_code.value == EXCEPTION_CODE)
throw typename EXC_TL::Head();
_check_for_exceptions(exc_code, Meta::Overload_selector<typename EXC_TL::Tail>());

View File

@ -2,13 +2,6 @@
* \brief Generic IPC infrastructure
* \author Norman Feske
* \date 2006-06-12
*
* Most of the marshalling and unmarshallung code is generic for IPC
* implementations among different platforms. In addition to the generic
* marshalling items, platform-specific marshalling items can be realized
* via specialized stream operators defined in the platform-specific
* 'base/ipc.h'. Hence, this header file is never to be included directly.
* It should only be included by a platform-specific 'base/ipc.h' file.
*/
/*
@ -32,13 +25,24 @@
namespace Genode {
class Native_connection_state;
class Ipc_error;
class Ipc_marshaller;
class Ipc_unmarshaller;
class Ipc_client;
class Ipc_server;
/**
* Invoke capability to call an RPC function
*
* \param rcv_caps number of capabilities expected as result
* \throw Blocking_canceled
*
* \noapi
*
* The 'rcv_caps' value is used on kernels like NOVA to allocate the
* receive window for incoming capability selectors.
*/
Rpc_exception_code ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t rcv_caps);
}
@ -51,17 +55,17 @@ class Genode::Ipc_error : public Exception { };
/**
* Marshal arguments into send message buffer
*/
class Genode::Ipc_marshaller
class Genode::Ipc_marshaller : Noncopyable
{
protected:
Msgbuf_base &_snd_msg;
unsigned _write_offset = 0;
size_t &_write_offset = _snd_msg._data_size;
private:
char *_snd_buf = (char *)_snd_msg.data();
size_t const _snd_buf_size = _snd_msg.size();
size_t const _snd_buf_size = _snd_msg.capacity();
public:
@ -123,17 +127,17 @@ class Genode::Ipc_marshaller
/**
* Unmarshal arguments from receive buffer
*/
class Genode::Ipc_unmarshaller
class Genode::Ipc_unmarshaller : Noncopyable
{
protected:
Msgbuf_base &_rcv_msg;
unsigned _read_offset = 0;
unsigned _read_offset = 0;
private:
char *_rcv_buf = (char *)_rcv_msg.data();
size_t const _rcv_buf_size = _rcv_msg.size();
size_t const _rcv_buf_size = _rcv_msg.capacity();
public:
@ -191,123 +195,9 @@ class Genode::Ipc_unmarshaller
_read_offset += align_natural(sizeof(T));
}
public:
Ipc_unmarshaller(Msgbuf_base &rcv_msg) : _rcv_msg(rcv_msg) { }
};
class Genode::Ipc_client : public Ipc_marshaller, public Ipc_unmarshaller,
public Noncopyable
{
protected:
int _result = 0; /* result of most recent call */
Native_capability _dst;
/**
* Set return value if call to server failed
*/
void ret(int retval)
{
reinterpret_cast<umword_t *>(_rcv_msg.data())[1] = retval;
}
void _call();
public:
enum { ERR_INVALID_OBJECT = -70000, };
/**
* Constructor
*/
Ipc_client(Native_capability const &dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
unsigned short rcv_caps = ~0);
/**
* Send RPC message and wait for result
*
* \throw Ipc_error
*/
void call()
{
_call();
extract(_result);
if (_result == ERR_INVALID_OBJECT)
throw Ipc_error();
}
int result() const { return _result; }
};
class Genode::Ipc_server : public Ipc_marshaller, public Ipc_unmarshaller,
public Noncopyable, public Native_capability
{
protected:
bool _reply_needed; /* false for the first reply_wait */
Native_capability _caller;
Native_connection_state &_rcv_cs;
void _prepare_next_reply_wait();
unsigned long _badge;
public:
/**
* Constructor
*/
Ipc_server(Native_connection_state &,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg);
~Ipc_server();
/**
* Wait for incoming call
*/
void wait();
/**
* 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(int retval)
{
reinterpret_cast<umword_t *>(_snd_msg.data())[1] = retval;
}
/**
* 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; }
};
#endif /* _INCLUDE__BASE__IPC_H_ */

View File

@ -152,25 +152,47 @@ namespace Genode {
/**
* Type used for transmitting the opcode of a RPC function (used for RPC call)
*/
typedef int Rpc_opcode;
struct Rpc_opcode
{
long value = 0;
explicit Rpc_opcode(int value) : value(value) { }
};
/**
* Type used for transmitting exception information (used for RPC reply)
*/
typedef int Rpc_exception_code;
struct Rpc_exception_code
{
long value;
enum {
SUCCESS = 0,
/**
* Special exception code used to respond to illegal opcodes
*/
enum { RPC_INVALID_OPCODE = -1 };
/**
* Server-side object does not exist
*
* This exception code is not meant to be reflected from the server
* to the client. On kernels with capability support, the condition
* can never occur. On kernels without capability protection, the
* code is merely used for diagnostic purposes at the server side.
*/
INVALID_OBJECT = -1,
/**
* Special exception code used to respond to illegal opcodes
*/
INVALID_OPCODE = -2,
/**
* Opcode base used for passing exception information
*/
enum { RPC_EXCEPTION_BASE = -1000 };
/**
* Opcode base used for passing exception information
*/
EXCEPTION_BASE = -1000
};
explicit Rpc_exception_code(int value) : value(value) { }
};
/**

View File

@ -58,39 +58,39 @@ namespace Genode {
template <typename RPC_INTERFACE>
template <typename ATL>
void Capability<RPC_INTERFACE>::
_marshal_args(Ipc_client &ipc_client, ATL &args) const
_marshal_args(Ipc_marshaller &marshaller, ATL &args) const
{
if (Trait::Rpc_direction<typename ATL::Head>::Type::IN)
ipc_client.insert(args.get());
marshaller.insert(args.get());
_marshal_args(ipc_client, args._2);
_marshal_args(marshaller, args._2);
}
template <typename RPC_INTERFACE>
template <typename T>
void Capability<RPC_INTERFACE>::
_unmarshal_result(Ipc_client &ipc_client, T &arg,
_unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector<Rpc_arg_out>) const
{
ipc_client.extract(arg);
unmarshaller.extract(arg);
}
template <typename RPC_INTERFACE>
template <typename T>
void Capability<RPC_INTERFACE>::
_unmarshal_result(Ipc_client &ipc_client, T &arg,
_unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector<Rpc_arg_inout>) const
{
_unmarshal_result(ipc_client, arg, Meta::Overload_selector<Rpc_arg_out>());
_unmarshal_result(unmarshaller, arg, Meta::Overload_selector<Rpc_arg_out>());
}
template <typename RPC_INTERFACE>
template <typename ATL>
void Capability<RPC_INTERFACE>::
_unmarshal_results(Ipc_client &ipc_client, ATL &args) const
_unmarshal_results(Ipc_unmarshaller &unmarshaller, ATL &args) const
{
/*
* Unmarshal current argument. The overload of
@ -98,10 +98,10 @@ namespace Genode {
* direction.
*/
typedef typename Trait::Rpc_direction<typename ATL::Head>::Type Rpc_dir;
_unmarshal_result(ipc_client, args.get(), Meta::Overload_selector<Rpc_dir>());
_unmarshal_result(unmarshaller, args.get(), Meta::Overload_selector<Rpc_dir>());
/* unmarshal remaining arguments */
_unmarshal_results(ipc_client, args._2);
_unmarshal_results(unmarshaller, args._2);
}
@ -119,38 +119,43 @@ namespace Genode {
enum { PROTOCOL_OVERHEAD = 4*sizeof(long),
CALL_MSG_SIZE = Rpc_function_msg_size<IF, RPC_CALL>::Value,
REPLY_MSG_SIZE = Rpc_function_msg_size<IF, RPC_REPLY>::Value,
CAP_BY_VALUE = Rpc_function_caps_out<IF>::Value };
RECEIVE_CAPS = Rpc_function_caps_out<IF>::Value };
Msgbuf<CALL_MSG_SIZE + PROTOCOL_OVERHEAD> call_buf;
Msgbuf<REPLY_MSG_SIZE + PROTOCOL_OVERHEAD> reply_buf;
Ipc_client ipc_client(*this, call_buf, reply_buf, CAP_BY_VALUE);
/* determine opcode of RPC function */
typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions;
Rpc_opcode opcode = static_cast<int>(Meta::Index_of<Rpc_functions, IF>::Value);
Rpc_opcode opcode(static_cast<int>(Meta::Index_of<Rpc_functions, IF>::Value));
/* marshal opcode and RPC input arguments */
ipc_client.insert(opcode);
_marshal_args(ipc_client, args);
Ipc_marshaller marshaller(call_buf);
marshaller.insert(opcode);
_marshal_args(marshaller, args);
{
Trace::Rpc_call trace_event(IF::name(), call_buf);
}
/* perform RPC, unmarshal return value */
ipc_client.call();
ipc_client.extract(ret);
Rpc_exception_code const exception_code =
ipc_call(*this, call_buf, reply_buf, RECEIVE_CAPS);
if (exception_code.value == Rpc_exception_code::INVALID_OBJECT)
throw Ipc_error();
Ipc_unmarshaller unmarshaller(reply_buf);
unmarshaller.extract(ret);
{
Trace::Rpc_returned trace_event(IF::name(), reply_buf);
}
/* unmarshal RPC output arguments */
_unmarshal_results(ipc_client, args);
_unmarshal_results(unmarshaller, args);
/* reflect callee-side exception at the caller */
_check_for_exceptions(ipc_client.result(),
_check_for_exceptions(exception_code,
Meta::Overload_selector<typename IF::Exceptions>());
}
}

View File

@ -24,6 +24,9 @@
#include <cap_session/cap_session.h>
namespace Genode {
class Ipc_server;
template <typename, typename> class Rpc_dispatcher;
class Rpc_object_base;
template <typename, typename> struct Rpc_object;
@ -86,12 +89,15 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
typename RPC_FUNCTION::Ret_type &ret,
Meta::Overload_selector<RPC_FUNCTION, EXC_TL>)
{
enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length<EXC_TL>::Value };
enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE
- Meta::Length<EXC_TL>::Value };
try {
typedef typename EXC_TL::Tail Exc_tail;
return _do_serve(args, ret,
Meta::Overload_selector<RPC_FUNCTION, Exc_tail>());
} catch (typename EXC_TL::Head) { return EXCEPTION_CODE; }
} catch (typename EXC_TL::Head) {
return Rpc_exception_code(EXCEPTION_CODE);
}
}
template <typename RPC_FUNCTION>
@ -100,7 +106,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
Meta::Overload_selector<RPC_FUNCTION, Meta::Empty>)
{
RPC_FUNCTION::serve(*static_cast<SERVER *>(this), args, ret);
return 0;
return Rpc_exception_code(Rpc_exception_code::SUCCESS);
}
template <typename RPC_FUNCTIONS_TO_CHECK>
@ -112,7 +118,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
typedef typename RPC_FUNCTIONS_TO_CHECK::Head This_rpc_function;
if (opcode == Index_of<Rpc_functions, This_rpc_function>::Value) {
if (opcode.value == Index_of<Rpc_functions, This_rpc_function>::Value) {
typename This_rpc_function::Server_args args{};
@ -131,8 +137,10 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
typedef typename This_rpc_function::Exceptions Exceptions;
typename This_rpc_function::Ret_type ret { };
Rpc_exception_code exc;
exc = _do_serve(args, ret, Overload_selector<This_rpc_function, Exceptions>());
Rpc_exception_code
exc(_do_serve(args, ret,
Overload_selector<This_rpc_function, Exceptions>()));
out.insert(ret);
{
@ -149,21 +157,22 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
return _do_dispatch(opcode, in, out, Overload_selector<Tail>());
}
int _do_dispatch(int opcode, Ipc_unmarshaller &, Ipc_marshaller &,
Meta::Overload_selector<Meta::Empty>)
Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &, Ipc_marshaller &,
Meta::Overload_selector<Meta::Empty>)
{
PERR("invalid opcode %d\n", opcode);
return RPC_INVALID_OPCODE;
PERR("invalid opcode %ld\n", opcode.value);
return Rpc_exception_code(Rpc_exception_code::INVALID_OPCODE);
}
/**
* Handle corner case of having an RPC interface with no RPC functions
*/
Rpc_exception_code _do_dispatch(int opcode,
Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &, Ipc_marshaller &,
Meta::Overload_selector<Meta::Type_list<> >)
{
return 0;
return Rpc_exception_code(Rpc_exception_code::SUCCESS);
}
/**
@ -175,7 +184,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
public:
Rpc_exception_code dispatch(int opcode,
Rpc_exception_code dispatch(Rpc_opcode opcode,
Ipc_unmarshaller &in, Ipc_marshaller &out)
{
return _do_dispatch(opcode, in, out,
@ -197,7 +206,8 @@ class Genode::Rpc_object_base : public Object_pool<Rpc_object_base>::Entry
* \param in incoming message with method arguments
* \param out outgoing message for storing method results
*/
virtual int dispatch(int op, Ipc_unmarshaller &in, Ipc_marshaller &out) = 0;
virtual Rpc_exception_code
dispatch(Rpc_opcode op, Ipc_unmarshaller &in, Ipc_marshaller &out) = 0;
};
@ -215,7 +225,7 @@ struct Genode::Rpc_object : Rpc_object_base, Rpc_dispatcher<RPC_INTERFACE, SERVE
** Server-object interface **
*****************************/
Rpc_exception_code dispatch(int opcode, Ipc_unmarshaller &in, Ipc_marshaller &out)
Rpc_exception_code dispatch(Rpc_opcode opcode, Ipc_unmarshaller &in, Ipc_marshaller &out)
{
return Rpc_dispatcher<RPC_INTERFACE, SERVER>::dispatch(opcode, in, out);
}

View File

@ -11,11 +11,15 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/rpc_server.h>
#include <base/rpc_client.h>
#include <base/blocking.h>
#include <base/env.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
using namespace Genode;
@ -58,7 +62,7 @@ void Rpc_entrypoint::reply_signal_info(Untyped_capability reply_cap,
Untyped_capability last_reply_cap = _ipc_server->caller();
/* direct ipc server to the specified reply destination */
_ipc_server->ret(0);
_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();

View File

@ -18,9 +18,10 @@
/* Genode includes */
#include <base/rpc_server.h>
#include <base/sleep.h>
#include <base/printf.h>
/* base-internal includes */
#include <base/internal/native_connection_state.h>
#include <base/internal/ipc_server.h>
using namespace Genode;
@ -64,13 +65,13 @@ void Rpc_entrypoint::entry()
while (!_exit_handler.exit) {
int opcode = 0;
Rpc_opcode opcode(0);
srv.reply_wait();
srv.extract(opcode);
/* set default return value */
srv.ret(Ipc_client::ERR_INVALID_OBJECT);
srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT));
Pool::apply(srv.badge(), [&] (Rpc_object_base *obj)
{

View File

@ -21,10 +21,9 @@ void Pager_object::wake_up()
{
/* notify pager to wake up faulter */
Msgbuf<16> snd, rcv;
Native_capability pager = cap();
Ipc_client ipc_client(pager, snd, rcv);
ipc_client.insert(this);
ipc_client.call();
Ipc_marshaller marshaller(snd);
marshaller.insert(this);
ipc_call(cap(), snd, rcv, 0);
}

View File

@ -0,0 +1,90 @@
/*
* \brief IPC server
* \author Norman Feske
* \date 2016-03-16
*/
/*
* 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_SERVER_H_
#define _INCLUDE__BASE__INTERNAL__IPC_SERVER_H_
/* Genode includes */
#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;
}
class Genode::Ipc_server : public Ipc_marshaller, public Ipc_unmarshaller,
public 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; }
};
#endif /* _INCLUDE__BASE__INTERNAL__IPC_SERVER_H_ */

View File

@ -17,13 +17,18 @@
#include <timer_session/connection.h>
#include <util/volatile_object.h>
/*
* The Genode headers must be included before any Linux header. Otherwise,
* the 'SUCCESS' macro defined in scsi/scsi_host.h collides with Genode's
* 'Rpc_exception_code::SUCCESS' enum value.
*/
#include "signal.h"
#include "list.h"
#include <extern_c_begin.h>
#include <lx_emul.h>
#include <extern_c_end.h>
#include "signal.h"
#include "list.h"
unsigned long jiffies;

View File

@ -21,12 +21,18 @@
#include <irq_session/connection.h>
#include <util/mmio.h>
/* Emulation */
/*
* The Genode headers must be included before any Linux header. Otherwise,
* the 'SUCCESS' macro defined in scsi/scsi_host.h collides with Genode's
* 'Rpc_exception_code::SUCCESS' enum value.
*/
#include <platform.h>
#include <platform/platform.h>
/* Emulation */
#include <extern_c_begin.h>
#include <lx_emul.h>
#include <extern_c_end.h>
#include <platform.h>
/* Linux */
#include <linux/platform_data/dwc3-exynos.h>