diff --git a/repos/base-fiasco/include/base/ipc_msgbuf.h b/repos/base-fiasco/include/base/ipc_msgbuf.h
index 08d553ec0f..acef59d106 100644
--- a/repos/base-fiasco/include/base/ipc_msgbuf.h
+++ b/repos/base-fiasco/include/base/ipc_msgbuf.h
@@ -14,42 +14,60 @@
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
+#include
+
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
+ T &header()
+ {
+ static_assert(sizeof(T) <= sizeof(Headroom),
+ "Header size exceeds message headroom");
+ return *reinterpret_cast(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(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) { }
};
}
diff --git a/repos/base-fiasco/src/base/ipc/ipc.cc b/repos/base-fiasco/src/base/ipc/ipc.cc
index 85c19f553f..55e7e533c6 100644
--- a/repos/base-fiasco/src/base/ipc/ipc.cc
+++ b/repos/base-fiasco/src/base/ipc/ipc.cc
@@ -17,7 +17,7 @@
#include
/* base-internal includes */
-#include
+#include
/* Fiasco includes */
namespace Fiasco {
@@ -26,30 +26,89 @@ namespace Fiasco {
#include
}
+
+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();
+ snd_header.snd_size(snd_msg.data_size());
+
+ Msg_header &rcv_header = rcv_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(&_snd_msg.buf[sizeof(umword_t)]),
- _rcv_msg.msg_start(),
- reinterpret_cast(&rec_badge),
- reinterpret_cast(&_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();
+ 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(&_rcv_msg.buf[0]),
- reinterpret_cast(&_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(&_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();
+ 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(&_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();
+ snd_header.snd_size(_snd_msg.data_size());
+
+ Msg_header &rcv_header = _rcv_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(&_snd_msg.buf[sizeof(umword_t)]),
- &_rcv_cs.caller, _rcv_msg.msg_start(),
- reinterpret_cast(&_rcv_msg.buf[0]),
- reinterpret_cast(&_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(_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() { }
diff --git a/repos/base-foc/include/base/ipc_msgbuf.h b/repos/base-foc/include/base/ipc_msgbuf.h
index 7550d7d2c1..9c44a012da 100644
--- a/repos/base-foc/include/base/ipc_msgbuf.h
+++ b/repos/base-foc/include/base/ipc_msgbuf.h
@@ -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(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) { }
};
}
diff --git a/repos/base-foc/src/base/ipc/ipc.cc b/repos/base-foc/src/base/ipc/ipc.cc
index 0ff0da5251..aa57805814 100644
--- a/repos/base-foc/src/base/ipc/ipc.cc
+++ b/repos/base-foc/src/base/ipc/ipc.cc
@@ -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 /* for 'thread_get_my_native_id()' */
+#include
/* 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(_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(_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() { }
diff --git a/repos/base-foc/src/base/server/server.cc b/repos/base-foc/src/base/server/server.cc
index 5fcb191b11..b338f80659 100644
--- a/repos/base-foc/src/base/server/server.cc
+++ b/repos/base-foc/src/base/server/server.cc
@@ -20,7 +20,7 @@
#include
/* base-internal includes */
-#include
+#include
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;
diff --git a/repos/base-foc/src/core/platform_thread.cc b/repos/base-foc/src/core/platform_thread.cc
index c364d22520..8f7b93b3d5 100644
--- a/repos/base-foc/src/core/platform_thread.cc
+++ b/repos/base-foc/src/core/platform_thread.cc
@@ -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);
}
diff --git a/repos/base-hw/include/base/ipc_msgbuf.h b/repos/base-hw/include/base/ipc_msgbuf.h
index 1f9d3eaf8a..666667bd9f 100644
--- a/repos/base-hw/include/base/ipc_msgbuf.h
+++ b/repos/base-hw/include/base/ipc_msgbuf.h
@@ -16,12 +16,15 @@
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include
+#include
#include
-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.
diff --git a/repos/base-hw/src/base/ipc/ipc.cc b/repos/base-hw/src/base/ipc/ipc.cc
index df8c7c4b99..13f9e20caf 100644
--- a/repos/base-hw/src/base/ipc/ipc.cc
+++ b/repos/base-hw/src/base/ipc/ipc.cc
@@ -24,6 +24,7 @@
/* base-internal includes */
#include
#include
+#include
/* base-hw includes */
#include
@@ -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(
[&] () {
/* 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(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(RPC_OBJECT_ID_SIZE);
- _write_offset = align_natural(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(RPC_OBJECT_ID_SIZE +
- RPC_RETURN_VALUE_SIZE);
-
- /* reset unmarshaller */
- _read_offset = align_natural(RPC_OBJECT_ID_SIZE);
-}
-
-
-void Ipc_server::wait()
-{
- retry(
- [&] () {
-
- /* 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(_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(
[&] () {
- /* 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(_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(RPC_OBJECT_ID_SIZE);
- _write_offset = align_natural(RPC_OBJECT_ID_SIZE);
_snd_msg.reset();
}
diff --git a/repos/base-hw/src/base/server/server.cc b/repos/base-hw/src/base/server/server.cc
index ca65bfeaea..ce3d013348 100644
--- a/repos/base-hw/src/base/server/server.cc
+++ b/repos/base-hw/src/base/server/server.cc
@@ -18,7 +18,7 @@
#include
/* base-internal includes */
-#include
+#include
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) {
diff --git a/repos/base-hw/src/include/base/internal/native_utcb.h b/repos/base-hw/src/include/base/internal/native_utcb.h
index 376761a9da..07ee0b9d76 100644
--- a/repos/base-hw/src/include/base/internal/native_utcb.h
+++ b/repos/base-hw/src/include/base/internal/native_utcb.h
@@ -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(_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()));
}
/**
diff --git a/repos/base-linux/include/base/ipc_msgbuf.h b/repos/base-linux/include/base/ipc_msgbuf.h
index 8a048430f5..2a052b4a7d 100644
--- a/repos/base-linux/include/base/ipc_msgbuf.h
+++ b/repos/base-linux/include/base/ipc_msgbuf.h
@@ -14,8 +14,12 @@
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
+#include
+
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
+ T &header()
+ {
+ static_assert(sizeof(T) <= sizeof(Headroom),
+ "Header size exceeds message headroom");
+ return *reinterpret_cast(_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) { }
};
}
diff --git a/repos/base-linux/src/base/ipc/ipc.cc b/repos/base-linux/src/base/ipc/ipc.cc
index 68dfa3540e..94797908ff 100644
--- a/repos/base-linux/src/base/ipc/ipc.cc
+++ b/repos/base-linux/src/base/ipc/ipc.cc
@@ -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
#include
-#include
+#include
/* Linux includes */
#include
@@ -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();
+ 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();
+
+ 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();
+ 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();
+ 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(_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();
diff --git a/repos/base-nova/include/base/ipc_msgbuf.h b/repos/base-nova/include/base/ipc_msgbuf.h
index 8dde43dddd..b09bb5ee7b 100644
--- a/repos/base-nova/include/base/ipc_msgbuf.h
+++ b/repos/base-nova/include/base/ipc_msgbuf.h
@@ -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(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) { }
};
}
diff --git a/repos/base-nova/src/base/ipc/ipc.cc b/repos/base-nova/src/base/ipc/ipc.cc
index 9c8aeb6a99..c5908b474a 100644
--- a/repos/base-nova/src/base/ipc/ipc.cc
+++ b/repos/base-nova/src/base/ipc/ipc.cc
@@ -14,9 +14,11 @@
/* Genode includes */
#include
#include
-
#include
+/* base-internal includes */
+#include
+
/* NOVA includes */
#include
@@ -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;
}
diff --git a/repos/base-nova/src/base/server/server.cc b/repos/base-nova/src/base/server/server.cc
index 3f6a49b9e2..550c860a73 100644
--- a/repos/base-nova/src/base/server/server.cc
+++ b/repos/base-nova/src/base/server/server.cc
@@ -20,7 +20,7 @@
/* base-internal includes */
#include
-#include
+#include
/* NOVA includes */
#include
@@ -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) {
diff --git a/repos/base-okl4/include/base/ipc_msgbuf.h b/repos/base-okl4/include/base/ipc_msgbuf.h
index 54cc6d8296..e29d0ff212 100644
--- a/repos/base-okl4/include/base/ipc_msgbuf.h
+++ b/repos/base-okl4/include/base/ipc_msgbuf.h
@@ -20,8 +20,13 @@
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
+#include
+#include
+
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) { }
};
}
diff --git a/repos/base-okl4/src/base/ipc/ipc.cc b/repos/base-okl4/src/base/ipc/ipc.cc
index 8aa82fdcaa..d5c2adbfc5 100644
--- a/repos/base-okl4/src/base/ipc/ipc.cc
+++ b/repos/base-okl4/src/base/ipc/ipc.cc
@@ -18,7 +18,7 @@
#include
/* base-internal includes */
-#include
+#include
/* 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(_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(_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() { }
diff --git a/repos/base-pistachio/include/base/ipc_msgbuf.h b/repos/base-pistachio/include/base/ipc_msgbuf.h
index 70a7a72b2a..58049f8850 100644
--- a/repos/base-pistachio/include/base/ipc_msgbuf.h
+++ b/repos/base-pistachio/include/base/ipc_msgbuf.h
@@ -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) { }
};
}
diff --git a/repos/base-pistachio/src/base/ipc/ipc.cc b/repos/base-pistachio/src/base/ipc/ipc.cc
index f1b62495d6..fe7391432f 100644
--- a/repos/base-pistachio/src/base/ipc/ipc.cc
+++ b/repos/base-pistachio/src/base/ipc/ipc.cc
@@ -19,7 +19,7 @@
#include
/* base-internal includes */
-#include
+#include
/* 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;
}
diff --git a/repos/base-sel4/include/base/ipc_msgbuf.h b/repos/base-sel4/include/base/ipc_msgbuf.h
index d38db66b6d..392f0bc16e 100644
--- a/repos/base-sel4/include/base/ipc_msgbuf.h
+++ b/repos/base-sel4/include/base/ipc_msgbuf.h
@@ -20,6 +20,8 @@ namespace Genode {
class Msgbuf_base;
template 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]; }
};
diff --git a/repos/base-sel4/src/base/ipc/ipc.cc b/repos/base-sel4/src/base/ipc/ipc.cc
index b0295e2e3f..8276840394 100644
--- a/repos/base-sel4/src/base/ipc/ipc.cc
+++ b/repos/base-sel4/src/base/ipc/ipc.cc
@@ -21,6 +21,7 @@
/* base-internal includes */
#include
#include
+#include
/* seL4 includes */
#include
@@ -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(this) =
Native_capability(Capability_space::create_ep_cap(*Thread_base::myself()));
-
- _read_offset = _write_offset = sizeof(umword_t);
}
diff --git a/repos/base-sel4/src/base/server/server.cc b/repos/base-sel4/src/base/server/server.cc
index 7e497bfa44..3e7cd26fbc 100644
--- a/repos/base-sel4/src/base/server/server.cc
+++ b/repos/base-sel4/src/base/server/server.cc
@@ -21,7 +21,7 @@
/* base-internal includes */
#include
-#include
+#include
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) {
diff --git a/repos/base/include/base/capability.h b/repos/base/include/base/capability.h
index 2967cfb16e..fdf6ee9b05 100644
--- a/repos/base/include/base/capability.h
+++ b/repos/base/include/base/capability.h
@@ -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
- 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
- void _unmarshal_result(Ipc_client &ipc_client, T &arg,
+ void _unmarshal_result(Ipc_unmarshaller &, T &arg,
Meta::Overload_selector) const;
template
- void _unmarshal_result(Ipc_client &ipc_client, T &arg,
+ void _unmarshal_result(Ipc_unmarshaller &, T &arg,
Meta::Overload_selector) const;
template
- void _unmarshal_result(Ipc_client &, T &,
+ void _unmarshal_result(Ipc_unmarshaller &, T &,
Meta::Overload_selector) const { }
/**
* Read RPC results from the message buffer
*/
template
- 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) const
{
- enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length::Value };
+ enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE
+ - Meta::Length::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());
diff --git a/repos/base/include/base/ipc.h b/repos/base/include/base/ipc.h
index b5d29f5a8a..18816ad05d 100644
--- a/repos/base/include/base/ipc.h
+++ b/repos/base/include/base/ipc.h
@@ -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(_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(_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_ */
diff --git a/repos/base/include/base/rpc.h b/repos/base/include/base/rpc.h
index b28c7e5ec9..6ce8d18af9 100644
--- a/repos/base/include/base/rpc.h
+++ b/repos/base/include/base/rpc.h
@@ -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) { }
+ };
/**
diff --git a/repos/base/include/base/rpc_client.h b/repos/base/include/base/rpc_client.h
index c40abb2934..d03f2ce0d6 100644
--- a/repos/base/include/base/rpc_client.h
+++ b/repos/base/include/base/rpc_client.h
@@ -58,39 +58,39 @@ namespace Genode {
template
template
void Capability::
- _marshal_args(Ipc_client &ipc_client, ATL &args) const
+ _marshal_args(Ipc_marshaller &marshaller, ATL &args) const
{
if (Trait::Rpc_direction::Type::IN)
- ipc_client.insert(args.get());
+ marshaller.insert(args.get());
- _marshal_args(ipc_client, args._2);
+ _marshal_args(marshaller, args._2);
}
template
template
void Capability::
- _unmarshal_result(Ipc_client &ipc_client, T &arg,
+ _unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector) const
{
- ipc_client.extract(arg);
+ unmarshaller.extract(arg);
}
template
template
void Capability::
- _unmarshal_result(Ipc_client &ipc_client, T &arg,
+ _unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector) const
{
- _unmarshal_result(ipc_client, arg, Meta::Overload_selector());
+ _unmarshal_result(unmarshaller, arg, Meta::Overload_selector());
}
template
template
void Capability::
- _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::Type Rpc_dir;
- _unmarshal_result(ipc_client, args.get(), Meta::Overload_selector());
+ _unmarshal_result(unmarshaller, args.get(), Meta::Overload_selector());
/* 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::Value,
REPLY_MSG_SIZE = Rpc_function_msg_size::Value,
- CAP_BY_VALUE = Rpc_function_caps_out::Value };
+ RECEIVE_CAPS = Rpc_function_caps_out::Value };
Msgbuf call_buf;
Msgbuf 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(Meta::Index_of::Value);
+ Rpc_opcode opcode(static_cast(Meta::Index_of::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());
}
}
diff --git a/repos/base/include/base/rpc_server.h b/repos/base/include/base/rpc_server.h
index afe41b052c..9f1a1fddb9 100644
--- a/repos/base/include/base/rpc_server.h
+++ b/repos/base/include/base/rpc_server.h
@@ -24,6 +24,9 @@
#include
namespace Genode {
+
+ class Ipc_server;
+
template class Rpc_dispatcher;
class Rpc_object_base;
template struct Rpc_object;
@@ -86,12 +89,15 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
typename RPC_FUNCTION::Ret_type &ret,
Meta::Overload_selector)
{
- enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length::Value };
+ enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE
+ - Meta::Length::Value };
try {
typedef typename EXC_TL::Tail Exc_tail;
return _do_serve(args, ret,
Meta::Overload_selector());
- } catch (typename EXC_TL::Head) { return EXCEPTION_CODE; }
+ } catch (typename EXC_TL::Head) {
+ return Rpc_exception_code(EXCEPTION_CODE);
+ }
}
template
@@ -100,7 +106,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
Meta::Overload_selector)
{
RPC_FUNCTION::serve(*static_cast(this), args, ret);
- return 0;
+ return Rpc_exception_code(Rpc_exception_code::SUCCESS);
}
template
@@ -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::Value) {
+ if (opcode.value == Index_of::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());
+ Rpc_exception_code
+ exc(_do_serve(args, ret,
+ Overload_selector()));
+
out.insert(ret);
{
@@ -149,21 +157,22 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE
return _do_dispatch(opcode, in, out, Overload_selector());
}
- int _do_dispatch(int opcode, Ipc_unmarshaller &, Ipc_marshaller &,
- Meta::Overload_selector)
+ Rpc_exception_code _do_dispatch(Rpc_opcode opcode,
+ Ipc_unmarshaller &, Ipc_marshaller &,
+ Meta::Overload_selector)
{
- 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 >)
{
- 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::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::dispatch(opcode, in, out);
}
diff --git a/repos/base/src/base/server/common.cc b/repos/base/src/base/server/common.cc
index f918c26dde..b91e271128 100644
--- a/repos/base/src/base/server/common.cc
+++ b/repos/base/src/base/server/common.cc
@@ -11,11 +11,15 @@
* under the terms of the GNU General Public License version 2.
*/
+/* Genode includes */
#include
#include
#include
#include
+/* base-internal includes */
+#include
+
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();
diff --git a/repos/base/src/base/server/server.cc b/repos/base/src/base/server/server.cc
index 8e974cdae6..60a77ac892 100644
--- a/repos/base/src/base/server/server.cc
+++ b/repos/base/src/base/server/server.cc
@@ -18,9 +18,10 @@
/* Genode includes */
#include
#include
+#include
/* base-internal includes */
-#include
+#include
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)
{
diff --git a/repos/base/src/core/pager_object.cc b/repos/base/src/core/pager_object.cc
index fd11e2cf38..ac59dd8f44 100644
--- a/repos/base/src/core/pager_object.cc
+++ b/repos/base/src/core/pager_object.cc
@@ -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);
}
diff --git a/repos/base/src/include/base/internal/ipc_server.h b/repos/base/src/include/base/internal/ipc_server.h
new file mode 100644
index 0000000000..11128421c9
--- /dev/null
+++ b/repos/base/src/include/base/internal/ipc_server.h
@@ -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
+#include
+
+/* base-internal includes */
+#include
+
+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_ */
diff --git a/repos/dde_linux/src/lib/usb/signal/timer.cc b/repos/dde_linux/src/lib/usb/signal/timer.cc
index 7fa97534a7..b35dab5794 100644
--- a/repos/dde_linux/src/lib/usb/signal/timer.cc
+++ b/repos/dde_linux/src/lib/usb/signal/timer.cc
@@ -17,13 +17,18 @@
#include
#include
+/*
+ * 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
#include
#include
-#include "signal.h"
-#include "list.h"
-
unsigned long jiffies;
diff --git a/repos/dde_linux/src/lib/usb/spec/arndale/platform.cc b/repos/dde_linux/src/lib/usb/spec/arndale/platform.cc
index c6296ce1cd..7b80a23bc8 100644
--- a/repos/dde_linux/src/lib/usb/spec/arndale/platform.cc
+++ b/repos/dde_linux/src/lib/usb/spec/arndale/platform.cc
@@ -21,12 +21,18 @@
#include
#include
-/* 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
#include
+
+/* Emulation */
#include
#include
#include
-#include
/* Linux */
#include