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