diff --git a/repos/base-fiasco/include/base/ipc_msgbuf.h b/repos/base-fiasco/include/base/ipc_msgbuf.h deleted file mode 100644 index acef59d106..0000000000 --- a/repos/base-fiasco/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * \brief Fiasco-specific layout of IPC message buffer - * \author Norman Feske - * \date 2006-06-14 - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -#include - -namespace Genode { - - class Ipc_marshaller; - - /** - * IPC message buffer layout - */ - class Msgbuf_base - { - private: - - size_t const _capacity; - - protected: - - size_t _data_size = 0; - - friend class Ipc_marshaller; - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - struct Headroom { long space[4]; } _headroom; - - char buf[]; - - public: - - template - T &header() - { - static_assert(sizeof(T) <= sizeof(Headroom), - "Header size exceeds message headroom"); - return *reinterpret_cast(buf - sizeof(T)); - } - - unsigned long &word(unsigned i) - { - return reinterpret_cast(buf)[i]; - } - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; }; - - /** - * Return pointer of message data payload - */ - void *data() { return buf; }; - void const *data() const { return buf; }; - - size_t data_size() const { return _data_size; } - }; - - - /** - * Instance of IPC message buffer with specified buffer size - */ - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-fiasco/lib/mk/base-common.mk b/repos/base-fiasco/lib/mk/base-common.mk index bb85cbe9cc..2920278b0e 100644 --- a/repos/base-fiasco/lib/mk/base-common.mk +++ b/repos/base-fiasco/lib/mk/base-common.mk @@ -7,7 +7,7 @@ LIBS += cxx startup SRC_CC += cap_copy.cc -SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc +SRC_CC += ipc/ipc.cc SRC_CC += avl_tree/avl_tree.cc SRC_CC += allocator/slab.cc SRC_CC += allocator/allocator_avl.cc diff --git a/repos/base-fiasco/src/base/ipc/ipc.cc b/repos/base-fiasco/src/base/ipc/ipc.cc index 55e7e533c6..40e5ba0699 100644 --- a/repos/base-fiasco/src/base/ipc/ipc.cc +++ b/repos/base-fiasco/src/base/ipc/ipc.cc @@ -26,6 +26,8 @@ namespace Fiasco { #include } +using namespace Genode; + class Msg_header { @@ -36,54 +38,90 @@ class Msg_header Fiasco::l4_msgdope_t size_dope; Fiasco::l4_msgdope_t send_dope; + public: + /* - * First data word of message, used to transfer the local name of the - * invoked object (when a client calls a server) or the exception code - * (when the server replies). This data word is never fetched from - * memory but transferred via the first short-IPC register. The - * 'protocol_word' is needed as a spacer between the header fields - * define above and the regular message payload.. + * First two data words of message, used to transfer the local name of + * the invoked object (when a client calls a server) or the exception + * code (when the server replies), and the number of capability + * arguments. The kernel does not fetch these data words from memory + * but transfers them via the short-IPC registers. */ Fiasco::l4_umword_t protocol_word; + Fiasco::l4_umword_t num_caps; + + private: + + enum { MAX_CAPS_PER_MSG = Msgbuf_base::MAX_CAPS_PER_MSG }; + + Fiasco::l4_threadid_t _cap_tid [MAX_CAPS_PER_MSG]; + unsigned long _cap_local_name [MAX_CAPS_PER_MSG]; + + size_t _num_msg_words(size_t num_data_words) const + { + size_t const caps_size = sizeof(_cap_tid) + sizeof(_cap_local_name); + + /* + * Account for the transfer of the protocol word, capability count, + * and capability arguments in front of the payload. + */ + return 2 + caps_size/sizeof(Fiasco::l4_umword_t) + num_data_words; + } public: void *msg_start() { return &rcv_fpage; } /** - * Define message size for sending + * Load header fields according to send-message buffer */ - void snd_size(Genode::size_t size) + void prepare_snd_msg(unsigned long protocol, Msgbuf_base const &snd_msg) { using namespace Fiasco; - /* account for the transfer of the protocol word in front of the payload */ - Genode::size_t const snd_words = size/sizeof(l4_umword_t); - send_dope = L4_IPC_DOPE(snd_words + 1, 0); + protocol_word = protocol; + num_caps = min((unsigned)MAX_CAPS_PER_MSG, snd_msg.used_caps()); + + size_t const snd_words = snd_msg.data_size()/sizeof(l4_umword_t); + send_dope = L4_IPC_DOPE(_num_msg_words(snd_words), 0); + + /* reset _cap_tid and _cap_local_name */ + for (unsigned i = 0; i < MAX_CAPS_PER_MSG; i++) { + _cap_tid[i] = L4_INVALID_ID; + _cap_local_name[i] = 0; + } + + for (unsigned i = 0; i < num_caps; i++) { + Native_capability const &cap = snd_msg.cap(i); + _cap_tid[i] = cap.dst(); + _cap_local_name[i] = cap.local_name(); + } } /** - * Define size of receive buffer + * Prepare header for receiving a message */ - void rcv_capacity(Genode::size_t capacity) + void prepare_rcv_msg(Msgbuf_base const &rcv_msg) { using namespace Fiasco; - size_dope = L4_IPC_DOPE(capacity/sizeof(l4_umword_t), 0); + size_t const rcv_max_words = rcv_msg.capacity()/sizeof(l4_umword_t); + + size_dope = L4_IPC_DOPE(_num_msg_words(rcv_max_words), 0); } - void *msg_type(Genode::size_t size) + /** + * Copy received capability arguments into receive message buffer + */ + void extract_caps(Msgbuf_base &rcv_msg) const { - using namespace Fiasco; - - return size <= sizeof(l4_umword_t) ? L4_IPC_SHORT_MSG : msg_start(); + for (unsigned i = 0; i < min((unsigned)MAX_CAPS_PER_MSG, num_caps); i++) + rcv_msg.insert(Native_capability(_cap_tid[i], + _cap_local_name[i])); } }; -using namespace Genode; - - /**************** ** IPC client ** ****************/ @@ -95,156 +133,128 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, using namespace Fiasco; Msg_header &snd_header = snd_msg.header(); - snd_header.snd_size(snd_msg.data_size()); + snd_header.prepare_snd_msg(dst.local_name(), snd_msg); Msg_header &rcv_header = rcv_msg.header(); - rcv_header.rcv_capacity(rcv_msg.capacity()); + rcv_header.prepare_rcv_msg(rcv_msg); l4_msgdope_t ipc_result; - l4_umword_t exception_code = 0; l4_ipc_call(dst.dst(), - snd_header.msg_type(snd_msg.data_size()), - dst.local_name(), - snd_msg.word(0), + snd_header.msg_start(), + snd_header.protocol_word, + snd_header.num_caps, rcv_header.msg_start(), - &exception_code, - &rcv_msg.word(0), + &rcv_header.protocol_word, + &rcv_header.num_caps, L4_IPC_NEVER, &ipc_result); + rcv_header.extract_caps(rcv_msg); + if (L4_IPC_IS_ERROR(ipc_result)) { if (L4_IPC_ERROR(ipc_result) == L4_IPC_RECANCELED) throw Genode::Blocking_canceled(); - PERR("Ipc error %lx", L4_IPC_ERROR(ipc_result)); + PERR("ipc_call error %lx", L4_IPC_ERROR(ipc_result)); throw Genode::Ipc_error(); } - return Rpc_exception_code(exception_code); + return Rpc_exception_code(rcv_header.protocol_word); } /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::_prepare_next_reply_wait() -{ - _reply_needed = true; - _read_offset = _write_offset = 0; -} - - -static umword_t wait(Native_connection_state &rcv_cs, Msgbuf_base &rcv_msg) +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { using namespace Fiasco; - l4_msgdope_t result; - umword_t badge = 0; - - /* - * Wait until we get a proper message and thereby - * ignore receive message cuts on the server-side. - * This error condition should be handled by the - * client. The server does not bother. - */ - do { - Msg_header &rcv_header = rcv_msg.header(); - rcv_header.rcv_capacity(rcv_msg.capacity()); - - l4_ipc_wait(&rcv_cs.caller, rcv_header.msg_start(), - &badge, - &rcv_msg.word(0), - L4_IPC_NEVER, &result); - - if (L4_IPC_IS_ERROR(result)) - PERR("Ipc error %lx", L4_IPC_ERROR(result)); - - } while (L4_IPC_IS_ERROR(result)); - - return badge; -} - - -void Ipc_server::reply() -{ - using namespace Fiasco; - - Msg_header &snd_header = _snd_msg.header(); - snd_header.snd_size(_snd_msg.data_size()); + Msg_header &snd_header = snd_msg.header(); + snd_header.prepare_snd_msg(exc.value, snd_msg); l4_msgdope_t result; - l4_ipc_send(_caller.dst(), snd_header.msg_start(), - _exception_code.value, - _snd_msg.word(0), + l4_ipc_send(caller.dst(), snd_header.msg_start(), + snd_header.protocol_word, + snd_header.num_caps, L4_IPC_SEND_TIMEOUT_0, &result); if (L4_IPC_IS_ERROR(result)) - PERR("Ipc error %lx, ignored", L4_IPC_ERROR(result)); - - _prepare_next_reply_wait(); + PERR("ipc_send error %lx, ignored", L4_IPC_ERROR(result)); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { using namespace Fiasco; - if (_reply_needed) { + l4_msgdope_t ipc_result; - l4_msgdope_t ipc_result; + bool need_to_wait = true; - Msg_header &snd_header = _snd_msg.header(); - snd_header.snd_size(_snd_msg.data_size()); + Msg_header &snd_header = reply_msg.header(); + snd_header.prepare_snd_msg(exc.value, reply_msg); - Msg_header &rcv_header = _rcv_msg.header(); - rcv_header.rcv_capacity(_rcv_msg.capacity()); + request_msg.reset(); + Msg_header &rcv_header = request_msg.header(); + rcv_header.prepare_rcv_msg(request_msg); + + l4_threadid_t caller = L4_INVALID_ID; + + if (last_caller.valid()) { /* * Use short IPC for reply if possible. This is the common case of * returning an integer as RPC result. */ - l4_ipc_reply_and_wait( - _caller.dst(), - snd_header.msg_type(_snd_msg.data_size()), - _exception_code.value, - _snd_msg.word(0), - &_rcv_cs.caller, rcv_header.msg_start(), - &_badge, - &_rcv_msg.word(0), - L4_IPC_SEND_TIMEOUT_0, &ipc_result); + l4_ipc_reply_and_wait(last_caller.dst(), snd_header.msg_start(), + snd_header.protocol_word, + snd_header.num_caps, + &caller, rcv_header.msg_start(), + &rcv_header.protocol_word, + &rcv_header.num_caps, + L4_IPC_SEND_TIMEOUT_0, &ipc_result); + /* + * The error condition could be a message cut (which we want to ignore + * on the server side) or a reply failure (for example, if the caller + * went dead during the call. In both cases, we do not reflect the + * error condition to the user but want to wait for the next proper + * incoming message. + */ if (L4_IPC_IS_ERROR(ipc_result)) { - PERR("Ipc error %lx", L4_IPC_ERROR(ipc_result)); - - /* - * The error conditions could be a message cut (which - * we want to ignore on the server side) or a reply failure - * (for example, if the caller went dead during the call. - * In both cases, we do not reflect the error condition to - * the user but want to wait for the next proper incoming - * message. So let's just wait now. - */ - _badge = wait(_rcv_cs, _rcv_msg); + PERR("ipc_reply_and_wait error %lx", L4_IPC_ERROR(ipc_result)); + } else { + need_to_wait = false; } - } else { - _badge = wait(_rcv_cs, _rcv_msg); } - /* define destination of next reply */ - _caller = Native_capability(_rcv_cs.caller, 0); + while (need_to_wait) { - _prepare_next_reply_wait(); + l4_ipc_wait(&caller, rcv_header.msg_start(), + &rcv_header.protocol_word, + &rcv_header.num_caps, + L4_IPC_NEVER, &ipc_result); + + if (L4_IPC_IS_ERROR(ipc_result)) { + PERR("ipc_wait error %lx", L4_IPC_ERROR(ipc_result)); + } else { + need_to_wait = false; + } + }; + + rcv_header.extract_caps(request_msg); + + return Rpc_request(Native_capability(caller, 0), rcv_header.protocol_word); } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) -: - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), - Native_capability(Fiasco::l4_myself(), 0), - _rcv_cs(cs) -{ } +Ipc_server::Ipc_server() : Native_capability(Fiasco::l4_myself(), 0) { } Ipc_server::~Ipc_server() { } diff --git a/repos/base-fiasco/src/core/pager_object.cc b/repos/base-fiasco/src/core/pager_object.cc new file mode 100644 index 0000000000..f04c0cc964 --- /dev/null +++ b/repos/base-fiasco/src/core/pager_object.cc @@ -0,0 +1,50 @@ +/* + * \brief Kernel-specific RM-faulter wake-up mechanism + * \author Norman Feske + * \date 2016-04-12 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* core includes */ +#include + +/* Fiasco includes */ +namespace Fiasco { +#include +#include +#include +} + +using namespace Genode; + + +void Pager_object::wake_up() +{ + using namespace Fiasco; + + /* kernel-defined message header */ + struct { + l4_fpage_t rcv_fpage; /* unused */ + l4_msgdope_t size_dope = L4_IPC_DOPE(0, 0); + l4_msgdope_t send_dope = L4_IPC_DOPE(0, 0); + } rcv_header; + + l4_msgdope_t ipc_result; + l4_umword_t dummy = 0; + l4_ipc_call(cap().dst(), L4_IPC_SHORT_MSG, + 0, /* fault address */ + (l4_umword_t)this, /* instruction pointer */ + &rcv_header, &dummy, &dummy, L4_IPC_NEVER, &ipc_result); +} + + +void Pager_object::unresolved_page_fault_occurred() +{ + state.unresolved_page_fault = true; +} diff --git a/repos/base-fiasco/src/core/target.inc b/repos/base-fiasco/src/core/target.inc index 4fcc7096b0..a087fb25a7 100644 --- a/repos/base-fiasco/src/core/target.inc +++ b/repos/base-fiasco/src/core/target.inc @@ -64,7 +64,6 @@ vpath trace_session_component.cc $(GEN_CORE_DIR) vpath dataspace_component.cc $(GEN_CORE_DIR) vpath dump_alloc.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) -vpath pager_object.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) vpath core_printf.cc $(BASE_DIR)/src/base/console vpath %.cc $(REP_DIR)/src/core diff --git a/repos/base-fiasco/src/include/base/internal/native_connection_state.h b/repos/base-fiasco/src/include/base/internal/native_connection_state.h deleted file mode 100644 index f3a16e317d..0000000000 --- a/repos/base-fiasco/src/include/base/internal/native_connection_state.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * \brief Connection state - * \author Norman Feske - * \date 2016-03-03 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ -#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ - -/* Genode includes */ -#include - -/* Fiasco includes */ -namespace Fiasco { -#include -} - -namespace Genode { struct Native_connection_state; } - - -struct Genode::Native_connection_state -{ - Fiasco::l4_threadid_t caller; -}; - - -#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */ diff --git a/repos/base-foc/include/base/ipc_msgbuf.h b/repos/base-foc/include/base/ipc_msgbuf.h deleted file mode 100644 index 9c44a012da..0000000000 --- a/repos/base-foc/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * \brief IPC message buffer layout for Fiasco.OC - * \author Stefan Kalkowski - * \date 2010-11-30 - * - * On Fiasco.OC, IPC is used to transmit plain data and capabilities. - * Therefore the message buffer contains both categories of payload. - */ - -/* - * Copyright (C) 2010-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -/* Genode includes */ -#include - -/* Fiasco.OC includes */ -namespace Fiasco { -#include -#include -} - -namespace Genode { - - class Ipc_marshaller; - - class Msgbuf_base - { - public: - - enum { MAX_CAP_ARGS_LOG2 = 2, MAX_CAP_ARGS = 1 << MAX_CAP_ARGS_LOG2 }; - - protected: - - friend class Ipc_marshaller; - - size_t const _capacity; - - size_t _data_size = 0; - - /** - * Number of capability selectors to send. - */ - size_t _snd_cap_sel_cnt = 0; - - /** - * Capability selectors to delegate. - */ - addr_t _snd_cap_sel[MAX_CAP_ARGS]; - - /** - * Base of capability receive window. - */ - Cap_index* _rcv_idx_base = nullptr; - - /** - * Read counter for unmarshalling portal capability selectors - */ - addr_t _rcv_cap_sel_cnt = 0; - - unsigned long _label = 0; - - char _msg_start[]; /* symbol marks start of message */ - - /** - * Constructor - */ - Msgbuf_base(size_t capacity) - : - _capacity(capacity), - _rcv_idx_base(cap_idx_alloc()->alloc_range(MAX_CAP_ARGS)) - { - rcv_reset(); - snd_reset(); - } - - public: - - ~Msgbuf_base() - { - cap_idx_alloc()->free(_rcv_idx_base, MAX_CAP_ARGS); - } - - /* - * Begin of actual message buffer - */ - char buf[]; - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; }; - - /** - * Return pointer of message data payload - */ - void *data() { return &_msg_start[0]; }; - void const *data() const { return &_msg_start[0]; }; - - size_t data_size() const { return _data_size; } - - unsigned long &word(unsigned i) - { - return reinterpret_cast(buf)[i]; - } - - /** - * Reset portal capability selector payload - */ - void snd_reset() { _snd_cap_sel_cnt = 0; } - - /** - * Append capability selector to message buffer - */ - bool snd_append_cap_sel(addr_t cap_sel) - { - if (_snd_cap_sel_cnt >= MAX_CAP_ARGS) - return false; - - _snd_cap_sel[_snd_cap_sel_cnt++] = cap_sel; - return true; - } - - /** - * Return number of marshalled capability selectors - */ - size_t snd_cap_sel_cnt() const { return _snd_cap_sel_cnt; } - - /** - * Return capability selector to send. - * - * \param i index (0 ... 'snd_cap_sel_cnt()' - 1) - * \return capability selector, or 0 if index is invalid - */ - addr_t snd_cap_sel(unsigned i) const { - return i < _snd_cap_sel_cnt ? _snd_cap_sel[i] : 0; } - - /** - * Return address of capability receive window. - */ - addr_t rcv_cap_sel_base() { return _rcv_idx_base->kcap(); } - - /** - * Reset capability receive window - */ - void rcv_reset() { _rcv_cap_sel_cnt = 0; } - - /** - * Return next received capability selector. - * - * \return capability selector, or 0 if index is invalid - */ - addr_t rcv_cap_sel() { - return rcv_cap_sel_base() + _rcv_cap_sel_cnt++ * Fiasco::L4_CAP_SIZE; } - - void label(unsigned long label) { _label = label; } - unsigned long label() { return _label & (~0UL << 2); } - }; - - - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-foc/include/foc/native_thread.h b/repos/base-foc/include/foc/native_thread.h index c293885630..fe624f9159 100644 --- a/repos/base-foc/include/foc/native_thread.h +++ b/repos/base-foc/include/foc/native_thread.h @@ -20,6 +20,7 @@ /* Genode includes */ #include +#include /* Fiasco.OC includes */ namespace Fiasco { @@ -32,6 +33,9 @@ struct Genode::Native_thread { Fiasco::l4_cap_idx_t kcap = 0; + /* receive window for capability selectors received at the server side */ + Receive_window rcv_window; + Native_thread() { } explicit Native_thread(Fiasco::l4_cap_idx_t kcap) : kcap(kcap) { } }; diff --git a/repos/base-foc/include/foc/receive_window.h b/repos/base-foc/include/foc/receive_window.h new file mode 100644 index 0000000000..587eae26d8 --- /dev/null +++ b/repos/base-foc/include/foc/receive_window.h @@ -0,0 +1,65 @@ +/* + * \brief Receive window for capability selectors + * \author Norman Feske + * \date 2016-03-22 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__FOC__RECEIVE_WINDOW_H_ +#define _INCLUDE__FOC__RECEIVE_WINDOW_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Genode { struct Receive_window; } + + +class Genode::Receive_window +{ + private: + + /** + * Base of capability receive window. + */ + Cap_index* _rcv_idx_base = nullptr; + + enum { MAX_CAPS_PER_MSG = Msgbuf_base::MAX_CAPS_PER_MSG }; + + public: + + Receive_window() { } + + ~Receive_window() + { + if (_rcv_idx_base) + cap_idx_alloc()->free(_rcv_idx_base, MAX_CAPS_PER_MSG); + } + + void init() + { + _rcv_idx_base = cap_idx_alloc()->alloc_range(MAX_CAPS_PER_MSG); + } + + /** + * Return address of capability receive window + */ + addr_t rcv_cap_sel_base() { return _rcv_idx_base->kcap(); } + + /** + * Return received selector with index i + * + * \return capability selector, or 0 if index is invalid + */ + addr_t rcv_cap_sel(unsigned i) { + return rcv_cap_sel_base() + i*Fiasco::L4_CAP_SIZE; } +}; + +#endif /* _INCLUDE__FOC__RECEIVE_WINDOW_H_ */ diff --git a/repos/base-foc/include/signal_source/client.h b/repos/base-foc/include/signal_source/client.h index aa8b42cbd0..72268b37a8 100644 --- a/repos/base-foc/include/signal_source/client.h +++ b/repos/base-foc/include/signal_source/client.h @@ -89,15 +89,23 @@ namespace Genode { { using namespace Fiasco; - /* block on semaphore, will be unblocked if signal is available */ - l4_irq_receive(_sem.dst(), L4_IPC_NEVER); + Signal signal; + do { - /* - * Now that the server has unblocked the semaphore, we are sure - * that there is a signal pending. The following 'wait_for_signal' - * request will be immediately answered. - */ - return call(); + /* block on semaphore until signal context was submitted */ + l4_irq_receive(_sem.dst(), L4_IPC_NEVER); + + /* + * The following request will return immediately and either + * return a valid or a null signal. The latter may happen in + * the case a submitted signal context was destroyed (by the + * submitter) before we have a chance to raise our request. + */ + signal = call(); + + } while (!signal.imprint()); + + return signal; } }; } diff --git a/repos/base-foc/src/base/ipc/ipc.cc b/repos/base-foc/src/base/ipc/ipc.cc index aa57805814..0b7814e06a 100644 --- a/repos/base-foc/src/base/ipc/ipc.cc +++ b/repos/base-foc/src/base/ipc/ipc.cc @@ -45,58 +45,11 @@ using namespace Genode; using namespace Fiasco; -/***************************** - ** IPC marshalling support ** - *****************************/ - -void Ipc_marshaller::insert(Native_capability const &cap) -{ - if (cap.valid()) { - if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst()))) { - insert(0UL); - return; - } - } - - /* transfer capability id */ - insert(cap.local_name()); - - /* only transfer kernel-capability if it's a valid one */ - if (cap.valid()) - _snd_msg.snd_append_cap_sel(cap.dst()); - - ASSERT(!cap.valid() || - l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())), - "Send invalid cap"); -} - - -void Ipc_unmarshaller::extract(Native_capability &cap) -{ - long value = 0; - - /* extract capability id from message buffer */ - extract(value); - - /* if id is zero an invalid capability was transfered */ - if (!value) { - cap = Native_capability(); - return; - } - - /* try to insert received capability in the map and return it */ - cap = Native_capability(cap_map()->insert_map(value, _rcv_msg.rcv_cap_sel())); -} - - /*************** ** Utilities ** ***************/ -enum Debug { - DEBUG_MSG = 1, - HALT_ON_ERROR = 0 -}; +enum Debug { DEBUG_MSG = 1, HALT_ON_ERROR = 0 }; static inline bool ipc_error(l4_msgtag_t tag, bool print) @@ -116,39 +69,110 @@ static inline bool ipc_error(l4_msgtag_t tag, bool print) } +enum { INVALID_BADGE = ~0UL }; + + +/** + * Representation of a capability during UTCB marshalling/unmarshalling + */ +struct Cap_info +{ + bool valid = false; + unsigned long sel = 0; + unsigned long badge = 0; +}; + + /** * Copy message registers from UTCB to destination message buffer * * \return protocol word (local name or exception code) */ -static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, Msgbuf_base &rcv_msg) +static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, + Receive_window &rcv_window, + Msgbuf_base &rcv_msg) { - unsigned const num_msg_words = l4_msgtag_words(tag); - unsigned const num_cap_sel = l4_msgtag_items(tag); + unsigned num_msg_words = l4_msgtag_words(tag); - /* each message has at least the protocol word */ - if (num_msg_words < 2 && num_cap_sel == 0) + l4_mword_t const *msg_words = (l4_mword_t const *)l4_utcb_mr(); + + /* each message has at least the protocol word and the capability count */ + if (num_msg_words < 2) return 0; - /* the first message word is reserved for the protocol word */ - unsigned num_data_msg_words = num_msg_words - 1; + /* read badge / exception code from first message word */ + unsigned long const protocol_word = *msg_words++; - if ((num_data_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) { - if (DEBUG_MSG) - outstring("receive message buffer too small"); - num_data_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t); + /* read number of capability arguments from second message word */ + unsigned long const num_caps = min(*msg_words, Msgbuf_base::MAX_CAPS_PER_MSG); + msg_words++; + + num_msg_words -= 2; + if (num_caps > 0 && num_msg_words < num_caps) { + outstring("unexpected end of message, capability info missing\n"); + return 0; } - /* read protocol word from first UTCB message register */ - unsigned long const protocol_word = l4_utcb_mr()->mr[0]; + /* + * Extract capabilities + * + * The badges are stored in the subsequent message registers. For each + * valid badge, we expect one capability selector to be present in the + * receive window. The content of the receive window is tracked via + * 'sel_idx'. If we encounter an invalid badge, the sender specified + * an invalid capabilty as argument. + */ + unsigned const num_cap_sel = l4_msgtag_items(tag); + + Cap_info caps[num_caps]; + + for (unsigned i = 0, sel_idx = 0; i < num_caps; i++) { + + unsigned long const badge = *msg_words++; + + if (badge == INVALID_BADGE) + continue; + + /* received a delegated capability */ + if (sel_idx == num_cap_sel) { + outstring("missing capability selector in message\n"); + break; + } + + caps[i].badge = badge; + caps[i].valid = true; + caps[i].sel = rcv_window.rcv_cap_sel(sel_idx++); + } + num_msg_words -= num_caps; + + /* the remainder of the message contains the regular data payload */ + if ((num_msg_words)*sizeof(l4_mword_t) > rcv_msg.capacity()) { + if (DEBUG_MSG) + outstring("receive message buffer too small\n"); + num_msg_words = rcv_msg.capacity()/sizeof(l4_mword_t); + } /* read message payload beginning from the second UTCB message register */ - l4_mword_t *src = (l4_mword_t *)l4_utcb_mr() + 1; l4_mword_t *dst = (l4_mword_t *)rcv_msg.data(); - for (unsigned i = 0; i < num_data_msg_words; i++) - *dst++ = *src++; + for (unsigned i = 0; i < num_msg_words; i++) + *dst++ = *msg_words++; - rcv_msg.rcv_reset(); + rcv_msg.data_size(sizeof(l4_mword_t)*num_msg_words); + + /* + * Insert received capability selectors into cap map. + * + * Note that this operation pollutes the UTCB. Therefore we must perform + * it not before the entire message content is extracted. + */ + for (unsigned i = 0; i < num_caps; i++) { + if (caps[i].valid) { + rcv_msg.insert(Native_capability(cap_map()->insert_map(caps[i].badge, + caps[i].sel))); + } else { + rcv_msg.insert(Native_capability()); + } + } return protocol_word; } @@ -164,31 +188,76 @@ static unsigned long extract_msg_from_utcb(l4_msgtag_t tag, Msgbuf_base &rcv_msg static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg, unsigned long protocol_word) { - unsigned const num_data_words = snd_msg.data_size() / sizeof(l4_mword_t); - unsigned const num_msg_words = num_data_words + 1; - unsigned const num_cap_sel = snd_msg.snd_cap_sel_cnt(); - /* account for message words, local name, and capability arguments */ - if (num_msg_words + 2*num_cap_sel > L4_UTCB_GENERIC_DATA_SIZE) { - if (DEBUG_MSG) - outstring("receive message buffer too small"); + unsigned const num_data_words = snd_msg.data_size() / sizeof(l4_mword_t); + unsigned const num_caps = snd_msg.used_caps(); + + /* validate capabilities present in the message buffer */ + for (unsigned i = 0; i < num_caps; i++) { + + Native_capability &cap = snd_msg.cap(i); + if (!cap.valid()) + continue; + + if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst()))) + cap = Native_capability(); + } + + /* + * Obtain capability info from message buffer + * + * This step must be performed prior any write operation to the UTCB + * because the 'Genode::Capability' operations may indirectly trigger + * system calls, which pollute the UTCB. + */ + Cap_info caps[num_caps]; + for (unsigned i = 0; i < num_caps; i++) { + Native_capability const &cap = snd_msg.cap(i); + if (cap.valid()) { + caps[i].valid = true; + caps[i].badge = cap.local_name(); + caps[i].sel = cap.dst(); + } + } + + /* + * The message consists of a protocol word, the capability count, one badge + * value per capability, and the data payload. + */ + unsigned const num_msg_words = 2 + num_caps + num_data_words; + + if (num_msg_words > L4_UTCB_GENERIC_DATA_SIZE) { + outstring("receive message buffer too small\n"); throw Ipc_error(); } - /* copy badge / exception code to UTCB message register */ - l4_utcb_mr()->mr[0] = protocol_word; + l4_mword_t *msg_words = (l4_mword_t *)l4_utcb_mr(); + + *msg_words++ = protocol_word; + *msg_words++ = num_caps; + + unsigned num_cap_sel = 0; + + for (unsigned i = 0; i < num_caps; i++) { + + Native_capability const &cap = snd_msg.cap(i); + + /* store badge as normal message word */ + *msg_words++ = caps[i].valid ? caps[i].badge : INVALID_BADGE; + + /* setup flexpage for valid capability to delegate */ + if (caps[i].valid) { + unsigned const idx = num_msg_words + 2*num_cap_sel; + l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/; + l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(caps[i].sel, + 0, L4_FPAGE_RWX).raw; + num_cap_sel++; + } + } /* store message data into UTCB message registers */ for (unsigned i = 0; i < num_data_words; i++) - l4_utcb_mr()->mr[i + 1] = snd_msg.word(i); - - /* setup flexpages of capabilities to send */ - for (unsigned i = 0; i < num_cap_sel; i++) { - unsigned const idx = num_msg_words + 2*i; - l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/; - l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(snd_msg.snd_cap_sel(i), - 0, L4_FPAGE_RWX).raw; - } + *msg_words++ = snd_msg.word(i); return l4_msgtag(0, num_msg_words, num_cap_sel, 0); } @@ -202,11 +271,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, size_t rcv_caps) { + Receive_window rcv_window; + rcv_window.init(); + rcv_msg.reset(); + /* copy call message to the UTCBs message registers */ l4_msgtag_t const call_tag = copy_msgbuf_to_utcb(snd_msg, dst.local_name()); - addr_t rcv_cap_sel = rcv_msg.rcv_cap_sel_base(); - for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) { + addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base(); + for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) { l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP; rcv_cap_sel += L4_CAP_SIZE; } @@ -220,106 +293,86 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, if (ipc_error(reply_tag, DEBUG_MSG)) throw Genode::Ipc_error(); - return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_msg)); + return Rpc_exception_code(extract_msg_from_utcb(reply_tag, rcv_window, rcv_msg)); } /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::_prepare_next_reply_wait() +static bool badge_matches_label(unsigned long badge, unsigned long label) { - _reply_needed = true; - _read_offset = _write_offset = 0; - - _snd_msg.snd_reset(); + return badge == (label & (~0UL << 2)); } -static unsigned long wait(Msgbuf_base &rcv_msg) +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { - addr_t rcv_cap_sel = rcv_msg.rcv_cap_sel_base(); - for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) { - l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP; - rcv_cap_sel += L4_CAP_SIZE; - } - l4_utcb_br()->bdr = 0; - - l4_msgtag_t tag; - do { - l4_umword_t label = 0; - tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); - rcv_msg.label(label); - } while (ipc_error(tag, DEBUG_MSG)); - - /* copy message from the UTCBs message registers to the receive buffer */ - return extract_msg_from_utcb(tag, rcv_msg); -} - - -void Ipc_server::reply() -{ - l4_msgtag_t tag = copy_msgbuf_to_utcb(_snd_msg, _exception_code.value); + l4_msgtag_t tag = copy_msgbuf_to_utcb(snd_msg, exc.value); tag = l4_ipc_send(L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_SEND_TIMEOUT_0); ipc_error(tag, DEBUG_MSG); - _snd_msg.snd_reset(); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { - if (_reply_needed) { - addr_t rcv_cap_sel = _rcv_msg.rcv_cap_sel_base(); - for (int i = 0; i < Msgbuf_base::MAX_CAP_ARGS; i++) { + Receive_window &rcv_window = Thread_base::myself()->native_thread().rcv_window; + + for (;;) { + + request_msg.reset(); + + /* prepare receive window in UTCB */ + addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base(); + for (int i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) { l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP; rcv_cap_sel += L4_CAP_SIZE; } - l4_utcb_br()->bdr &= ~L4_BDR_OFFSET_MASK; - l4_umword_t label = 0; + l4_msgtag_t request_tag; + l4_umword_t label = 0; /* kernel-protected label of invoked capability */ - l4_msgtag_t const reply_tag = - copy_msgbuf_to_utcb(_snd_msg, _exception_code.value); + if (exc.value != Rpc_exception_code::INVALID_OBJECT) { - l4_msgtag_t const request_tag = - l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, - L4_IPC_SEND_TIMEOUT_0); + l4_msgtag_t const reply_tag = copy_msgbuf_to_utcb(reply_msg, exc.value); - _rcv_msg.label(label); - - if (ipc_error(request_tag, false)) { - /* - * The error conditions could be a message cut (which - * we want to ignore on the server side) or a reply failure - * (for example, if the caller went dead during the call. - * In both cases, we do not reflect the error condition to - * the user but want to wait for the next proper incoming - * message. So let's just wait now. - */ - _badge = wait(_rcv_msg); + request_tag = l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, L4_IPC_SEND_TIMEOUT_0); } else { - - /* copy request message from the UTCBs message registers */ - _badge = extract_msg_from_utcb(request_tag, _rcv_msg); + request_tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); } - } else - _badge = wait(_rcv_msg); - _prepare_next_reply_wait(); + if (ipc_error(request_tag, false)) + continue; + + /* copy request message from the UTCBs message registers */ + unsigned long const badge = + extract_msg_from_utcb(request_tag, rcv_window, request_msg); + + /* ignore request if we detect a forged badge */ + if (!badge_matches_label(badge, label)) { + outstring("badge does not match label, ignoring request\n"); + continue; + } + + return Rpc_request(Native_capability(), badge); + } } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) +Ipc_server::Ipc_server() : - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), - Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]), - _rcv_cs(cs) -{ } + Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]) +{ + Thread_base::myself()->native_thread().rcv_window.init(); +} Ipc_server::~Ipc_server() { } diff --git a/repos/base-foc/src/base/server/server.cc b/repos/base-foc/src/base/server/server.cc deleted file mode 100644 index b338f80659..0000000000 --- a/repos/base-foc/src/base/server/server.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * \brief Default version of platform-specific part of server framework - * \author Norman Feske - * \author Stefan Kalkowski - * \date 2006-05-12 - * - * This version is suitable for platforms similar to L4. Each platform - * for which this implementation is not suited contains a platform- - * specific version in its respective 'base-' repository. - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode includes */ -#include - -/* base-internal includes */ -#include - -using namespace Genode; - - -/*********************** - ** Server entrypoint ** - ***********************/ - -Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) -{ - Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap); - - /* add server object to object pool */ - obj->cap(new_obj_cap); - insert(obj); - - /* return capability that uses the object id as badge */ - return new_obj_cap; -} - - -void Rpc_entrypoint::entry() -{ - Native_connection_state cs; - Ipc_server srv(cs, _snd_buf, _rcv_buf); - _ipc_server = &srv; - _cap = srv; - _cap_valid.unlock(); - - /* - * Now, the capability of the server activation is initialized - * an can be passed around. However, the processing of capability - * invocations should not happen until activation-using server - * is completely initialized. Thus, we wait until the activation - * gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'. - */ - _delay_start.lock(); - - while (!_exit_handler.exit) { - - Rpc_opcode opcode(0); - - srv.reply_wait(); - srv.extract(opcode); - - /* set default return value */ - srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT)); - - apply(srv.badge(), [&] (Rpc_object_base *obj) { - if (!obj) return; - - try { - srv.ret(obj->dispatch(opcode, srv, srv)); - } catch(Blocking_canceled&) { } - }); - } - - /* answer exit call, thereby wake up '~Rpc_entrypoint' */ - srv.reply(); - - /* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */ - _delay_exit.lock(); -} diff --git a/repos/base-foc/src/core/pager_object.cc b/repos/base-foc/src/core/pager_object.cc new file mode 100644 index 0000000000..4eb5001179 --- /dev/null +++ b/repos/base-foc/src/core/pager_object.cc @@ -0,0 +1,42 @@ +/* + * \brief Kernel-specific RM-faulter wake-up mechanism + * \author Norman Feske + * \date 2016-04-12 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* core includes */ +#include + +/* Fiasco.OC includes */ +namespace Fiasco { +#include +} + +using namespace Genode; + + +void Pager_object::wake_up() +{ + using namespace Fiasco; + + /* + * Issue IPC to pager, transmitting the pager-object pointer as 'IP'. + */ + l4_utcb_mr()->mr[0] = 0; /* fault address */ + l4_utcb_mr()->mr[1] = (l4_umword_t)this; /* instruction pointer */ + + l4_ipc_call(cap().dst(), l4_utcb(), l4_msgtag(0, 2, 0, 0), L4_IPC_NEVER); +} + + +void Pager_object::unresolved_page_fault_occurred() +{ + state.unresolved_page_fault = true; +} diff --git a/repos/base-foc/src/core/platform_thread.cc b/repos/base-foc/src/core/platform_thread.cc index a023386f9b..daf6309360 100644 --- a/repos/base-foc/src/core/platform_thread.cc +++ b/repos/base-foc/src/core/platform_thread.cc @@ -140,8 +140,7 @@ void Platform_thread::resume() /* Send a message to the exception handler, to unblock the client */ Msgbuf<16> snd, rcv; - Ipc_marshaller marshaller(snd); - marshaller.insert(_pager_obj); + snd.insert(_pager_obj); ipc_call(_pager_obj->cap(), snd, rcv, 0); } diff --git a/repos/base-foc/src/core/target.inc b/repos/base-foc/src/core/target.inc index a082af0240..7e8d67f097 100644 --- a/repos/base-foc/src/core/target.inc +++ b/repos/base-foc/src/core/target.inc @@ -63,7 +63,6 @@ vpath rm_session_component.cc $(GEN_CORE_DIR) vpath rom_session_component.cc $(GEN_CORE_DIR) vpath trace_session_component.cc $(GEN_CORE_DIR) vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) -vpath pager_object.cc $(GEN_CORE_DIR) vpath core_printf.cc $(BASE_DIR)/src/base/console vpath %.cc $(REP_DIR)/src/core vpath %.cc $(REP_DIR)/src/base/thread diff --git a/repos/base-hw/include/base/ipc_msgbuf.h b/repos/base-hw/include/base/ipc_msgbuf.h deleted file mode 100644 index 666667bd9f..0000000000 --- a/repos/base-hw/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * \brief IPC message buffers - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-01-03 - */ - -/* - * Copyright (C) 2012-2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -#include -#include -#include - -namespace Genode { - - class Native_utcb; - - class Ipc_marshaller; - - /** - * IPC message buffer layout - */ - class Msgbuf_base; - - /** - * Instance of IPC message buffer with specified buffer size - * - * 'Msgbuf_base' must be the last class this class inherits from. - */ - template class Msgbuf; -} - - -class Genode::Msgbuf_base -{ - public: - - enum { MAX_CAP_ARGS = 4 }; - - private: - - friend class Native_utcb; - friend class Ipc_marshaller; - - size_t const _capacity; /* buffer size in bytes */ - size_t _data_size = 0; /* marshalled data in bytes */ - Native_capability _caps[MAX_CAP_ARGS]; /* capability buffer */ - size_t _snd_cap_cnt = 0; /* capability counter */ - size_t _rcv_cap_cnt = 0; /* capability counter */ - - public: - - /************************************************* - ** 'buf' must be the last member of this class ** - *************************************************/ - - char buf[]; /* begin of actual message buffer */ - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - void const * base() const { return &buf; } - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; } - - /** - * Return pointer of message data payload - */ - void *data() { return &buf[0]; } - void const *data() const { return &buf[0]; } - - size_t data_size() const { return _data_size; } - - /** - * Reset capability buffer. - */ - void reset() - { - _snd_cap_cnt = 0; - _rcv_cap_cnt = 0; - } - - /** - * Return how many capabilities are accepted by this message buffer - */ - size_t cap_rcv_window() { return _rcv_cap_cnt; } - - /** - * Set how many capabilities are accepted by this message buffer - */ - void cap_rcv_window(size_t cnt) { _rcv_cap_cnt = cnt; } - - /** - * Add capability to buffer - */ - void cap_add(Native_capability const &cap) - { - if (_snd_cap_cnt < MAX_CAP_ARGS) - _caps[_snd_cap_cnt++] = cap; - } - - /** - * Return last capability from buffer. - */ - Native_capability cap_get() - { - return (_rcv_cap_cnt < _snd_cap_cnt) - ? _caps[_rcv_cap_cnt++] : Native_capability(); - } -}; - - -template -class Genode::Msgbuf : public Genode::Msgbuf_base -{ - public: - - /************************************************** - ** 'buf' must be the first member of this class ** - **************************************************/ - - char buf[BUF_SIZE]; - - /** - * Constructor - */ - Msgbuf() : Msgbuf_base(BUF_SIZE) { } -}; - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-hw/src/base/ipc/ipc.cc b/repos/base-hw/src/base/ipc/ipc.cc index 13f9e20caf..8f3ee42414 100644 --- a/repos/base-hw/src/base/ipc/ipc.cc +++ b/repos/base-hw/src/base/ipc/ipc.cc @@ -35,16 +35,55 @@ namespace Hw { extern Genode::Untyped_capability _main_thread_cap; } using namespace Genode; -/***************************** - ** IPC marshalling support ** - *****************************/ +/** + * Copy data from the message buffer to UTCB + */ +static inline void copy_msg_to_utcb(Msgbuf_base const &snd_msg, Native_utcb &utcb) +{ + /* copy capabilities */ + size_t const num_caps = min((size_t)Msgbuf_base::MAX_CAPS_PER_MSG, + snd_msg.used_caps()); -void Ipc_marshaller::insert(Native_capability const &cap) { - _snd_msg.cap_add(cap); } + for (unsigned i = 0; i < num_caps; i++) + utcb.cap_set(i, snd_msg.cap(i).dst()); + + utcb.cap_cnt(num_caps); + + /* copy data payload */ + size_t const data_size = min(snd_msg.data_size(), + min(snd_msg.capacity(), utcb.capacity())); + + memcpy(utcb.data(), snd_msg.data(), data_size); + + utcb.data_size(data_size); +} -void Ipc_unmarshaller::extract(Native_capability &cap) { - cap = _rcv_msg.cap_get(); } +/** + * Copy data from UTCB to the message buffer + */ +static inline void copy_utcb_to_msg(Native_utcb const &utcb, Msgbuf_base &rcv_msg) +{ + /* copy capabilities */ + size_t const num_caps = min((size_t)Msgbuf_base::MAX_CAPS_PER_MSG, + utcb.cap_cnt()); + + for (unsigned i = 0; i < num_caps; i++) { + rcv_msg.cap(i) = utcb.cap_get(i); + if (rcv_msg.cap(i).valid()) + Kernel::ack_cap(rcv_msg.cap(i).dst()); + } + + rcv_msg.used_caps(num_caps); + + /* copy data payload */ + size_t const data_size = min(utcb.data_size(), + min(utcb.capacity(), rcv_msg.capacity())); + + memcpy(rcv_msg.data(), utcb.data(), data_size); + + rcv_msg.data_size(data_size); +} /**************** @@ -55,23 +94,19 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, size_t rcv_caps) { - rcv_msg.cap_rcv_window(rcv_caps); - Native_utcb &utcb = *Thread_base::myself()->utcb(); retry( [&] () { - /* send request and receive corresponding reply */ - Thread_base::myself()->utcb()->copy_from(snd_msg); + copy_msg_to_utcb(snd_msg, *Thread_base::myself()->utcb()); switch (Kernel::send_request_msg(dst.dst(), - rcv_msg.cap_rcv_window())) { + rcv_caps)) { case -1: throw Blocking_canceled(); case -2: throw Allocator::Out_of_memory(); default: - rcv_msg.reset(); - utcb.copy_to(rcv_msg); + copy_utcb_to_msg(utcb, rcv_msg); } }, @@ -82,30 +117,36 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::reply() +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { - Thread_base::myself()->utcb()->copy_from(_snd_msg); - _snd_msg.reset(); + Native_utcb &utcb = *Thread_base::myself()->utcb(); + copy_msg_to_utcb(snd_msg, utcb); + utcb.exception_code(exc.value); + snd_msg.reset(); Kernel::send_reply_msg(0, false); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { Native_utcb &utcb = *Thread_base::myself()->utcb(); retry( [&] () { int ret = 0; - if (_reply_needed) { - utcb.copy_from(_snd_msg); - utcb.exception_code(_exception_code.value); - ret = Kernel::send_reply_msg(Msgbuf_base::MAX_CAP_ARGS, true); + if (exc.value != Rpc_exception_code::INVALID_OBJECT) { + copy_msg_to_utcb(reply_msg, utcb); + utcb.exception_code(exc.value); + ret = Kernel::send_reply_msg(Msgbuf_base::MAX_CAPS_PER_MSG, true); } else { - ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAP_ARGS); + ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAPS_PER_MSG); } switch (ret) { @@ -116,27 +157,17 @@ void Ipc_server::reply_wait() }, [&] () { upgrade_pd_session_quota(3*4096); }); - _rcv_msg.reset(); - _snd_msg.reset(); + copy_utcb_to_msg(utcb, request_msg); - utcb.copy_to(_rcv_msg); - _badge = utcb.destination(); - - _reply_needed = true; - _read_offset = _write_offset = 0; + return Rpc_request(Native_capability(), utcb.destination()); } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) +Ipc_server::Ipc_server() : - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), Native_capability(Thread_base::myself() ? Thread_base::myself()->native_thread().cap - : Hw::_main_thread_cap), - _rcv_cs(cs) -{ - _snd_msg.reset(); -} + : Hw::_main_thread_cap) +{ } Ipc_server::~Ipc_server() { } diff --git a/repos/base-hw/src/base/server/server.cc b/repos/base-hw/src/base/server/server.cc deleted file mode 100644 index ce3d013348..0000000000 --- a/repos/base-hw/src/base/server/server.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * \brief base-hw specific part of RPC framework - * \author Stefan Kalkowski - * \date 2015-03-05 - */ - -/* - * Copyright (C) 2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode includes */ -#include -#include -#include -#include - -/* base-internal includes */ -#include - -using namespace Genode; - - -/*********************** - ** Server entrypoint ** - ***********************/ - -Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) -{ - Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap); - - /* add server object to object pool */ - obj->cap(new_obj_cap); - insert(obj); - - /* return capability that uses the object id as badge */ - return new_obj_cap; -} - - -void Rpc_entrypoint::entry() -{ - Native_connection_state cs; - Ipc_server srv(cs, _snd_buf, _rcv_buf); - _ipc_server = &srv; - _cap = srv; - _cap_valid.unlock(); - - /* - * Now, the capability of the server activation is initialized - * an can be passed around. However, the processing of capability - * invocations should not happen until activation-using server - * is completely initialized. Thus, we wait until the activation - * gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'. - */ - _delay_start.lock(); - - while (!_exit_handler.exit) { - - Rpc_opcode opcode(0); - - srv.reply_wait(); - srv.extract(opcode); - - /* set default return value */ - srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT)); - - /* atomically lookup and lock referenced object */ - apply(srv.badge(), [&] (Rpc_object_base *curr_obj) { - if (!curr_obj) return; - - /* dispatch request */ - try { srv.ret(curr_obj->dispatch(opcode, srv, srv)); } - catch (Blocking_canceled) { } - }); - } - - /* answer exit call, thereby wake up '~Rpc_entrypoint' */ - srv.reply(); - - /* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */ - _delay_exit.lock(); -} diff --git a/repos/base-hw/src/base/signal/signal.cc b/repos/base-hw/src/base/signal/signal.cc index 4767eccfb1..47bbee3836 100644 --- a/repos/base-hw/src/base/signal/signal.cc +++ b/repos/base-hw/src/base/signal/signal.cc @@ -124,7 +124,7 @@ void Signal_receiver::block_for_signal() return; } /* read signal data */ - const void * const utcb = Thread_base::myself()->utcb()->base(); + const void * const utcb = Thread_base::myself()->utcb()->data(); Signal::Data * const data = (Signal::Data *)utcb; Signal_context * const context = data->context; { diff --git a/repos/base-hw/src/core/include/kernel/ipc_node.h b/repos/base-hw/src/core/include/kernel/ipc_node.h index ab28f9baa9..39c96071da 100644 --- a/repos/base-hw/src/core/include/kernel/ipc_node.h +++ b/repos/base-hw/src/core/include/kernel/ipc_node.h @@ -66,7 +66,7 @@ class Kernel::Ipc_node : public Ipc_node_queue::Element Ipc_node_queue _request_queue; /* pre-allocation array for obkject identity references */ - void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAP_ARGS]; + void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG]; inline void copy_msg(Ipc_node * const sender); diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 7012e0a187..ff9ecdcc76 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -70,7 +70,7 @@ void Thread::_await_signal(Signal_receiver * const receiver) void Thread::_receive_signal(void * const base, size_t const size) { assert(_state == AWAITS_SIGNAL); - Genode::memcpy((void*)utcb()->base(), base, size); + Genode::memcpy(utcb()->data(), base, size); _become_active(); } diff --git a/repos/base-hw/src/core/rm_session_support.cc b/repos/base-hw/src/core/rm_session_support.cc index 45c44a0ed0..78723cd147 100644 --- a/repos/base-hw/src/core/rm_session_support.cc +++ b/repos/base-hw/src/core/rm_session_support.cc @@ -48,7 +48,7 @@ void Pager_entrypoint::entry() if (Kernel::await_signal(_cap.dst())) continue; Untyped_capability cap = - (*(Pager_object**)Thread_base::myself()->utcb()->base())->cap(); + (*(Pager_object**)Thread_base::myself()->utcb()->data())->cap(); /* * Synchronize access and ensure that the object is still managed 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 07ee0b9d76..9ce79a8793 100644 --- a/repos/base-hw/src/include/base/internal/native_utcb.h +++ b/repos/base-hw/src/include/base/internal/native_utcb.h @@ -16,6 +16,8 @@ #define _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ /* Genode includes */ +#include +#include #include #include @@ -47,30 +49,37 @@ class Genode::Native_utcb { public: - enum { MAX_CAP_ARGS = Msgbuf_base::MAX_CAP_ARGS}; + enum { MAX_CAP_ARGS = Msgbuf_base::MAX_CAPS_PER_MSG}; enum Offsets { THREAD_MYSELF, PARENT, UTCB_DATASPACE }; private: - Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */ + /* + * Note thats the member variables are sorted from the largest to the + * smallest size to avoid padding. Otherwise, the dimensioning of + * '_data' would not yield a page-sized 'Native_utcb'. + */ + size_t _cap_cnt; /* capability counter */ - size_t _size; /* bytes to transfer */ + size_t _data_size; /* bytes to transfer */ long _exception_code; /* result code of RPC */ Kernel::capid_t _destination; /* invoked object */ - uint8_t _buf[get_page_size() - sizeof(_caps) - - sizeof(_cap_cnt) - sizeof(_size) - - sizeof(_destination) - sizeof(_exception_code)]; + Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */ + uint8_t _data[get_page_size() - sizeof(_caps) - + sizeof(_cap_cnt) - sizeof(_data_size) - + sizeof(_destination) - sizeof(_exception_code)]; public: - Native_utcb& operator= (const Native_utcb &o) + Native_utcb& operator= (const Native_utcb &other) { _cap_cnt = 0; - _size = o._size; - _exception_code = o._exception_code; - _destination = o._destination; - memcpy(_buf, o._buf, _size); + _data_size = min(sizeof(_data), other._data_size); + _exception_code = other._exception_code; + _destination = other._destination; + memcpy(_data, other._data, _data_size); + return *this; } @@ -91,7 +100,7 @@ class Genode::Native_utcb /** * Return the count of capabilities in the UTCB */ - size_t cap_cnt() { return _cap_cnt; } + size_t cap_cnt() const { return _cap_cnt; } /** * Set the count of capabilities in the UTCB @@ -101,41 +110,43 @@ class Genode::Native_utcb /** * Return the start address of the payload data */ - void const * base() const { return &_buf; } + void const *data() const { return &_data[0]; } + void *data() { return &_data[0]; } /** - * Copy data from the message buffer 'snd_msg' to this UTCB + * Return maximum number of bytes for message payload */ - void copy_from(Msgbuf_base const &snd_msg) - { - _size = min(snd_msg.data_size(), sizeof(_buf)); - - _cap_cnt = snd_msg._snd_cap_cnt; - for (unsigned i = 0; i < _cap_cnt; i++) - _caps[i] = snd_msg._caps[i].dst(); - - memcpy(_buf, snd_msg.buf, min(_size, snd_msg.capacity())); - } + size_t capacity() const { return sizeof(_data); } /** - * Copy data from this UTCB to the message buffer 'o' + * Return size of message data in bytes */ - void copy_to(Msgbuf_base &o) - { - o._snd_cap_cnt = _cap_cnt; - for (unsigned i = 0; i < _cap_cnt; i++) { - o._caps[i] = _caps[i]; - if (o._caps[i].valid()) Kernel::ack_cap(o._caps[i].dst()); - } + size_t data_size() const { return _data_size; } - memcpy(o.buf, _buf, min(_size, o.capacity())); + /** + * Define size of message data to be transferred, in bytes + */ + void data_size(size_t data_size) + { + _data_size = min(data_size, sizeof(_data)); } /** * Return the capability id at index 'i' */ - Kernel::capid_t cap_get(unsigned i) { - return (i < _cap_cnt) ? _caps[i] : Kernel::cap_id_invalid(); } + Kernel::capid_t cap_get(unsigned i) const + { + return (i < MAX_CAP_ARGS) ? _caps[i] : Kernel::cap_id_invalid(); + } + + /** + * Set the capability id at index 'i' + */ + void cap_set(unsigned i, Kernel::capid_t cap) + { + if (i < MAX_CAP_ARGS) + _caps[i] = cap; + } /** * Set the capability id 'cap_id' at the next index @@ -144,4 +155,7 @@ class Genode::Native_utcb if (_cap_cnt < MAX_CAP_ARGS) _caps[_cap_cnt++] = cap_id; } }; +static_assert(sizeof(Genode::Native_utcb) == Genode::get_page_size(), + "Native_utcb is not page-sized"); + #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ */ diff --git a/repos/base-linux/include/base/ipc_msgbuf.h b/repos/base-linux/include/base/ipc_msgbuf.h deleted file mode 100644 index 2a052b4a7d..0000000000 --- a/repos/base-linux/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * \brief Linux-specific layout of IPC message buffer - * \author Norman Feske - * \date 2006-06-14 - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -#include - -namespace Genode { - - class Ipc_marshaller; - - /** - * IPC message buffer layout - */ - class Msgbuf_base - { - public: - - enum { MAX_CAPS_PER_MSG = 8 }; - - protected: - - friend class Ipc_marshaller; - - /* - * Capabilities (file descriptors) to be transferred - */ - int _caps[MAX_CAPS_PER_MSG]; - Genode::size_t _used_caps = 0; - Genode::size_t _read_cap_index = 0; - - /** - * Maximum size of plain-data message payload - */ - Genode::size_t const _capacity; - - /** - * Actual size of plain-data message payload - */ - Genode::size_t _data_size = 0; - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - struct Headroom { long space[4]; } _headroom; - - char _msg_start[]; /* symbol marks start of message buffer data */ - - /* - * No member variables are allowed beyond this point! - */ - - public: - - template - 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 - */ - Genode::size_t capacity() const { return _capacity; }; - - /** - * Return pointer of message data payload - */ - void *data() { return &_msg_start[0]; }; - void const *data() const { return &_msg_start[0]; }; - - size_t data_size() const { return _data_size; } - - void reset_caps() { _used_caps = 0; _read_cap_index = 0; } - - bool append_cap(int cap) - { - if (_used_caps == MAX_CAPS_PER_MSG) - return false; - - _caps[_used_caps++] = cap; - return true; - } - - int read_cap() - { - if (_read_cap_index == _used_caps) - return -1; - - return _caps[_read_cap_index++]; - } - - size_t used_caps() const { return _used_caps; } - - int cap(unsigned index) const - { - return index < _used_caps ? _caps[index] : -1; - } - }; - - - /** - * Pump up IPC message buffer to specified buffer size - */ - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-linux/src/base/env/platform_env.cc b/repos/base-linux/src/base/env/platform_env.cc index 8a9aeadc45..12afea271f 100644 --- a/repos/base-linux/src/base/env/platform_env.cc +++ b/repos/base-linux/src/base/env/platform_env.cc @@ -19,7 +19,7 @@ /* base-internal includes */ #include -#include +#include using namespace Genode; @@ -180,24 +180,25 @@ Platform_env::Platform_env() namespace Genode { - Native_connection_state server_socket_pair() + Socket_pair server_socket_pair() { Linux_native_cpu_client native_cpu(env()->cpu_session()->native_cpu()); - Native_connection_state ncs; + Socket_pair socket_pair; Thread_base *thread = Thread_base::myself(); if (thread) { - ncs.server_sd = native_cpu.server_sd(thread->cap()).dst().socket; - ncs.client_sd = native_cpu.client_sd(thread->cap()).dst().socket; + socket_pair.server_sd = native_cpu.server_sd(thread->cap()).dst().socket; + socket_pair.client_sd = native_cpu.client_sd(thread->cap()).dst().socket; + thread->native_thread().socket_pair = socket_pair; } - return ncs; + return socket_pair; } - void destroy_server_socket_pair(Native_connection_state const &ncs) + void destroy_server_socket_pair(Socket_pair socket_pair) { /* close local file descriptor if it is valid */ - if (ncs.server_sd != -1) lx_close(ncs.server_sd); - if (ncs.client_sd != -1) lx_close(ncs.client_sd); + if (socket_pair.server_sd != -1) lx_close(socket_pair.server_sd); + if (socket_pair.client_sd != -1) lx_close(socket_pair.client_sd); } } diff --git a/repos/base-linux/src/base/ipc/ipc.cc b/repos/base-linux/src/base/ipc/ipc.cc index 69ea157076..4b77b680ec 100644 --- a/repos/base-linux/src/base/ipc/ipc.cc +++ b/repos/base-linux/src/base/ipc/ipc.cc @@ -23,13 +23,13 @@ #include #include #include +#include /* Linux includes */ #include #include #include - using namespace Genode; @@ -52,70 +52,20 @@ using namespace Genode; */ struct Protocol_header { + /* badge of invoked object (on call) / exception code (on reply) */ unsigned long protocol_word; + size_t num_caps; + + /* badges of the transferred capability arguments */ + unsigned long badges[Msgbuf_base::MAX_CAPS_PER_MSG]; + + enum { INVALID_BADGE = ~0UL }; + void *msg_start() { return &protocol_word; } }; - -/***************************** - ** IPC marshalling support ** - *****************************/ - -void Ipc_marshaller::insert(Native_capability const &cap) -{ - if (cap.valid()) { - insert(cap.local_name()); - - _snd_msg.append_cap(cap.dst().socket); - } else { - insert(-1L); - } -} - - -void Ipc_unmarshaller::extract(Native_capability &cap) -{ - long local_name = 0; - extract(local_name); - - if (local_name == -1) { - - /* construct invalid capability */ - cap = Genode::Native_capability(); - - } else { - - /* construct valid capability */ - int const socket = _rcv_msg.read_cap(); - cap = Native_capability(Cap_dst_policy::Dst(socket), local_name); - } -} - - -namespace Genode { - - /* - * Helper for obtaining a bound and connected socket pair - * - * For core, the implementation is just a wrapper around - * 'lx_server_socket_pair()'. For all other processes, the implementation - * requests the socket pair from the Env::CPU session interface using a - * Linux-specific interface extension. - */ - Native_connection_state server_socket_pair(); - - /* - * Helper to destroy the server socket pair - * - * For core, this is a no-op. For all other processes, the server and client - * sockets are closed. - */ - void destroy_server_socket_pair(Native_connection_state const &ncs); -} - - /****************************** ** File-descriptor registry ** ******************************/ @@ -205,7 +155,7 @@ namespace { { public: - enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG }; + enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG + 1 }; private: @@ -283,23 +233,51 @@ namespace { } /* unnamed namespace */ +static void insert_sds_into_message(Message &msg, + Protocol_header &header, + Genode::Msgbuf_base &snd_msgbuf) +{ + for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++) { + + Native_capability const &cap = snd_msgbuf.cap(i); + + if (cap.valid()) { + msg.marshal_socket(cap.dst().socket); + header.badges[i] = cap.local_name(); + } else { + header.badges[i] = Protocol_header::INVALID_BADGE; + } + + } + header.num_caps = snd_msgbuf.used_caps(); +} + + /** * Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf' */ -static void extract_sds_from_message(unsigned start_index, Message const &msg, +static void extract_sds_from_message(unsigned start_index, + Message const &msg, + Protocol_header const &header, Genode::Msgbuf_base &buf) { - buf.reset_caps(); + unsigned sd_cnt = 0; + for (unsigned i = 0; i < min(header.num_caps, Msgbuf_base::MAX_CAPS_PER_MSG); i++) { - /* start at offset 1 to skip the reply channel */ - for (unsigned i = start_index; i < msg.num_sockets(); i++) { + unsigned long const badge = header.badges[i]; - int const sd = msg.socket_at_index(i); + /* an invalid capabity was transferred */ + if (badge == Protocol_header::INVALID_BADGE) { + buf.insert(Native_capability()); + continue; + } + + int const sd = msg.socket_at_index(start_index + sd_cnt++); int const id = lookup_tid_by_client_socket(sd); int const associated_sd = Genode::ep_sd_registry()->try_associate(sd, id); - buf.append_cap(associated_sd); + buf.insert(Native_capability(Cap_dst_policy::Dst(associated_sd), badge)); if ((associated_sd >= 0) && (associated_sd != sd)) { @@ -313,57 +291,6 @@ static void extract_sds_from_message(unsigned start_index, Message const &msg, } -/** - * Return type of 'lx_wait' - */ -struct Request -{ - /** - * Destination socket for sending the reply of the RPC function - */ - int reply_socket = 0; - - /** - * Identity of invoked server object - */ - unsigned long badge = 0; -}; - - -/** - * for request from client - * - * \return socket descriptor of reply capability - */ -static Request lx_wait(Genode::Native_connection_state &cs, - Genode::Msgbuf_base &rcv_msgbuf) -{ - Protocol_header &header = rcv_msgbuf.header(); - Message msg(header.msg_start(), sizeof(Protocol_header) + rcv_msgbuf.capacity()); - - msg.accept_sockets(Message::MAX_SDS_PER_MSG); - - int const ret = lx_recvmsg(cs.server_sd, msg.msg(), 0); - - /* system call got interrupted by a signal */ - if (ret == -LX_EINTR) - throw Genode::Blocking_canceled(); - - if (ret < 0) { - PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd); - throw Genode::Ipc_error(); - } - - Request request; - request.reply_socket = msg.socket_at_index(0); - request.badge = header.protocol_word; - - extract_sds_from_message(1, msg, rcv_msgbuf); - - return request; -} - - /** * Send reply to client */ @@ -377,13 +304,10 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code, Message msg(header.msg_start(), sizeof(Protocol_header) + snd_msgbuf.data_size()); - /* - * Marshall capabilities to be transferred to the client - */ - for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++) - msg.marshal_socket(snd_msgbuf.cap(i)); + /* marshall capabilities to be transferred to the client */ + insert_sds_into_message(msg, header, snd_msgbuf); - int ret = lx_sendmsg(reply_socket, msg.msg(), 0); + int const ret = lx_sendmsg(reply_socket, msg.msg(), 0); /* ignore reply send error caused by disappearing client */ if (ret >= 0 || ret == -LX_ECONNREFUSED) { @@ -392,7 +316,7 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code, } if (ret < 0) - PRAW("[%d] lx_sendmsg failed with %d in lx_reply()", lx_getpid(), ret); + PRAW("[%d] lx_sendmsg failed with %d in lx_reply() reply_socket=%d", lx_gettid(), ret, reply_socket); } @@ -448,8 +372,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, snd_msg.marshal_socket(reply_channel.remote_socket()); /* marshal capabilities contained in 'snd_msgbuf' */ - for (unsigned i = 0; i < snd_msgbuf.used_caps(); i++) - snd_msg.marshal_socket(snd_msgbuf.cap(i)); + insert_sds_into_message(snd_msg, snd_header, snd_msgbuf); int const send_ret = lx_sendmsg(dst.dst().socket, snd_msg.msg(), 0); if (send_ret < 0) { @@ -466,6 +389,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, sizeof(Protocol_header) + rcv_msgbuf.capacity()); rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG); + rcv_msgbuf.reset(); int const recv_ret = lx_recvmsg(reply_channel.local_socket(), rcv_msg.msg(), 0); /* system call got interrupted by a signal */ @@ -477,40 +401,31 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, throw Genode::Ipc_error(); } - extract_sds_from_message(0, rcv_msg, rcv_msgbuf); + extract_sds_from_message(0, rcv_msg, rcv_header, rcv_msgbuf); return Rpc_exception_code(rcv_header.protocol_word); } /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::_prepare_next_reply_wait() +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { - _read_offset = _write_offset = 0; - - /* reset capability slots of send message buffer */ - _snd_msg.reset_caps(); + try { lx_reply(caller.dst().socket, exc, snd_msg); } catch (Ipc_error) { } } -void Ipc_server::reply() -{ - try { - lx_reply(_caller.dst().socket, _exception_code, _snd_msg); } - catch (Ipc_error) { } - - _prepare_next_reply_wait(); -} - - -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { /* when first called, there was no request yet */ - if (_reply_needed) - lx_reply(_caller.dst().socket, _exception_code, _snd_msg); + if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT) + lx_reply(last_caller.dst().socket, exc, reply_msg); /* * Block infinitely if called from the main thread. This may happen if the @@ -521,71 +436,86 @@ void Ipc_server::reply_wait() for (;;) lx_nanosleep(&ts, 0); } - try { - Request const request = lx_wait(_rcv_cs, _rcv_msg); + for (;;) { + + Protocol_header &header = request_msg.header(); + Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity()); + + msg.accept_sockets(Message::MAX_SDS_PER_MSG); + + Native_thread &native_thread = Thread_base::myself()->native_thread(); + + request_msg.reset(); + int const ret = lx_recvmsg(native_thread.socket_pair.server_sd, msg.msg(), 0); + + /* system call got interrupted by a signal */ + if (ret == -LX_EINTR) + continue; + + if (ret < 0) { + PRAW("lx_recvmsg failed with %d in ipc_reply_wait, sd=%d", + ret, native_thread.socket_pair.server_sd); + continue; + } + + int const reply_socket = msg.socket_at_index(0); + unsigned long const badge = header.protocol_word; + + /* start at offset 1 to skip the reply channel */ + extract_sds_from_message(1, msg, header, request_msg); - /* remember reply capability */ - enum { DUMMY_LOCAL_NAME = -1 }; typedef Native_capability::Dst Dst; - _caller = Native_capability(Dst(request.reply_socket), DUMMY_LOCAL_NAME); - _badge = request.badge; - - _prepare_next_reply_wait(); - - } catch (Blocking_canceled) { } - - _reply_needed = true; + return Rpc_request(Native_capability(Dst(reply_socket), ~0UL), badge); + } } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) +Ipc_server::Ipc_server() : - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), - Native_capability(Dst(-1), 0), - _rcv_cs(cs) + Native_capability(Dst(-1), 0) { - Thread_base *thread = Thread_base::myself(); - /* * If 'thread' is 0, the constructor was called by the main thread. By * definition, main is never an RPC entrypoint. However, the main thread * may call 'sleep_forever()', which instantiates 'Ipc_server'. */ + if (!Thread_base::myself()) + return; - if (thread && thread->native_thread().is_ipc_server) { + Native_thread &native_thread = Thread_base::myself()->native_thread(); + + if (native_thread.is_ipc_server) { PRAW("[%d] unexpected multiple instantiation of Ipc_server by one thread", lx_gettid()); struct Ipc_server_multiple_instance { }; throw Ipc_server_multiple_instance(); } - if (thread) { - _rcv_cs = server_socket_pair(); - thread->native_thread().is_ipc_server = true; - } + Socket_pair const socket_pair = server_socket_pair(); + + native_thread.socket_pair = socket_pair; + native_thread.is_ipc_server = true; /* override capability initialization */ *static_cast(this) = - Native_capability(Native_capability::Dst(_rcv_cs.client_sd), 0); - - _prepare_next_reply_wait(); + Native_capability(Native_capability::Dst(socket_pair.client_sd), 0); } Ipc_server::~Ipc_server() { - Genode::ep_sd_registry()->disassociate(_rcv_cs.client_sd); + if (!Thread_base::myself()) + return; /* * Reset thread role to non-server such that we can enter 'sleep_forever' * without getting a warning. */ - Thread_base *thread = Thread_base::myself(); - if (thread) - thread->native_thread().is_ipc_server = false; + Native_thread &native_thread = Thread_base::myself()->native_thread(); - destroy_server_socket_pair(_rcv_cs); - _rcv_cs.client_sd = -1; - _rcv_cs.server_sd = -1; + Genode::ep_sd_registry()->disassociate(native_thread.socket_pair.client_sd); + native_thread.is_ipc_server = false; + + destroy_server_socket_pair(native_thread.socket_pair); + native_thread.socket_pair = Socket_pair(); } diff --git a/repos/base-linux/src/core/include/platform_thread.h b/repos/base-linux/src/core/include/platform_thread.h index 1a7d46461a..84486d2b0e 100644 --- a/repos/base-linux/src/core/include/platform_thread.h +++ b/repos/base-linux/src/core/include/platform_thread.h @@ -21,7 +21,7 @@ #include /* base-internal includes */ -#include +#include /* core includes */ #include @@ -68,7 +68,7 @@ namespace Genode { /** * Unix-domain socket pair bound to the thread */ - Native_connection_state _ncs; + Socket_pair _socket_pair; /* * Dummy pager object that is solely used for storing the diff --git a/repos/base-linux/src/core/include/server_socket_pair.h b/repos/base-linux/src/core/include/server_socket_pair.h index 68d18275fe..f0a133ab6b 100644 --- a/repos/base-linux/src/core/include/server_socket_pair.h +++ b/repos/base-linux/src/core/include/server_socket_pair.h @@ -21,6 +21,7 @@ /* base-internal includes */ #include +#include /* core-local includes */ #include @@ -43,25 +44,25 @@ struct Uds_addr : sockaddr_un /** * Utility: Create named socket pair for given unique ID */ -static inline Genode::Native_connection_state create_server_socket_pair(long id) +static inline Genode::Socket_pair create_server_socket_pair(long id) { - Genode::Native_connection_state ncs; + Genode::Socket_pair socket_pair; /* * Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for * binding. */ if (id == -1) - return ncs; + return socket_pair; Uds_addr addr(id); /* * Create server-side socket */ - ncs.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (ncs.server_sd < 0) { - PRAW("Error: Could not create server-side socket (ret=%d)", ncs.server_sd); + socket_pair.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (socket_pair.server_sd < 0) { + PRAW("Error: Could not create server-side socket (ret=%d)", socket_pair.server_sd); class Server_socket_failed { }; throw Server_socket_failed(); } @@ -69,7 +70,7 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id) /* make sure bind succeeds */ lx_unlink(addr.sun_path); - int const bind_ret = lx_bind(ncs.server_sd, (sockaddr *)&addr, sizeof(addr)); + int const bind_ret = lx_bind(socket_pair.server_sd, (sockaddr *)&addr, sizeof(addr)); if (bind_ret < 0) { PRAW("Error: Could not bind server socket (ret=%d)", bind_ret); class Bind_failed { }; @@ -79,21 +80,21 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id) /* * Create client-side socket */ - ncs.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (ncs.client_sd < 0) { - PRAW("Error: Could not create client-side socket (ret=%d)", ncs.client_sd); + socket_pair.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (socket_pair.client_sd < 0) { + PRAW("Error: Could not create client-side socket (ret=%d)", socket_pair.client_sd); class Client_socket_failed { }; throw Client_socket_failed(); } - int const conn_ret = lx_connect(ncs.client_sd, (sockaddr *)&addr, sizeof(addr)); + int const conn_ret = lx_connect(socket_pair.client_sd, (sockaddr *)&addr, sizeof(addr)); if (conn_ret < 0) { PRAW("Error: Could not connect client-side socket (ret=%d)", conn_ret); class Connect_failed { }; throw Connect_failed(); } - ncs.client_sd = Genode::ep_sd_registry()->try_associate(ncs.client_sd, id); + socket_pair.client_sd = Genode::ep_sd_registry()->try_associate(socket_pair.client_sd, id); /* * Wipe Unix domain socket from the file system. It will live as long as @@ -101,7 +102,7 @@ static inline Genode::Native_connection_state create_server_socket_pair(long id) */ lx_unlink(addr.sun_path); - return ncs; + return socket_pair; } #endif /* _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_ */ diff --git a/repos/base-linux/src/core/platform.cc b/repos/base-linux/src/core/platform.cc index dd759c2db5..9467c06d6f 100644 --- a/repos/base-linux/src/core/platform.cc +++ b/repos/base-linux/src/core/platform.cc @@ -158,19 +158,19 @@ void Core_parent::exit(int exit_value) namespace Genode { - Native_connection_state server_socket_pair() + Socket_pair server_socket_pair() { return create_server_socket_pair(Thread_base::myself()->native_thread().tid); } - void destroy_server_socket_pair(Native_connection_state const &ncs) + void destroy_server_socket_pair(Socket_pair socket_pair) { /* * As entrypoints in core are never destructed, this function is only * called on IPC-client destruction. In this case, it's a no-op in core * as well as in Genode processes. */ - if (ncs.server_sd != -1 || ncs.client_sd != -1) + if (socket_pair.server_sd != -1 || socket_pair.client_sd != -1) PERR("%s called for IPC server which should never happen", __func__); } } diff --git a/repos/base-linux/src/core/platform_thread.cc b/repos/base-linux/src/core/platform_thread.cc index 060ca43df6..f7fe433a39 100644 --- a/repos/base-linux/src/core/platform_thread.cc +++ b/repos/base-linux/src/core/platform_thread.cc @@ -85,13 +85,13 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned, addr_t) Platform_thread::~Platform_thread() { - ep_sd_registry()->disassociate(_ncs.client_sd); + ep_sd_registry()->disassociate(_socket_pair.client_sd); - if (_ncs.client_sd) - lx_close(_ncs.client_sd); + if (_socket_pair.client_sd) + lx_close(_socket_pair.client_sd); - if (_ncs.server_sd) - lx_close(_ncs.server_sd); + if (_socket_pair.server_sd) + lx_close(_socket_pair.server_sd); _registry()->remove(this); } @@ -119,15 +119,15 @@ void Platform_thread::resume() int Platform_thread::client_sd() { /* construct socket pair on first call */ - if (_ncs.client_sd == -1) - _ncs = create_server_socket_pair(_tid); + if (_socket_pair.client_sd == -1) + _socket_pair = create_server_socket_pair(_tid); - return _ncs.client_sd; + return _socket_pair.client_sd; } int Platform_thread::server_sd() { client_sd(); - return _ncs.server_sd; + return _socket_pair.server_sd; } diff --git a/repos/base-linux/src/include/base/internal/native_connection_state.h b/repos/base-linux/src/include/base/internal/native_connection_state.h deleted file mode 100644 index 2a7cc7cc40..0000000000 --- a/repos/base-linux/src/include/base/internal/native_connection_state.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * \brief Connection state of incoming RPC request - * \author Norman Feske - * \date 2016-03-03 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ -#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ - -#include - -namespace Genode { struct Native_connection_state; } - - -struct Genode::Native_connection_state -{ - int server_sd = -1; - int client_sd = -1; -}; - -#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */ diff --git a/repos/base-linux/src/include/base/internal/native_thread.h b/repos/base-linux/src/include/base/internal/native_thread.h index 5cd901dda6..5f1a3a5ab2 100644 --- a/repos/base-linux/src/include/base/internal/native_thread.h +++ b/repos/base-linux/src/include/base/internal/native_thread.h @@ -15,6 +15,7 @@ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ #include +#include namespace Genode { struct Native_thread; } @@ -45,6 +46,8 @@ struct Genode::Native_thread */ Meta_data *meta_data = nullptr; + Socket_pair socket_pair; + Native_thread() { } }; diff --git a/repos/base-linux/src/include/base/internal/server_socket_pair.h b/repos/base-linux/src/include/base/internal/server_socket_pair.h new file mode 100644 index 0000000000..d59f38c413 --- /dev/null +++ b/repos/base-linux/src/include/base/internal/server_socket_pair.h @@ -0,0 +1,44 @@ +/* + * \brief Socket pair used by RPC entrypoint + * \author Norman Feske + * \date 2016-03-25 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_ +#define _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_ + +namespace Genode { + + struct Socket_pair + { + int client_sd = -1; + int server_sd = -1; + }; + + /* + * Helper for obtaining a bound and connected socket pair + * + * For core, the implementation is just a wrapper around + * 'lx_server_socket_pair()'. For all other processes, the implementation + * requests the socket pair from the Env::CPU session interface using a + * Linux-specific interface extension. + */ + Socket_pair server_socket_pair(); + + /* + * Helper to destroy the server socket pair + * + * For core, this is a no-op. For all other processes, the server and client + * sockets are closed. + */ + void destroy_server_socket_pair(Socket_pair); +} + +#endif /* _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_ */ diff --git a/repos/base-nova/include/base/ipc_msgbuf.h b/repos/base-nova/include/base/ipc_msgbuf.h deleted file mode 100644 index b09bb5ee7b..0000000000 --- a/repos/base-nova/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,453 +0,0 @@ -/* - * \brief IPC message buffer layout for NOVA - * \author Norman Feske - * \author Alexander Boettcher - * \date 2009-10-02 - * - * On NOVA, we use IPC to transmit plain data and for capability delegation - * and capability translation. - * Therefore the message buffer contains three categories of payload. The - * capability-specific part are the members '_snd_pt*' (sending capability - * selectors) and '_rcv_pt*' (receiving capability selectors). - */ - -/* - * Copyright (C) 2009-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -/* NOVA includes */ -#include -#include - -namespace Genode { - - class Ipc_marshaller; - - class Msgbuf_base - { - public: - - enum { - MAX_CAP_ARGS_LOG2 = 2, - MAX_CAP_ARGS = 1 << MAX_CAP_ARGS_LOG2 - }; - - protected: - - friend class Ipc_marshaller; - - size_t const _capacity; - - size_t _data_size = 0; - - /** - * Number of portal-capability selectors to send - */ - size_t _snd_pt_sel_cnt = 0; - - /** - * Portal capability selectors to delegate - */ - Native_capability _snd_pt_sel[MAX_CAP_ARGS]; - - /** - * Base of portal receive window - */ - addr_t _rcv_pt_base = 0; - - struct { - addr_t sel = 0; - bool del = 0; - } _rcv_pt_sel[MAX_CAP_ARGS]; - - /** - * Normally the received capabilities start from the beginning of - * the receive window (_rcv_pt_base), densely packed ascending. - * However, a receiver may send invalid caps, which will cause - * capability-selector gaps in the receiver window. Or a - * misbehaving sender may even intentionally place a cap at the end - * of the receive window. The position of a cap within the receive - * window is fundamentally important to correctly maintain the - * component-local capability-selector reference count. - * - * Additionally, the position is also required to decide whether a - * kernel capability must be revoked during the receive window - * cleanup/re-usage. '_rcv_pt_cap_free' is used to track this - * information in order to free up and revoke selectors - * (message-buffer cleanup). - * - * Meanings of the enums: - * - FREE_INVALID - invalid cap selector, no cap_map entry - * - FREE_SEL - valid cap selector, invalid kernel capability - * - UNUSED_CAP - valid selector and cap, not read/used yet - * - USED_CAP - valid sel and cap, read/used by stream operator - */ - enum { FREE_INVALID, FREE_SEL, UNUSED_CAP, USED_CAP } - _rcv_pt_cap_free [MAX_CAP_ARGS]; - - /** - * Read counter for unmarshalling portal capability - * selectors - */ - unsigned short _rcv_pt_sel_cnt = 0; - unsigned short _rcv_pt_sel_max = 0; - unsigned short _rcv_wnd_log2 = 0; - - char _msg_start[]; /* symbol marks start of message */ - - public: - - enum { INVALID_INDEX = ~0UL }; - - /** - * Constructor - */ - Msgbuf_base(size_t capacity) - : - _capacity(capacity), - _rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2) - { - rcv_reset(); - snd_reset(); - } - - ~Msgbuf_base() - { - rcv_reset(); - } - - /* - * Begin of actual message buffer - */ - char buf[]; - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; } - - /** - * Return pointer of message data payload - */ - void *data() { return &_msg_start[0]; } - void const *data() const { return &_msg_start[0]; } - - unsigned long &word(unsigned i) - { - return reinterpret_cast(buf)[i]; - } - - size_t data_size() const { return _data_size; } - - /** - * Reset portal capability selector payload - */ - void snd_reset() { - - for (unsigned i = 0; i < MAX_CAP_ARGS; i++) { - +_snd_pt_sel[i]; - _snd_pt_sel[i] = Native_capability(); - } - - _snd_pt_sel_cnt = 0; - } - - /** - * Append portal capability selector to message buffer - */ - bool snd_append_pt_sel(Native_capability const &cap) - { - if (_snd_pt_sel_cnt >= MAX_CAP_ARGS - 1) - return false; - - _snd_pt_sel[_snd_pt_sel_cnt++ ] = cap; - return true; - } - - /** - * Return number of marshalled portal-capability - * selectors - */ - size_t snd_pt_sel_cnt() const - { - return _snd_pt_sel_cnt; - } - - /** - * Return portal capability selector - * - * \param i index (0 ... 'pt_sel_cnt()' - 1) - * \return portal-capability range descriptor - * - * The returned object could be a null cap. Use - * is_null method to check for it. - */ - Nova::Obj_crd snd_pt_sel(addr_t i, bool &trans_map) const - { - if (i >= _snd_pt_sel_cnt) - return Nova::Obj_crd(); - - trans_map = _snd_pt_sel[i].trans_map(); - - return Nova::Obj_crd(_snd_pt_sel[i].local_name(), 0, - _snd_pt_sel[i].dst().rights()); - } - - /** - * Request current portal-receive window - */ - addr_t rcv_pt_base() const { return _rcv_pt_base; } - - /** - * Set log2 number of capabilities to be received during reply of - * a IPC call. - */ - void rcv_wnd(unsigned short const caps_log2) - { - if (caps_log2 > MAX_CAP_ARGS_LOG2) - nova_die(); - - _rcv_wnd_log2 = caps_log2; - } - - /** - * Reset portal-capability receive window - */ - void rcv_reset() - { - if (!rcv_invalid()) { rcv_cleanup(false); } - - _rcv_pt_sel_cnt = 0; - _rcv_pt_sel_max = 0; - _rcv_pt_base = INVALID_INDEX; - } - - /** - * Return received portal-capability selector - */ - void rcv_pt_sel(Native_capability &cap) - { - if (_rcv_pt_sel_cnt >= _rcv_pt_sel_max) { - cap = Native_capability(); - return; - } - - /* return only received or translated caps */ - cap = Native_capability(_rcv_pt_sel[_rcv_pt_sel_cnt++].sel); - } - - /** - * Return true if receive window must be re-initialized - */ - bool rcv_invalid() const - { - return _rcv_pt_base == INVALID_INDEX; - } - - /** - * Return true if receive window must be re-initialized - * - * After reading portal selectors from the message - * buffer using 'rcv_pt_sel()', we assume that the IDC - * call populated the current receive window with one - * or more portal capabilities. - * To enable the reception of portal capability - * selectors for the next IDC, we need a fresh receive - * window. - * - * \param keep 'true' - Try to keep receive window if - * it's clean. - * 'false' - Free caps of receive window - * because object is freed - * afterwards. - * - * \result 'true' - receive window must be re-initialized - * 'false' - portal selectors has been kept - */ - bool rcv_cleanup(bool keep, unsigned short const new_max = MAX_CAP_ARGS) - { - /* mark used mapped capabilities as used to prevent freeing */ - bool reinit = false; - for (unsigned i = 0; i < _rcv_pt_sel_cnt; i++) { - if (!_rcv_pt_sel[i].del) - continue; - - /* should never happen */ - if (_rcv_pt_sel[i].sel < rcv_pt_base() || - (_rcv_pt_sel[i].sel >= rcv_pt_base() + MAX_CAP_ARGS)) - nova_die(); - - _rcv_pt_cap_free [_rcv_pt_sel[i].sel - rcv_pt_base()] = USED_CAP; - - reinit = true; - } - - /* if old receive window was smaller, we need to re-init */ - for (unsigned i = 0; !reinit && i < new_max; i++) - if (_rcv_pt_cap_free[i] == FREE_INVALID) - reinit = true; - - _rcv_pt_sel_cnt = 0; - _rcv_pt_sel_max = 0; - - /* we can keep the cap selectors if none was used */ - if (keep && !reinit) { - for (unsigned i = 0; i < MAX_CAP_ARGS; i++) { - /* revoke received caps which are unused */ - if (_rcv_pt_cap_free[i] == UNUSED_CAP) - Nova::revoke(Nova::Obj_crd(rcv_pt_base() + i, 0), true); - - /* free rest of indexes if new_max is smaller then last window */ - if (i >= new_max && _rcv_pt_cap_free[i] == FREE_SEL) - cap_map()->remove(rcv_pt_base() + i, 0, false); - } - - return false; - } - - /* decrease ref count if valid selector */ - for (unsigned i = 0; i < MAX_CAP_ARGS; i++) { - if (_rcv_pt_cap_free[i] == FREE_INVALID) - continue; - cap_map()->remove(rcv_pt_base() + i, 0, _rcv_pt_cap_free[i] != FREE_SEL); - } - - return true; - } - - /** - * Initialize receive window for portal capability - * selectors - * - * \param utcb - UTCB of designated receiver - * thread - * \param rcv_window - If specified - receive exactly - * one capability at the specified - * index of rcv_window - * - * Depending on the 'rcv_invalid', 'rcv_cleanup(true)' - * state of the message buffer and the specified - * rcv_window parameter, this function allocates a - * fresh receive window and clears 'rcv_invalid'. - */ - bool prepare_rcv_window(Nova::Utcb *utcb, - addr_t rcv_window = INVALID_INDEX) - { - /* open maximal translate window */ - utcb->crd_xlt = Nova::Obj_crd(0, ~0UL); - - /* use receive window if specified */ - if (rcv_window != INVALID_INDEX) { - /* cleanup if receive window already used */ - if (!rcv_invalid()) rcv_cleanup(false); - - _rcv_pt_base = rcv_window; - - /* open receive window */ - utcb->crd_rcv = Nova::Obj_crd(rcv_pt_base(), _rcv_wnd_log2); - return true; - } - - /* allocate receive window if necessary, otherwise use old one */ - if (rcv_invalid() || rcv_cleanup(true, 1U << _rcv_wnd_log2)) - { - _rcv_pt_base = cap_map()->insert(_rcv_wnd_log2); - - if (_rcv_pt_base == INVALID_INDEX) { - /* no mappings can be received */ - utcb->crd_rcv = Nova::Obj_crd(); - return false; - } - } - - /* open receive window */ - utcb->crd_rcv = Nova::Obj_crd(rcv_pt_base(), _rcv_wnd_log2); - return true; - } - - /** - * Post IPC processing. - * - * Remember where and which caps have been received - * respectively have been translated. - * The information is required to correctly free - * cap indexes and to revoke unused received caps. - * - * \param utcb UTCB of designated receiver thread - */ - void post_ipc(Nova::Utcb *utcb, addr_t const rcv_window = INVALID_INDEX) - { - using namespace Nova; - - unsigned const rcv_items = (utcb->items >> 16) & 0xffffu; - - _rcv_pt_sel_max = 0; - _rcv_pt_sel_cnt = 0; - - unsigned short const max = 1U << utcb->crd_rcv.order(); - if (max > MAX_CAP_ARGS) - nova_die(); - - for (unsigned short i = 0; i < MAX_CAP_ARGS; i++) - _rcv_pt_cap_free [i] = (i >= max) ? FREE_INVALID : FREE_SEL; - - for (unsigned i = 0; i < rcv_items; i++) { - Nova::Utcb::Item * item = utcb->get_item(i); - if (!item) - break; - - Nova::Crd cap(item->crd); - - /* track which items we got mapped */ - if (!cap.is_null() && item->is_del()) { - /* should never happen */ - if (cap.base() < rcv_pt_base() || - (cap.base() >= rcv_pt_base() + max)) - nova_die(); - _rcv_pt_cap_free [cap.base() - rcv_pt_base()] = UNUSED_CAP; - } - - if (_rcv_pt_sel_max >= max) continue; - - /* track the order of mapped and translated items */ - if (cap.is_null()) { - _rcv_pt_sel[_rcv_pt_sel_max].sel = INVALID_INDEX; - _rcv_pt_sel[_rcv_pt_sel_max++].del = false; - } else { - _rcv_pt_sel[_rcv_pt_sel_max].sel = cap.base(); - _rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del(); - } - } - - /* - * If a specific rcv_window has been specified, - * (see prepare_rcv_window) then the caller want to take care - * about freeing the * selector. Make the _rcv_pt_base invalid - * so that it is not cleanup twice. - */ - if (rcv_window != INVALID_INDEX) - _rcv_pt_base = INVALID_INDEX; - - utcb->crd_rcv = 0; - } - }; - - - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-nova/include/base/native_types.h b/repos/base-nova/include/base/native_types.h index 3bad1694d5..246536bbf3 100644 --- a/repos/base-nova/include/base/native_types.h +++ b/repos/base-nova/include/base/native_types.h @@ -54,7 +54,6 @@ namespace Genode { : dst(sel, 0, rights) { } } _cap; - bool _trans_map; addr_t _rcv_window; enum { INVALID_INDEX = ~0UL }; @@ -80,7 +79,7 @@ namespace Genode { */ Native_capability() - : _cap(), _trans_map(true), _rcv_window(INVALID_INDEX) {} + : _cap(), _rcv_window(INVALID_INDEX) {} explicit Native_capability(addr_t sel, unsigned rights = 0x1f) @@ -92,13 +91,12 @@ namespace Genode { _inc(); } - _trans_map = true; - _rcv_window = INVALID_INDEX; + _rcv_window = INVALID_INDEX; } Native_capability(const Native_capability &o) - : _cap(o._cap), _trans_map(o._trans_map), - _rcv_window(o._rcv_window) { if (valid()) _inc(); } + : _cap(o._cap), _rcv_window(o._rcv_window) + { if (valid()) _inc(); } ~Native_capability() { if (valid()) _dec(); } @@ -108,10 +106,13 @@ namespace Genode { bool operator==(const Native_capability &o) const { return local_name() == o.local_name(); } - Native_capability operator+ () const + /** + * Inhibit removal of capability from cap map if it's the last reference + */ + void keep_if_last_reference() { - if (valid()) _inc(true); - return *this; + if (valid()) + _inc(true); } /** @@ -126,7 +127,6 @@ namespace Genode { if (valid()) _dec(); _cap = o._cap; - _trans_map = o._trans_map; _rcv_window = o._rcv_window; if (valid()) _inc(); @@ -179,17 +179,6 @@ namespace Genode { { return Native_capability(); } - - /** - * Invoke map syscall instead of translate_map call - */ - void solely_map() { _trans_map = false; } - - /** - * Return true if the cap should be tried first to - * be translated and if this fails it should be mapped. - */ - bool trans_map() const { return _trans_map; } }; } diff --git a/repos/base-nova/include/nova/native_thread.h b/repos/base-nova/include/nova/native_thread.h index d74ef62315..32aec3fa9f 100644 --- a/repos/base-nova/include/nova/native_thread.h +++ b/repos/base-nova/include/nova/native_thread.h @@ -20,6 +20,7 @@ #define _INCLUDE__NOVA__NATIVE_THREAD_H_ #include +#include namespace Genode { struct Native_thread; } @@ -31,6 +32,9 @@ struct Genode::Native_thread addr_t exc_pt_sel; /* base of event portal window */ bool is_vcpu; + /* receive window for capability selectors received at the server side */ + Receive_window rcv_window; + Native_thread() : ec_sel(INVALID_INDEX), exc_pt_sel(INVALID_INDEX), is_vcpu(false) { } }; diff --git a/repos/base-nova/include/nova/receive_window.h b/repos/base-nova/include/nova/receive_window.h new file mode 100644 index 0000000000..3ce7509041 --- /dev/null +++ b/repos/base-nova/include/nova/receive_window.h @@ -0,0 +1,338 @@ +/* + * \brief Receive window for capability selectors + * \author Alexander Boettcher + * \author Norman Feske + * \date 2016-03-22 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__NOVA__RECEIVE_WINDOW_H_ +#define _INCLUDE__NOVA__RECEIVE_WINDOW_H_ + +/* Genode includes */ +#include +#include + +/* NOVA includes */ +#include +#include + +namespace Genode { struct Receive_window; } + + +struct Genode::Receive_window +{ + public: + + enum { + MAX_CAP_ARGS_LOG2 = 2, + MAX_CAP_ARGS = 1UL << MAX_CAP_ARGS_LOG2 + }; + + static_assert(MAX_CAP_ARGS == (size_t)Msgbuf_base::MAX_CAPS_PER_MSG, + "Inconsistency between Receive_window and Msgbuf_base"); + + private: + + /** + * Base of portal receive window + */ + addr_t _rcv_pt_base = 0; + + struct { + addr_t sel = 0; + bool del = 0; + } _rcv_pt_sel[MAX_CAP_ARGS]; + + /** + * Normally the received capabilities start from the beginning of + * the receive window (_rcv_pt_base), densely packed ascending. + * However, a receiver may send invalid caps, which will cause + * capability-selector gaps in the receiver window. Or a + * misbehaving sender may even intentionally place a cap at the end + * of the receive window. The position of a cap within the receive + * window is fundamentally important to correctly maintain the + * component-local capability-selector reference count. + * + * Additionally, the position is also required to decide whether a + * kernel capability must be revoked during the receive window + * cleanup/re-usage. '_rcv_pt_cap_free' is used to track this + * information in order to free up and revoke selectors + * (message-buffer cleanup). + * + * Meanings of the enums: + * - FREE_INVALID - invalid cap selector, no cap_map entry + * - FREE_SEL - valid cap selector, invalid kernel capability + * - UNUSED_CAP - valid selector and cap, not read/used yet + * - USED_CAP - valid sel and cap, read/used by stream operator + */ + enum { FREE_INVALID, FREE_SEL, UNUSED_CAP, USED_CAP } + _rcv_pt_cap_free [MAX_CAP_ARGS]; + + /** + * Read counter for unmarshalling portal capability + * selectors + */ + unsigned short _rcv_pt_sel_cnt = 0; + unsigned short _rcv_pt_sel_max = 0; + unsigned short _rcv_wnd_log2 = 0; + + /** + * Reset portal-capability receive window + */ + void _rcv_reset() + { + if (!rcv_invalid()) { rcv_cleanup(false); } + + _rcv_pt_sel_cnt = 0; + _rcv_pt_sel_max = 0; + _rcv_pt_base = INVALID_INDEX; + } + + public: + + enum { INVALID_INDEX = ~0UL }; + + Receive_window() + : + _rcv_pt_base(INVALID_INDEX), _rcv_wnd_log2(MAX_CAP_ARGS_LOG2) + { + _rcv_reset(); + } + + ~Receive_window() + { + _rcv_reset(); + } + + /** + * Set log2 number of capabilities to be received during reply of + * a IPC call. + */ + void rcv_wnd(unsigned short const caps_log2) + { + if (caps_log2 > MAX_CAP_ARGS_LOG2) + nova_die(); + + _rcv_wnd_log2 = caps_log2; + } + + /** + * Return received portal-capability selector + */ + void rcv_pt_sel(Native_capability &cap) + { + if (_rcv_pt_sel_cnt >= _rcv_pt_sel_max) { + cap = Native_capability(); + return; + } + + /* return only received or translated caps */ + cap = Native_capability(_rcv_pt_sel[_rcv_pt_sel_cnt++].sel); + } + + /** + * Return true if receive window must be re-initialized + */ + bool rcv_invalid() const + { + return _rcv_pt_base == INVALID_INDEX; + } + + unsigned num_received_caps() const { return _rcv_pt_sel_max; } + + /** + * Return true if receive window must be re-initialized + * + * After reading portal selectors from the message + * buffer using 'rcv_pt_sel()', we assume that the IDC + * call populated the current receive window with one + * or more portal capabilities. + * To enable the reception of portal capability + * selectors for the next IDC, we need a fresh receive + * window. + * + * \param keep 'true' - Try to keep receive window if + * it's clean. + * 'false' - Free caps of receive window + * because object is freed + * afterwards. + * + * \result 'true' - receive window must be re-initialized + * 'false' - portal selectors has been kept + */ + bool rcv_cleanup(bool keep, unsigned short const new_max = MAX_CAP_ARGS) + { + /* mark used mapped capabilities as used to prevent freeing */ + bool reinit = false; + for (unsigned i = 0; i < _rcv_pt_sel_cnt; i++) { + if (!_rcv_pt_sel[i].del) + continue; + + /* should never happen */ + if (_rcv_pt_sel[i].sel < _rcv_pt_base || + (_rcv_pt_sel[i].sel >= _rcv_pt_base + MAX_CAP_ARGS)) + nova_die(); + + _rcv_pt_cap_free [_rcv_pt_sel[i].sel - _rcv_pt_base] = USED_CAP; + + reinit = true; + } + + /* if old receive window was smaller, we need to re-init */ + for (unsigned i = 0; !reinit && i < new_max; i++) + if (_rcv_pt_cap_free[i] == FREE_INVALID) + reinit = true; + + _rcv_pt_sel_cnt = 0; + _rcv_pt_sel_max = 0; + + /* we can keep the cap selectors if none was used */ + if (keep && !reinit) { + for (unsigned i = 0; i < MAX_CAP_ARGS; i++) { + /* revoke received caps which are unused */ + if (_rcv_pt_cap_free[i] == UNUSED_CAP) + Nova::revoke(Nova::Obj_crd(_rcv_pt_base + i, 0), true); + + /* free rest of indexes if new_max is smaller then last window */ + if (i >= new_max && _rcv_pt_cap_free[i] == FREE_SEL) + cap_map()->remove(_rcv_pt_base + i, 0, false); + } + + return false; + } + + /* decrease ref count if valid selector */ + for (unsigned i = 0; i < MAX_CAP_ARGS; i++) { + if (_rcv_pt_cap_free[i] == FREE_INVALID) + continue; + cap_map()->remove(_rcv_pt_base + i, 0, _rcv_pt_cap_free[i] != FREE_SEL); + } + + return true; + } + + /** + * Initialize receive window for portal capability + * selectors + * + * \param utcb - UTCB of designated receiver + * thread + * \param rcv_window - If specified - receive exactly + * one capability at the specified + * index of rcv_window + * + * Depending on the 'rcv_invalid', 'rcv_cleanup(true)' + * state of the message buffer and the specified + * rcv_window parameter, this function allocates a + * fresh receive window and clears 'rcv_invalid'. + */ + bool prepare_rcv_window(Nova::Utcb &utcb, + addr_t rcv_window = INVALID_INDEX) + { + /* open maximal translate window */ + utcb.crd_xlt = Nova::Obj_crd(0, ~0UL); + + /* use receive window if specified */ + if (rcv_window != INVALID_INDEX) { + /* cleanup if receive window already used */ + if (!rcv_invalid()) rcv_cleanup(false); + + _rcv_pt_base = rcv_window; + + /* open receive window */ + utcb.crd_rcv = Nova::Obj_crd(_rcv_pt_base, _rcv_wnd_log2); + return true; + } + + /* allocate receive window if necessary, otherwise use old one */ + if (rcv_invalid() || rcv_cleanup(true, 1U << _rcv_wnd_log2)) + { + _rcv_pt_base = cap_map()->insert(_rcv_wnd_log2); + + if (_rcv_pt_base == INVALID_INDEX) { + /* no mappings can be received */ + utcb.crd_rcv = Nova::Obj_crd(); + return false; + } + } + + /* open receive window */ + utcb.crd_rcv = Nova::Obj_crd(_rcv_pt_base, _rcv_wnd_log2); + return true; + } + + /** + * Post IPC processing. + * + * Remember where and which caps have been received + * respectively have been translated. + * The information is required to correctly free + * cap indexes and to revoke unused received caps. + * + * \param utcb UTCB of designated receiver thread + */ + void post_ipc(Nova::Utcb &utcb, addr_t const rcv_window = INVALID_INDEX) + { + using namespace Nova; + + unsigned const rcv_items = (utcb.items >> 16) & 0xffffu; + + _rcv_pt_sel_max = 0; + _rcv_pt_sel_cnt = 0; + + unsigned short const max = 1U << utcb.crd_rcv.order(); + if (max > MAX_CAP_ARGS) + nova_die(); + + for (unsigned short i = 0; i < MAX_CAP_ARGS; i++) + _rcv_pt_cap_free [i] = (i >= max) ? FREE_INVALID : FREE_SEL; + + for (unsigned i = 0; i < rcv_items; i++) { + Nova::Utcb::Item * item = utcb.get_item(i); + if (!item) + break; + + Nova::Crd cap(item->crd); + + /* track which items we got mapped */ + if (!cap.is_null() && item->is_del()) { + /* should never happen */ + if (cap.base() < _rcv_pt_base || + (cap.base() >= _rcv_pt_base + max)) + nova_die(); + _rcv_pt_cap_free [cap.base() - _rcv_pt_base] = UNUSED_CAP; + } + + if (_rcv_pt_sel_max >= max) continue; + + /* track the order of mapped and translated items */ + if (cap.is_null()) { + _rcv_pt_sel[_rcv_pt_sel_max].sel = INVALID_INDEX; + _rcv_pt_sel[_rcv_pt_sel_max++].del = false; + } else { + _rcv_pt_sel[_rcv_pt_sel_max].sel = cap.base(); + _rcv_pt_sel[_rcv_pt_sel_max++].del = item->is_del(); + } + } + + /* + * If a specific rcv_window has been specified, + * (see prepare_rcv_window) then the caller want to take care + * about freeing the * selector. Make the _rcv_pt_base invalid + * so that it is not cleanup twice. + */ + if (rcv_window != INVALID_INDEX) + _rcv_pt_base = INVALID_INDEX; + + utcb.crd_rcv = 0; + } +}; + +#endif /* _INCLUDE__NOVA__RECEIVE_WINDOW_H_ */ diff --git a/repos/base-nova/include/nova/util.h b/repos/base-nova/include/nova/util.h index d3d61d1ef1..464ab31e11 100644 --- a/repos/base-nova/include/nova/util.h +++ b/repos/base-nova/include/nova/util.h @@ -51,7 +51,7 @@ inline void request_event_portal(Genode::Native_capability const &cap, utcb->crd_rcv = orig_crd; if (res) - PERR("request of event (%lu) capability selector failed", event); + PERR("request of event (%lu) capability selector failed (res=%u)", event, res); } diff --git a/repos/base-nova/include/signal_source/client.h b/repos/base-nova/include/signal_source/client.h index c96132a4a4..8735552f2c 100644 --- a/repos/base-nova/include/signal_source/client.h +++ b/repos/base-nova/include/signal_source/client.h @@ -71,18 +71,29 @@ namespace Genode { Signal wait_for_signal() override { - /* - * Block on semaphore, will be unblocked if - * signal is available - */ using namespace Nova; - mword_t value = 0; - mword_t count = 0; - if (uint8_t res = si_ctrl(_sem.local_name(), SEMAPHORE_DOWN, - value, count)) - PWRN("signal reception failed - error %u", res); - return Signal(value, count); + mword_t imprint, count; + do { + + /* + * We set an invalid imprint (0) to detect a spurious + * unblock. In this case, NOVA does not block + * SEMAPHORE_DOWN nor touch our input values if the + * deblocking (chained) semaphore was dequeued before we + * intend to block. + */ + imprint = 0; + count = 0; + + /* block on semaphore until signal context was submitted */ + if (uint8_t res = si_ctrl(_sem.local_name(), SEMAPHORE_DOWN, + imprint, count)) + PWRN("signal reception failed - error %u", res); + + } while (imprint == 0); + + return Signal(imprint, count); } }; } diff --git a/repos/base-nova/src/base/ipc/ipc.cc b/repos/base-nova/src/base/ipc/ipc.cc index c5908b474a..4c331a0a04 100644 --- a/repos/base-nova/src/base/ipc/ipc.cc +++ b/repos/base-nova/src/base/ipc/ipc.cc @@ -17,117 +17,9 @@ #include /* base-internal includes */ -#include - -/* NOVA includes */ -#include +#include using namespace Genode; -using namespace Nova; - - -/***************************** - ** IPC marshalling support ** - *****************************/ - -void Ipc_marshaller::insert(Native_capability const &cap) -{ - _snd_msg.snd_append_pt_sel(cap); -} - - -void Ipc_unmarshaller::extract(Native_capability &cap) -{ - _rcv_msg.rcv_pt_sel(cap); -} - - -/*************** - ** Utilities ** - ***************/ - -/** - * Copy message registers from UTCB to destination message buffer - * - * \return protocol word delivered via the first UTCB message register - * - * The caller of this function must ensure that utcb->msg_words is greater - * than 0. - */ -static mword_t copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base &rcv_msg) -{ - size_t num_msg_words = utcb->msg_words(); - - /* - * Handle the reception of a malformed message. This should never happen - * because the utcb->msg_words is checked by the caller of this function. - */ - if (num_msg_words < 1) - return 0; - - /* the UTCB contains the protocol word followed by the message data */ - mword_t const protocol_word = utcb->msg[0]; - size_t num_data_words = num_msg_words - 1; - - if (num_data_words*sizeof(mword_t) > rcv_msg.capacity()) { - PERR("receive message buffer too small msg size=%zx, buf size=%zd", - num_data_words*sizeof(mword_t), rcv_msg.capacity()); - num_data_words = rcv_msg.capacity()/sizeof(mword_t); - } - - /* read message payload into destination message buffer */ - mword_t *src = (mword_t *)(void *)(&utcb->msg[1]); - mword_t *dst = (mword_t *)rcv_msg.data(); - for (unsigned i = 0; i < num_data_words; i++) - *dst++ = *src++; - - return protocol_word; -} - - -/** - * Copy message payload to UTCB message registers - */ -static bool copy_msgbuf_to_utcb(Nova::Utcb *utcb, Msgbuf_base const &snd_msg, - mword_t protocol_value) -{ - /* look up address and size of message payload */ - mword_t *msg_buf = (mword_t *)snd_msg.data(); - - /* size of message payload in machine words */ - size_t const num_data_words = snd_msg.data_size()/sizeof(mword_t); - - /* account for protocol value in front of the message */ - size_t num_msg_words = 1 + num_data_words; - - enum { NUM_MSG_REGS = 256 }; - if (num_msg_words > NUM_MSG_REGS) { - PERR("Message does not fit into UTCB message registers\n"); - num_msg_words = NUM_MSG_REGS; - } - - utcb->msg[0] = protocol_value; - - /* store message into UTCB message registers */ - mword_t *src = (mword_t *)&msg_buf[0]; - mword_t *dst = (mword_t *)(void *)&utcb->msg[1]; - for (unsigned i = 0; i < num_data_words; i++) - *dst++ = *src++; - - utcb->set_msg_word(num_msg_words); - - /* append portal capability selectors */ - for (unsigned i = 0; i < snd_msg.snd_pt_sel_cnt(); i++) { - bool trans_map = true; - Nova::Obj_crd crd = snd_msg.snd_pt_sel(i, trans_map); - if (crd.base() == ~0UL) continue; - - if (!utcb->append_item(crd, i, false, false, trans_map)) - return false; - } - - return true; -} /**************** @@ -138,6 +30,9 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, size_t rcv_caps) { + Receive_window rcv_window; + rcv_msg.reset(); + /* update receive window for capability selectors if needed */ if (rcv_caps != ~0UL) { @@ -145,10 +40,10 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, unsigned short log2_max = rcv_caps ? log2(rcv_caps) : 0; if ((1U << log2_max) < rcv_caps) log2_max ++; - rcv_msg.rcv_wnd(log2_max); + rcv_window.rcv_wnd(log2_max); } - Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); + Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb(); /* the protocol value is unused as the badge is delivered by the kernel */ if (!copy_msgbuf_to_utcb(utcb, snd_msg, 0)) { @@ -157,7 +52,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, } /* if we can't setup receive window, die in order to recognize the issue */ - if (!rcv_msg.prepare_rcv_window(utcb, dst.rcv_window())) + if (!rcv_window.prepare_rcv_window(utcb, dst.rcv_window())) /* printf doesn't work here since for IPC also rcv_prepare* is used */ nova_die(); @@ -165,67 +60,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, uint8_t res = Nova::call(dst.local_name()); if (res != Nova::NOVA_OK) { /* If an error occurred, reset word&item count (not done by kernel). */ - utcb->set_msg_word(0); + utcb.set_msg_word(0); return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); } - rcv_msg.post_ipc(utcb, dst.rcv_window()); + rcv_window.post_ipc(utcb, dst.rcv_window()); /* handle malformed reply from a server */ - if (utcb->msg_words() < 1) + if (utcb.msg_words() < 1) return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); - return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_msg)); + return Rpc_exception_code(copy_utcb_to_msgbuf(utcb, rcv_window, rcv_msg)); } - - -/**************** - ** Ipc_server ** - ****************/ - -void Ipc_server::reply() -{ - Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); - - copy_msgbuf_to_utcb(utcb, _snd_msg, _exception_code.value); - - _snd_msg.snd_reset(); - - Nova::reply(Thread_base::myself()->stack_top()); -} - - -void Ipc_server::reply_wait() -{ - /* - * This function is only called by the portal dispatcher of server - * entrypoint'. When the dispatcher is called, the incoming message already - * arrived so that we do not need to block. The only remaining thing to do - * is unmarshalling the arguments. - */ - - Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); - - _rcv_msg.post_ipc(utcb); - - /* handle ill-formed message */ - if (utcb->msg_words() < 2) { - _rcv_msg.word(0) = ~0UL; /* invalid opcode */ - } else { - copy_utcb_to_msgbuf(utcb, _rcv_msg); - } - - _read_offset = _write_offset = 0; -} - - -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) -: - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _rcv_cs(cs) -{ - _read_offset = _write_offset = 0; -} - - -Ipc_server::~Ipc_server() { } diff --git a/repos/base-nova/src/base/server/server.cc b/repos/base-nova/src/base/server/server.cc index d52537ed74..0c9a76b6e2 100644 --- a/repos/base-nova/src/base/server/server.cc +++ b/repos/base-nova/src/base/server/server.cc @@ -20,11 +20,12 @@ /* base-internal includes */ #include -#include +#include /* NOVA includes */ #include #include +#include using namespace Genode; @@ -106,6 +107,14 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj) } +static void reply(Nova::Utcb &utcb, Rpc_exception_code exc, Msgbuf_base &snd_msg) +{ + copy_msgbuf_to_utcb(utcb, snd_msg, exc.value); + + Nova::reply(Thread_base::myself()->stack_top()); +} + + void Rpc_entrypoint::_activation_entry() { /* retrieve portal id from eax/rdi */ @@ -115,32 +124,38 @@ void Rpc_entrypoint::_activation_entry() addr_t id_pt; asm volatile ("" : "=a" (id_pt)); #endif - Rpc_entrypoint *ep = static_cast(Thread_base::myself()); + Rpc_entrypoint &ep = *static_cast(Thread_base::myself()); + Nova::Utcb &utcb = *(Nova::Utcb *)Thread_base::myself()->utcb(); - /* required to decrease ref count of capability used during last reply */ - ep->_snd_buf.snd_reset(); + Receive_window &rcv_window = ep.native_thread().rcv_window; + rcv_window.post_ipc(utcb); - /* prepare ipc server object (copying utcb content to message buffer */ - Rpc_opcode opcode(0); - - Native_connection_state cs; - Ipc_server srv(cs, ep->_snd_buf, ep->_rcv_buf); - srv.reply_wait(); - srv.extract(opcode); - - /* set default return value */ - srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT)); - - /* in case of a portal cleanup call we are done here - just reply */ - if (ep->_cap.local_name() == id_pt) { - if (!ep->_rcv_buf.prepare_rcv_window((Nova::Utcb *)ep->utcb())) - PWRN("out of capability selectors for handling server requests"); - srv.reply(); + /* handle ill-formed message */ + if (utcb.msg_words() < 2) { + ep._rcv_buf.word(0) = ~0UL; /* invalid opcode */ + } else { + copy_utcb_to_msgbuf(utcb, rcv_window, ep._rcv_buf); } + Ipc_unmarshaller unmarshaller(ep._rcv_buf); + + Rpc_opcode opcode(0); + unmarshaller.extract(opcode); + + /* default return value */ + Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); + + /* in case of a portal cleanup call we are done here - just reply */ + if (ep._cap.local_name() == id_pt) { + if (!rcv_window.prepare_rcv_window(utcb)) + PWRN("out of capability selectors for handling server requests"); + + ep._rcv_buf.reset(); + reply(utcb, exc, ep._snd_buf); + } { /* potentially delay start */ - Lock::Guard lock_guard(ep->_delay_start); + Lock::Guard lock_guard(ep._delay_start); } /* atomically lookup and lock referenced object */ @@ -151,16 +166,27 @@ void Rpc_entrypoint::_activation_entry() return; } + /* + * Inhibit removal of capabilities sent as results of client requests. + * This prevents the recursive revocation of NOVA portal caps and, + * therefore, permits clients to use result capabilities after server + * code dropped all references. + */ + for (unsigned i = 0; i < ep._snd_buf.used_caps(); ++i) + ep._snd_buf.cap(i).keep_if_last_reference(); + /* dispatch request */ - try { srv.ret(obj->dispatch(opcode, srv, srv)); } + ep._snd_buf.reset(); + try { exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); } catch (Blocking_canceled) { } }; - ep->apply(id_pt, lambda); + ep.apply(id_pt, lambda); - if (!ep->_rcv_buf.prepare_rcv_window((Nova::Utcb *)ep->utcb())) + if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)ep.utcb())) PWRN("out of capability selectors for handling server requests"); - srv.reply(); + ep._rcv_buf.reset(); + reply(utcb, exc, ep._snd_buf); } @@ -220,8 +246,10 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size, if (!_cap.valid()) throw Cpu_session::Thread_creation_failed(); + Receive_window &rcv_window = Thread_base::native_thread().rcv_window; + /* prepare portal receive window of new thread */ - if (!_rcv_buf.prepare_rcv_window((Nova::Utcb *)&_stack->utcb())) + if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) throw Cpu_session::Thread_creation_failed(); if (start_on_construction) diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index 8c3fd9c44a..52ee95b5ca 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -33,6 +33,7 @@ /* NOVA includes */ #include +#include using namespace Genode; using namespace Nova; diff --git a/repos/base-nova/src/include/base/internal/ipc.h b/repos/base-nova/src/include/base/internal/ipc.h new file mode 100644 index 0000000000..3b046d92d4 --- /dev/null +++ b/repos/base-nova/src/include/base/internal/ipc.h @@ -0,0 +1,123 @@ +/* + * \brief IPC utility functions + * \author Norman Feske + * \date 2016-03-08 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__IPC_H_ +#define _INCLUDE__BASE__INTERNAL__IPC_H_ + +/* NOVA includes */ +#include +#include + +/** + * Copy message registers from UTCB to destination message buffer + * + * \return protocol word delivered via the first UTCB message register + * + * The caller of this function must ensure that utcb.msg_words is greater + * than 0. + */ +static inline Nova::mword_t copy_utcb_to_msgbuf(Nova::Utcb &utcb, + Genode::Receive_window &rcv_window, + Genode::Msgbuf_base &rcv_msg) +{ + using namespace Genode; + using namespace Nova; + + size_t num_msg_words = utcb.msg_words(); + + /* + * Handle the reception of a malformed message. This should never happen + * because the utcb.msg_words is checked by the caller of this function. + */ + if (num_msg_words < 1) + return 0; + + /* the UTCB contains the protocol word followed by the message data */ + mword_t const protocol_word = utcb.msg[0]; + size_t num_data_words = num_msg_words - 1; + + if (num_data_words*sizeof(mword_t) > rcv_msg.capacity()) { + PERR("receive message buffer too small msg size=%zx, buf size=%zd", + num_data_words*sizeof(mword_t), rcv_msg.capacity()); + num_data_words = rcv_msg.capacity()/sizeof(mword_t); + } + + /* read message payload into destination message buffer */ + mword_t *src = (mword_t *)(void *)(&utcb.msg[1]); + mword_t *dst = (mword_t *)rcv_msg.data(); + for (unsigned i = 0; i < num_data_words; i++) + *dst++ = *src++; + + /* extract caps from UTCB */ + for (unsigned i = 0; i < rcv_window.num_received_caps(); i++) { + Native_capability cap; + rcv_window.rcv_pt_sel(cap); + rcv_msg.insert(cap); + } + + return protocol_word; +} + + +/** + * Copy message payload to UTCB message registers + */ +static inline bool copy_msgbuf_to_utcb(Nova::Utcb &utcb, + Genode::Msgbuf_base const &snd_msg, + Nova::mword_t protocol_value) +{ + using namespace Genode; + using namespace Nova; + + /* look up address and size of message payload */ + mword_t *msg_buf = (mword_t *)snd_msg.data(); + + /* size of message payload in machine words */ + size_t const num_data_words = snd_msg.data_size()/sizeof(mword_t); + + /* account for protocol value in front of the message */ + size_t num_msg_words = 1 + num_data_words; + + enum { NUM_MSG_REGS = 256 }; + if (num_msg_words > NUM_MSG_REGS) { + PERR("Message does not fit into UTCB message registers\n"); + num_msg_words = NUM_MSG_REGS; + } + + utcb.msg[0] = protocol_value; + + /* store message into UTCB message registers */ + mword_t *src = (mword_t *)&msg_buf[0]; + mword_t *dst = (mword_t *)(void *)&utcb.msg[1]; + for (unsigned i = 0; i < num_data_words; i++) + *dst++ = *src++; + + utcb.set_msg_word(num_msg_words); + + /* append portal capability selectors */ + for (unsigned i = 0; i < snd_msg.used_caps(); i++) { + + Native_capability const &cap = snd_msg.cap(i); + Nova::Obj_crd crd(cap.local_name(), 0, cap.dst().rights()); + + if (crd.base() == ~0UL) continue; + + if (!utcb.append_item(crd, i, false, false, true)) + return false; + } + + return true; +} + + +#endif /* _INCLUDE__BASE__INTERNAL__IPC_H_ */ diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc index b953f72cad..4901435136 100644 --- a/repos/base-nova/src/test/platform/main.cc +++ b/repos/base-nova/src/test/platform/main.cc @@ -161,6 +161,9 @@ void test_server_oom() PINF("received %u. cap", i); } + /* XXX this code does does no longer work since the removal of 'solely_map' */ +#if 0 + /* case that during send we get oom */ for (unsigned i = 0; i < 20000; i++) { /* be evil and switch translation off - server ever uses a new selector */ @@ -176,6 +179,7 @@ void test_server_oom() if (i % 5000 == 4999) PINF("sent %u. cap", i); } +#endif ep.dissolve(&component); } diff --git a/repos/base-nova/src/test/platform/server.h b/repos/base-nova/src/test/platform/server.h index d0b09dd066..5452b6e5de 100644 --- a/repos/base-nova/src/test/platform/server.h +++ b/repos/base-nova/src/test/platform/server.h @@ -81,8 +81,13 @@ bool Test::Component::cap_void(Genode::Native_capability got_cap) { Genode::Native_capability Test::Component::void_cap() { Genode::Native_capability send_cap = cap(); + + /* XXX this code does does no longer work since the removal of 'solely_map' */ +#if 0 /* be evil and switch translation off - client ever uses a new selector */ send_cap.solely_map(); +#endif + return send_cap; } diff --git a/repos/base-okl4/include/base/ipc_msgbuf.h b/repos/base-okl4/include/base/ipc_msgbuf.h deleted file mode 100644 index e29d0ff212..0000000000 --- a/repos/base-okl4/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * \brief OKL4-specific layout of IPC message buffer - * \author Norman Feske - * \date 2009-03-25 - * - * On OKL4, we do not directly use the a kernel-specific message-buffer layout. - * The IPC goes through the UTCBs of the sending and receiving threads. Because - * on Genode, message buffers are decoupled from threads, we need to copy-in - * and copy-out the message payload between the message buffers and the used - * UTCBs. - */ - -/* - * Copyright (C) 2009-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -#include -#include - -namespace Genode { - - class Ipc_marshaller; - - /** - * IPC message buffer layout - */ - class Msgbuf_base - { - protected: - - size_t _data_size = 0; - size_t _capacity; - char _msg_start[]; /* symbol marks start of message */ - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - friend class Ipc_marshaller; - - public: - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; }; - - /** - * Return pointer of message data payload - */ - void *data() { return &_msg_start[0]; }; - void const *data() const { return &_msg_start[0]; }; - - size_t data_size() const { return _data_size; } - }; - - - /** - * Instance of IPC message buffer with specified buffer size - */ - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-okl4/lib/mk/base-common.mk b/repos/base-okl4/lib/mk/base-common.mk index bb85cbe9cc..2920278b0e 100644 --- a/repos/base-okl4/lib/mk/base-common.mk +++ b/repos/base-okl4/lib/mk/base-common.mk @@ -7,7 +7,7 @@ LIBS += cxx startup SRC_CC += cap_copy.cc -SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc +SRC_CC += ipc/ipc.cc SRC_CC += avl_tree/avl_tree.cc SRC_CC += allocator/slab.cc SRC_CC += allocator/allocator_avl.cc diff --git a/repos/base-okl4/src/base/ipc/ipc.cc b/repos/base-okl4/src/base/ipc/ipc.cc index d5c2adbfc5..6dcc5457cd 100644 --- a/repos/base-okl4/src/base/ipc/ipc.cc +++ b/repos/base-okl4/src/base/ipc/ipc.cc @@ -53,7 +53,9 @@ static void kdb_emergency_print(const char *s) * The message tag contains the information about the number of message words * to send. The tag is always supplied in message register 0. Message register * 1 is used for the local name (when the client calls the server) or the - * exception code (when the server replies to the client). All subsequent + * exception code (when the server replies to the client). Message register + * 2 holds the number of transferred capability arguments. It is followed + * by a tuple of (thread ID, local name) for each capability. All subsequent * message registers hold the message payload. */ @@ -64,43 +66,79 @@ static void kdb_emergency_print(const char *s) */ static L4_Word_t extract_msg_from_utcb(L4_MsgTag_t rcv_tag, Msgbuf_base &rcv_msg) { - unsigned num_msg_words = (int)L4_UntypedWords(rcv_tag); + rcv_msg.reset(); - if (num_msg_words*sizeof(L4_Word_t) > rcv_msg.capacity()) { - PERR("receive message buffer too small msg size=%zd, buf size=%zd", - num_msg_words*sizeof(L4_Word_t), rcv_msg.capacity()); - num_msg_words = rcv_msg.capacity()/sizeof(L4_Word_t); + unsigned const num_msg_words = (int)L4_UntypedWords(rcv_tag); + + if (num_msg_words < 3) + return Rpc_exception_code::INVALID_OBJECT; + + L4_Word_t protocol_word = 0; + L4_StoreMR(1, &protocol_word); + + L4_Word_t num_caps = 0; + L4_StoreMR(2, &num_caps); + + /* each capability is represened as two message words (tid, local name) */ + for (unsigned i = 0; i < num_caps; i++) { + L4_Word_t local_name = 0; + L4_ThreadId_t tid; + L4_StoreMR(3 + 2*i, &tid.raw); + L4_StoreMR(3 + 2*i + 1, &local_name); + rcv_msg.insert(Native_capability(tid, local_name)); } - L4_Word_t local_name = 0; - L4_StoreMR(1, &local_name); + unsigned const data_start_idx = 3 + 2*num_caps; + + if (num_msg_words < data_start_idx) + return Rpc_exception_code::INVALID_OBJECT; + + unsigned const num_data_words = num_msg_words - data_start_idx; + + if (num_data_words*sizeof(L4_Word_t) > rcv_msg.capacity()) { + PERR("receive message buffer too small msg size=%zd, buf size=%zd", + num_data_words*sizeof(L4_Word_t), rcv_msg.capacity()); + return Rpc_exception_code::INVALID_OBJECT; + } /* read message payload into destination message buffer */ - L4_StoreMRs(2, num_msg_words - 2, (L4_Word_t *)rcv_msg.data()); + L4_StoreMRs(data_start_idx, num_data_words, (L4_Word_t *)rcv_msg.data()); - return local_name; + rcv_msg.data_size(sizeof(num_data_words)); + + return protocol_word; } /** * Copy message payload to UTCB message registers */ -static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, unsigned num_msg_words, - L4_Word_t local_name) +static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, L4_Word_t local_name) { - num_msg_words += 2; + unsigned const num_header_words = 3 + 2*snd_msg.used_caps(); + unsigned const num_data_words = snd_msg.data_size()/sizeof(L4_Word_t); + unsigned const num_msg_words = num_data_words + num_header_words; if (num_msg_words >= L4_GetMessageRegisters()) { kdb_emergency_print("Message does not fit into UTCB message registers\n"); - num_msg_words = L4_GetMessageRegisters() - 1; + L4_LoadMR(0, 0); + return; } L4_MsgTag_t snd_tag; snd_tag.raw = 0; snd_tag.X.u = num_msg_words; - L4_LoadMR (0, snd_tag.raw); - L4_LoadMR (1, local_name); - L4_LoadMRs(2, num_msg_words - 2, (L4_Word_t *)snd_msg.data()); + + L4_LoadMR(0, snd_tag.raw); + L4_LoadMR(1, local_name); + L4_LoadMR(2, snd_msg.used_caps()); + + for (unsigned i = 0; i < snd_msg.used_caps(); i++) { + L4_LoadMR(3 + i*2, snd_msg.cap(i).dst().raw); + L4_LoadMR(3 + i*2 + 1, snd_msg.cap(i).local_name()); + } + + L4_LoadMRs(num_header_words, num_data_words, (L4_Word_t *)snd_msg.data()); } @@ -113,8 +151,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, size_t) { /* copy call message to the UTCBs message registers */ - copy_msg_to_utcb(snd_msg, snd_msg.data_size()/sizeof(L4_Word_t), - dst.local_name()); + copy_msg_to_utcb(snd_msg, dst.local_name()); L4_Accept(L4_UntypedWordsAcceptor); @@ -136,54 +173,46 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::_prepare_next_reply_wait() -{ - _reply_needed = true; - _read_offset = _write_offset = 0; -} - - -void Ipc_server::reply() +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { /* copy reply to the UTCBs message registers */ - copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t), - _exception_code.value); + copy_msg_to_utcb(snd_msg, exc.value); /* perform non-blocking IPC send operation */ - L4_MsgTag_t rcv_tag = L4_Reply(_caller.dst()); + L4_MsgTag_t rcv_tag = L4_Reply(caller.dst()); if (L4_IpcFailed(rcv_tag)) PERR("ipc error in _reply - gets ignored"); - - _prepare_next_reply_wait(); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { L4_MsgTag_t rcv_tag; - if (_reply_needed) { + Okl4::L4_ThreadId_t caller = L4_nilthread; + + if (last_caller.valid()) { /* copy reply to the UTCBs message registers */ - copy_msg_to_utcb(_snd_msg, _write_offset/sizeof(L4_Word_t), - _exception_code.value); + copy_msg_to_utcb(reply_msg, exc.value); - rcv_tag = L4_ReplyWait(_caller.dst(), &_rcv_cs.caller); + rcv_tag = L4_ReplyWait(last_caller.dst(), &caller); } else { - rcv_tag = L4_Wait(&_rcv_cs.caller); + rcv_tag = L4_Wait(&caller); } /* copy request message from the UTCBs message registers */ - _badge = extract_msg_from_utcb(rcv_tag, _rcv_msg); + unsigned long const badge = extract_msg_from_utcb(rcv_tag, request_msg); - /* define destination of next reply */ - _caller = Native_capability(_rcv_cs.caller, badge()); - - _prepare_next_reply_wait(); + return Rpc_request(Native_capability(caller, 0), badge); } @@ -202,14 +231,7 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id() } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) -: - Ipc_marshaller(snd_msg), - Ipc_unmarshaller(rcv_msg), - Native_capability(thread_get_my_global_id(), 0), - _rcv_cs(cs) -{ } +Ipc_server::Ipc_server() : Native_capability(thread_get_my_global_id(), 0) { } Ipc_server::~Ipc_server() { } diff --git a/repos/base-okl4/src/core/pager_object.cc b/repos/base-okl4/src/core/pager_object.cc new file mode 100644 index 0000000000..bb3adab879 --- /dev/null +++ b/repos/base-okl4/src/core/pager_object.cc @@ -0,0 +1,50 @@ +/* + * \brief Kernel-specific RM-faulter wake-up mechanism + * \author Norman Feske + * \date 2016-04-12 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* core includes */ +#include + +/* OKL4 includes */ +namespace Okl4 { extern "C" { +#include +#include +} } + +using namespace Genode; + + +void Pager_object::wake_up() +{ + using namespace Okl4; + + /* + * Issue IPC to pager, transmitting the pager-object pointer as 'IP'. + */ + L4_Accept(L4_UntypedWordsAcceptor); + + L4_MsgTag_t snd_tag; + snd_tag.raw = 0; + snd_tag.X.u = 2; + + L4_LoadMR(0, snd_tag.raw); + L4_LoadMR(1, 0); /* fault address */ + L4_LoadMR(2, (unsigned long)this); /* instruction pointer */ + + L4_Call(cap().dst()); +} + + +void Pager_object::unresolved_page_fault_occurred() +{ + state.unresolved_page_fault = true; +} diff --git a/repos/base-okl4/src/core/target.inc b/repos/base-okl4/src/core/target.inc index a5f40be42d..014c44bda8 100644 --- a/repos/base-okl4/src/core/target.inc +++ b/repos/base-okl4/src/core/target.inc @@ -62,7 +62,6 @@ vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) vpath dump_alloc.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) -vpath pager_object.cc $(GEN_CORE_DIR) vpath %.cc $(REP_DIR)/src/core vpath core_printf.cc $(BASE_DIR)/src/base/console diff --git a/repos/base-okl4/src/include/base/internal/native_connection_state.h b/repos/base-okl4/src/include/base/internal/native_connection_state.h deleted file mode 100644 index 3f1215927e..0000000000 --- a/repos/base-okl4/src/include/base/internal/native_connection_state.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * \brief Connection state - * \author Norman Feske - * \date 2016-03-11 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ -#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ - -#include - -namespace Genode { struct Native_connection_state; } - - -struct Genode::Native_connection_state -{ - Okl4::L4_ThreadId_t caller; -}; - -#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */ diff --git a/repos/base-pistachio/include/base/ipc_msgbuf.h b/repos/base-pistachio/include/base/ipc_msgbuf.h deleted file mode 100644 index 58049f8850..0000000000 --- a/repos/base-pistachio/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * \brief Pistachio-specific layout of IPC message buffer - * \author Julian Stecklina - * \date 2007-01-10 - */ - -/* - * Copyright (C) 2007-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -namespace Genode { - - class Ipc_marshaller; - - /** - * IPC message buffer layout - */ - class Msgbuf_base - { - protected: - - friend class Ipc_marshaller; - - size_t const _capacity; - - size_t _data_size = 0; - - char _msg_start[]; /* symbol marks start of message */ - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - public: - - /* - * Begin of message buffer layout - */ - Pistachio::L4_Fpage_t rcv_fpage; - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; }; - - /** - * Return pointer of message data payload - */ - void *data() { return &_msg_start[0]; }; - void const *data() const { return &_msg_start[0]; }; - - size_t data_size() const { return _data_size; } - }; - - - /** - * Instance of IPC message buffer with specified buffer size - */ - template - class Msgbuf : public Msgbuf_base - { - public: - - char buf[BUF_SIZE]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } - }; -} - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-pistachio/lib/mk/base-common.mk b/repos/base-pistachio/lib/mk/base-common.mk index 58e8e974dc..7717bb8135 100644 --- a/repos/base-pistachio/lib/mk/base-common.mk +++ b/repos/base-pistachio/lib/mk/base-common.mk @@ -7,7 +7,7 @@ LIBS += cxx startup syscall SRC_CC += cap_copy.cc -SRC_CC += ipc/ipc.cc ipc/ipc_marshal_cap.cc +SRC_CC += ipc/ipc.cc SRC_CC += avl_tree/avl_tree.cc SRC_CC += allocator/slab.cc SRC_CC += allocator/allocator_avl.cc diff --git a/repos/base-pistachio/src/base/ipc/ipc.cc b/repos/base-pistachio/src/base/ipc/ipc.cc index fe7391432f..ae07e5c8b3 100644 --- a/repos/base-pistachio/src/base/ipc/ipc.cc +++ b/repos/base-pistachio/src/base/ipc/ipc.cc @@ -68,19 +68,62 @@ static inline void check_ipc_result(L4_MsgTag_t result, L4_Word_t error_code) throw Genode::Ipc_error(); } - if (L4_UntypedWords(result) != 1) { - PERR("Error in thread %08lx. Expected one untyped word (local_name), but got %lu.\n", + if (L4_UntypedWords(result) < 2) { + PERR("Error in thread %08lx. Expected at leat two untyped words, but got %lu.\n", L4_Myself().raw, L4_UntypedWords(result)); + throw Genode::Ipc_error(); + } +} - PERR("This should not happen. Inspect!"); - throw Genode::Ipc_error(); + +/** + * Configure L4 receive buffer according to Genode receive buffer + */ +static void extract_caps(L4_Msg_t &msg, Msgbuf_base &rcv_msg) +{ + using namespace Pistachio; + + L4_Word_t const num_caps = min((unsigned)Msgbuf_base::MAX_CAPS_PER_MSG, + L4_Get(&msg, 1)); + for (unsigned i = 0; i < num_caps; i++) { + + L4_ThreadId_t tid; + tid.raw = L4_Get(&msg, 2 + i*2); + + L4_Word_t const local_name = L4_Get(&msg, 2 + i*2 + 1); + + rcv_msg.insert(Native_capability(tid, local_name)); } - if (L4_TypedWords(result) != 2) { - PERR("Error. Expected two typed words (a string item). but got %lu.\n", - L4_TypedWords(result)); - PERR("This should not happen. Inspect!"); - throw Genode::Ipc_error(); +} + + +/** + * Configure L4 message descriptor according to Genode send buffer + */ +static void prepare_send(L4_Word_t protocol_value, L4_Msg_t &msg, + Msgbuf_base &snd_msg) +{ + L4_Clear(&msg); + L4_Append(&msg, protocol_value); + + L4_Append(&msg, (L4_Word_t)snd_msg.used_caps()); + + for (unsigned i = 0; i < snd_msg.used_caps(); i++) { + L4_Append(&msg, (L4_Word_t)snd_msg.cap(i).dst().raw); + L4_Append(&msg, (L4_Word_t)snd_msg.cap(i).local_name()); } + + L4_Append(&msg, L4_StringItem(snd_msg.data_size(), snd_msg.data())); + L4_Load(&msg); +} + + +static void prepare_receive(L4_MsgBuffer_t &l4_msgbuf, Msgbuf_base &rcv_msg) +{ + L4_Clear(&l4_msgbuf); + L4_Append(&l4_msgbuf, L4_StringItem(rcv_msg.capacity(), rcv_msg.data())); + L4_Accept(L4_UntypedWordsAcceptor); + L4_Accept(L4_StringItemsAcceptor, &l4_msgbuf); } @@ -92,23 +135,13 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, size_t) { - L4_Msg_t msg; - L4_StringItem_t sitem = L4_StringItem(snd_msg.data_size(), snd_msg.data()); - L4_Word_t const local_name = dst.local_name(); - + /* prepare receive message buffer */ L4_MsgBuffer_t msgbuf; - - /* prepare message buffer */ - L4_Clear (&msgbuf); - L4_Append (&msgbuf, L4_StringItem (rcv_msg.capacity(), rcv_msg.data())); - L4_Accept(L4_UntypedWordsAcceptor); - L4_Accept(L4_StringItemsAcceptor, &msgbuf); + prepare_receive(msgbuf, rcv_msg); /* prepare sending parameters */ - L4_Clear(&msg); - L4_Append(&msg, local_name); - L4_Append(&msg, sitem); - L4_Load(&msg); + L4_Msg_t msg; + prepare_send(dst.local_name(), msg, snd_msg); L4_MsgTag_t result = L4_Call(dst.dst()); @@ -117,67 +150,56 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, check_ipc_result(result, L4_ErrorCode()); + extract_caps(msg, rcv_msg); + return Rpc_exception_code(L4_Get(&msg, 0)); } /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::_prepare_next_reply_wait() -{ - _reply_needed = true; - _read_offset = _write_offset = 0; -} - - -void Ipc_server::reply() +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { L4_Msg_t msg; - L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data()); - L4_Word_t const local_name = _caller.local_name(); + prepare_send(exc.value, msg, snd_msg); - L4_Clear(&msg); - L4_Append(&msg, local_name); - L4_Append(&msg, sitem); - L4_Load(&msg); - - L4_MsgTag_t result = L4_Reply(_caller.dst()); + L4_MsgTag_t result = L4_Reply(caller.dst()); if (L4_IpcFailed(result)) PERR("ipc error in _reply, ignored"); - _prepare_next_reply_wait(); + snd_msg.reset(); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { bool need_to_wait = true; L4_MsgTag_t request_tag; - /* prepare request message buffer */ - L4_MsgBuffer_t request_msgbuf; - L4_Clear(&request_msgbuf); - L4_Append(&request_msgbuf, L4_StringItem (_rcv_msg.capacity(), _rcv_msg.data())); - L4_Accept(L4_UntypedWordsAcceptor); - L4_Accept(L4_StringItemsAcceptor, &request_msgbuf); + request_msg.reset(); - if (_reply_needed) { + /* prepare receive buffer for request */ + L4_MsgBuffer_t request_msgbuf; + prepare_receive(request_msgbuf, request_msg); + + L4_ThreadId_t caller = L4_nilthread; + + if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT) { /* prepare reply massage */ - L4_Msg_t reply_msg; - L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data()); - - L4_Clear(&reply_msg); - L4_Append(&reply_msg, (L4_Word_t)_exception_code.value); - L4_Append(&reply_msg, sitem); - L4_Load(&reply_msg); + L4_Msg_t reply_l4_msg; + prepare_send(exc.value, reply_l4_msg, reply_msg); /* send reply and wait for new request message */ - request_tag = L4_Ipc(_caller.dst(), L4_anythread, - L4_Timeouts(L4_ZeroTime, L4_Never), &_rcv_cs.caller); + request_tag = L4_Ipc(last_caller.dst(), L4_anythread, + L4_Timeouts(L4_ZeroTime, L4_Never), &caller); if (!L4_IpcFailed(request_tag)) need_to_wait = false; @@ -186,7 +208,7 @@ void Ipc_server::reply_wait() while (need_to_wait) { /* wait for new request message */ - request_tag = L4_Wait(&_rcv_cs.caller); + request_tag = L4_Wait(&caller); if (!L4_IpcFailed(request_tag)) need_to_wait = false; @@ -196,26 +218,14 @@ void Ipc_server::reply_wait() L4_Msg_t msg; L4_Clear(&msg); L4_Store(request_tag, &msg); + extract_caps(msg, request_msg); - /* remember badge of invoked object */ - _badge = L4_Get(&msg, 0); - - /* define destination of next reply */ - _caller = Native_capability(_rcv_cs.caller, badge()); - - _prepare_next_reply_wait(); + unsigned long const badge = L4_Get(&msg, 0); + return Rpc_request(Native_capability(caller, 0), badge); } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) -: - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), - Native_capability(Pistachio::L4_Myself(), 0), - _rcv_cs(cs) -{ - _read_offset = _write_offset = 0; -} +Ipc_server::Ipc_server() : Native_capability(Pistachio::L4_Myself(), 0) { } Ipc_server::~Ipc_server() { } diff --git a/repos/base-pistachio/src/core/pager.cc b/repos/base-pistachio/src/core/pager.cc index c0f79c88ff..cfeb6d2040 100644 --- a/repos/base-pistachio/src/core/pager.cc +++ b/repos/base-pistachio/src/core/pager.cc @@ -132,10 +132,7 @@ void Ipc_pager::reply_and_wait_for_fault() void Ipc_pager::acknowledge_wakeup() { - PERR("acknowledge_wakeup called, not yet implemented"); -// /* answer wakeup call from one of core's region-manager sessions */ -// l4_msgdope_t result; -// l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result); + L4_Reply(_last); } diff --git a/repos/base-pistachio/src/core/pager_object.cc b/repos/base-pistachio/src/core/pager_object.cc new file mode 100644 index 0000000000..0165684d55 --- /dev/null +++ b/repos/base-pistachio/src/core/pager_object.cc @@ -0,0 +1,50 @@ +/* + * \brief Kernel-specific RM-faulter wake-up mechanism + * \author Norman Feske + * \date 2016-04-12 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* core includes */ +#include + +/* Pistachio includes */ +namespace Pistachio { +#include +#include +} + +using namespace Genode; + + +void Pager_object::wake_up() +{ + using namespace Pistachio; + + /* + * Issue IPC to pager, transmitting the pager-object pointer as 'IP'. + */ + L4_Accept(L4_UntypedWordsAcceptor); + + L4_MsgTag_t snd_tag; + snd_tag.raw = 0; + snd_tag.X.u = 2; + + L4_LoadMR(0, snd_tag.raw); + L4_LoadMR(1, 0); /* fault address */ + L4_LoadMR(2, (unsigned long)this); /* instruction pointer */ + + L4_Call(cap().dst()); +} + + +void Pager_object::unresolved_page_fault_occurred() +{ + state.unresolved_page_fault = true; +} diff --git a/repos/base-pistachio/src/core/target.inc b/repos/base-pistachio/src/core/target.inc index 69fd7d9f60..ef57fe5b6b 100644 --- a/repos/base-pistachio/src/core/target.inc +++ b/repos/base-pistachio/src/core/target.inc @@ -61,7 +61,6 @@ vpath dump_alloc.cc $(GEN_CORE_DIR) vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) -vpath pager_object.cc $(GEN_CORE_DIR) vpath core_printf.cc $(BASE_DIR)/src/base/console vpath kip.cc $(REP_DIR)/src/base/kip vpath %.cc $(REP_DIR)/src/core diff --git a/repos/base-pistachio/src/include/base/internal/native_connection_state.h b/repos/base-pistachio/src/include/base/internal/native_connection_state.h deleted file mode 100644 index 1620cb0ed2..0000000000 --- a/repos/base-pistachio/src/include/base/internal/native_connection_state.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief Connection state - * \author Norman Feske - * \date 2016-03-11 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ -#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ - -/* Pistachio includes */ -namespace Pistachio { -#include -} - -namespace Genode { struct Native_connection_state; } - - -struct Genode::Native_connection_state -{ - Pistachio::L4_ThreadId_t caller; -}; - -#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */ diff --git a/repos/base-sel4/include/base/ipc_msgbuf.h b/repos/base-sel4/include/base/ipc_msgbuf.h deleted file mode 100644 index 392f0bc16e..0000000000 --- a/repos/base-sel4/include/base/ipc_msgbuf.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * \brief IPC message buffer layout - * \author Norman Feske - * \date 2015-05-10 - */ - -/* - * Copyright (C) 2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ -#define _INCLUDE__BASE__IPC_MSGBUF_H_ - -#include - -namespace Genode { - - class Msgbuf_base; - template struct Msgbuf; - - class Ipc_marshaller; -} - - -class Genode::Msgbuf_base -{ - public: - - enum { MAX_CAPS_PER_MSG = 3 }; - - protected: - - friend class Ipc_marshaller; - - /* - * Resolve ambiguity if the header is included from a libc-using - * program. - */ - typedef Genode::size_t size_t; - - /* - * Capabilities to be transferred - */ - Native_capability _caps[MAX_CAPS_PER_MSG]; - size_t _used_caps = 0; - size_t _read_cap_index = 0; - - /** - * Maximum size of plain-data message payload - */ - size_t const _capacity; - - /** - * Actual size of plain-data message payload - */ - size_t _data_size = 0; - - char _msg_start[]; /* symbol marks start of message buffer data */ - - /* - * No member variables are allowed beyond this point! - */ - - Msgbuf_base(size_t capacity) : _capacity(capacity) { } - - public: - - char buf[]; - - /** - * Return size of message buffer - */ - size_t capacity() const { return _capacity; }; - - void reset_caps() - { - for (Genode::size_t i = 0; i < _used_caps; i++) - _caps[i] = Native_capability(); - - _used_caps = 0; - } - - void reset_read_cap_index() - { - _read_cap_index = 0; - } - - /** - * Return pointer to start of message-buffer content - */ - void const *data() const { return &_msg_start[0]; }; - void *data() { return &_msg_start[0]; }; - - size_t data_size() const { return _data_size; } - - /** - * Exception type - */ - class Too_many_caps : public Exception { }; - - /** - * Called from '_marshal_capability' - */ - void append_cap(Native_capability const &cap) - { - if (_used_caps == MAX_CAPS_PER_MSG) - throw Too_many_caps(); - - _caps[_used_caps++] = cap; - } - - /** - * Called from '_unmarshal_capability' - */ - Native_capability extract_cap() - { - if (_read_cap_index == _used_caps) - return Native_capability(); - - return _caps[_read_cap_index++]; - } - - /** - * Return number of marshalled capabilities - */ - size_t used_caps() const { return _used_caps; } - - Native_capability &cap(unsigned index) { return _caps[index]; } - Native_capability const &cap(unsigned index) const { return _caps[index]; } -}; - - -template -struct Genode::Msgbuf : Msgbuf_base -{ - /** - * Pump up IPC message buffer to specified buffer size - * - * XXX remove padding of 16 - */ - char buf[BUF_SIZE + 16]; - - Msgbuf() : Msgbuf_base(BUF_SIZE) { } -}; - - -#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base-sel4/src/base/ipc/ipc.cc b/repos/base-sel4/src/base/ipc/ipc.cc index 8276840394..7ef0b2314d 100644 --- a/repos/base-sel4/src/base/ipc/ipc.cc +++ b/repos/base-sel4/src/base/ipc/ipc.cc @@ -63,11 +63,9 @@ static unsigned &rcv_sel() /** * Convert Genode::Msgbuf_base content into seL4 message * - * \param msg source message buffer - * \param data_length size of message data in bytes + * \param msg source message buffer */ -static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg, - size_t const data_length) +static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg) { /* * Supply capabilities to kernel IPC message @@ -107,7 +105,7 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg, * Supply data payload */ size_t const num_data_mwords = - align_natural(data_length) / sizeof(umword_t); + align_natural(msg.data_size()) / sizeof(umword_t); umword_t const *src = (umword_t const *)msg.data(); for (size_t i = 0; i < num_data_mwords; i++) @@ -129,7 +127,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, /* * Extract Genode capabilities from seL4 IPC message */ - dst_msg.reset_caps(); + dst_msg.reset(); size_t const num_caps = seL4_GetMR(MR_IDX_NUM_CAPS); size_t curr_sel4_cap_idx = 0; @@ -153,7 +151,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, * Hence it is meaningless as a key. */ if (!rpc_obj_key.valid() && seL4_MessageInfo_get_extraCaps(msg_info) == 0) { - dst_msg.append_cap(Native_capability()); + dst_msg.insert(Native_capability()); continue; } @@ -185,7 +183,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, Native_capability arg_cap = Capability_space::lookup(rpc_obj_key); - dst_msg.append_cap(arg_cap); + dst_msg.insert(arg_cap); } else { @@ -224,14 +222,14 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, Capability_space::reset_sel(rcv_sel()); - dst_msg.append_cap(arg_cap); + dst_msg.insert(arg_cap); } else { Capability_space::Ipc_cap_data const ipc_cap_data(rpc_obj_key, rcv_sel()); - dst_msg.append_cap(Capability_space::import(ipc_cap_data)); + dst_msg.insert(Capability_space::import(ipc_cap_data)); /* * Since we keep using the received selector, we need to @@ -247,25 +245,21 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, * Extract message data payload */ + size_t const num_msg_words = seL4_MessageInfo_get_length(msg_info); + + /* detect malformed message with too small header */ + if (num_msg_words < MR_IDX_DATA) + return; + + /* copy data payload */ + size_t const max_words = dst_msg.capacity()/sizeof(umword_t); + size_t const num_data_words = min(num_msg_words - MR_IDX_DATA, max_words); + umword_t *dst = (umword_t *)dst_msg.data(); - for (size_t i = 0; i < seL4_MessageInfo_get_length(msg_info); i++) + for (size_t i = 0; i < num_data_words; i++) *dst++ = seL4_GetMR(MR_IDX_DATA + i); -} - -/***************************** - ** IPC marshalling support ** - *****************************/ - -void Ipc_marshaller::insert(Native_capability const &cap) -{ - _snd_msg.append_cap(cap); -} - - -void Ipc_unmarshaller::extract(Native_capability &cap) -{ - cap = _rcv_msg.extract_cap(); + dst_msg.data_size(num_data_words*sizeof(umword_t)); } @@ -285,8 +279,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, if (!rcv_sel()) rcv_sel() = Capability_space::alloc_rcv_sel(); - seL4_MessageInfo_t const request_msg_info = - new_seL4_message(snd_msg, snd_msg.data_size()); + seL4_MessageInfo_t const request_msg_info = new_seL4_message(snd_msg); unsigned const dst_sel = Capability_space::ipc_cap_data(dst).sel.value(); @@ -300,55 +293,51 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, /**************** - ** Ipc_server ** + ** IPC server ** ****************/ -void Ipc_server::reply() +void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc, + Msgbuf_base &snd_msg) { ASSERT(false); } -void Ipc_server::reply_wait() +Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, + Rpc_exception_code exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg) { - if (!_reply_needed) { + seL4_Word badge = 0; - seL4_MessageInfo_t const msg_info = - seL4_Recv(Thread_base::myself()->native_thread().ep_sel, - (seL4_Word *)&_badge); + if (exc.value == Rpc_exception_code::INVALID_OBJECT) { - decode_seL4_message(msg_info, _rcv_msg); + seL4_MessageInfo_t const request_msg_info = + seL4_Recv(Thread_base::myself()->native_thread().ep_sel, &badge); + + decode_seL4_message(request_msg_info, request_msg); } else { - seL4_MessageInfo_t const reply_msg_info = - new_seL4_message(_snd_msg, _write_offset); + seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg); - seL4_SetMR(MR_IDX_EXC_CODE, _exception_code.value); + seL4_SetMR(MR_IDX_EXC_CODE, exc.value); seL4_MessageInfo_t const request_msg_info = seL4_ReplyRecv(Thread_base::myself()->native_thread().ep_sel, - reply_msg_info, (seL4_Word *)&_badge); + reply_msg_info, &badge); - decode_seL4_message(request_msg_info, _rcv_msg); + decode_seL4_message(request_msg_info, request_msg); } - _reply_needed = true; - _read_offset = _write_offset = 0; - - _rcv_msg.reset_read_cap_index(); - _snd_msg.reset_caps(); + return Rpc_request(Native_capability(), badge); } -Ipc_server::Ipc_server(Native_connection_state &cs, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg) +Ipc_server::Ipc_server() : - Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _rcv_cs(cs) -{ - *static_cast(this) = - Native_capability(Capability_space::create_ep_cap(*Thread_base::myself())); -} + Native_capability(Capability_space::create_ep_cap(*Thread_base::myself())) +{ } Ipc_server::~Ipc_server() { } diff --git a/repos/base-sel4/src/base/server/server.cc b/repos/base-sel4/src/base/server/server.cc deleted file mode 100644 index 3e7cd26fbc..0000000000 --- a/repos/base-sel4/src/base/server/server.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * \brief Default version of platform-specific part of server framework - * \author Norman Feske - * \author Stefan Kalkowski - * \date 2006-05-12 - * - * This version is suitable for platforms similar to L4. Each platform - * for which this implementation is not suited contains a platform- - * specific version in its respective 'base-' repository. - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode includes */ -#include - -/* base-internal includes */ -#include -#include - -using namespace Genode; - - -/*********************** - ** Server entrypoint ** - ***********************/ - -Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) -{ - Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap); - - /* add server object to object pool */ - obj->cap(new_obj_cap); - insert(obj); - - /* return capability that uses the object id as badge */ - return new_obj_cap; -} - - -void Rpc_entrypoint::entry() -{ - Native_connection_state cs; - Ipc_server srv(cs, _snd_buf, _rcv_buf); - _ipc_server = &srv; - _cap = srv; - _cap_valid.unlock(); - - /* - * Now, the capability of the server activation is initialized - * an can be passed around. However, the processing of capability - * invocations should not happen until activation-using server - * is completely initialized. Thus, we wait until the activation - * gets explicitly unblocked by calling 'Rpc_entrypoint::activate()'. - */ - _delay_start.lock(); - - while (!_exit_handler.exit) { - - Rpc_opcode opcode(0); - - srv.reply_wait(); - srv.extract(opcode); - - /* set default return value */ - srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT)); - - /* atomically lookup and lock referenced object */ - auto lambda = [&] (Rpc_object_base *obj) { - if (!obj) return; - - /* dispatch request */ - try { srv.ret(obj->dispatch(opcode, srv, srv)); } - catch (Blocking_canceled) { } - }; - apply(srv.badge(), lambda); - } - - /* answer exit call, thereby wake up '~Rpc_entrypoint' */ - srv.reply(); - - /* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */ - _delay_exit.lock(); -} diff --git a/repos/base/include/base/capability.h b/repos/base/include/base/capability.h index fdf6ee9b05..c22cfe0a87 100644 --- a/repos/base/include/base/capability.h +++ b/repos/base/include/base/capability.h @@ -25,8 +25,8 @@ namespace Genode { /** * Forward declaration needed for internal interfaces of 'Capability' */ - class Ipc_marshaller; class Ipc_unmarshaller; + class Msgbuf_base; /** @@ -58,9 +58,9 @@ class Genode::Capability : public Untyped_capability * Insert RPC arguments into the message buffer */ template - void _marshal_args(Ipc_marshaller &, ATL &args) const; + void _marshal_args(Msgbuf_base &, ATL &args) const; - void _marshal_args(Ipc_marshaller &, Meta::Empty &) const { } + void _marshal_args(Msgbuf_base &, Meta::Empty &) const { } /** * Unmarshal single RPC argument from the message buffer diff --git a/repos/base/include/base/ipc.h b/repos/base/include/base/ipc.h index 18816ad05d..0757b48c79 100644 --- a/repos/base/include/base/ipc.h +++ b/repos/base/include/base/ipc.h @@ -14,19 +14,14 @@ #ifndef _INCLUDE__BASE__IPC_H_ #define _INCLUDE__BASE__IPC_H_ -#include -#include -#include -#include -#include #include #include #include namespace Genode { - class Ipc_error; - class Ipc_marshaller; + struct Ipc_error : Exception { }; + class Ipc_unmarshaller; /** @@ -46,84 +41,6 @@ namespace Genode { } -/** - * Exception type - */ -class Genode::Ipc_error : public Exception { }; - - -/** - * Marshal arguments into send message buffer - */ -class Genode::Ipc_marshaller : Noncopyable -{ - protected: - - Msgbuf_base &_snd_msg; - size_t &_write_offset = _snd_msg._data_size; - - private: - - char *_snd_buf = (char *)_snd_msg.data(); - size_t const _snd_buf_size = _snd_msg.capacity(); - - public: - - /** - * Write value to send buffer - */ - template - void insert(T const &value) - { - /* check buffer range */ - if (_write_offset + sizeof(T) >= _snd_buf_size) return; - - /* write integer to buffer */ - *reinterpret_cast(&_snd_buf[_write_offset]) = value; - - /* increment write pointer to next dword-aligned value */ - _write_offset += align_natural(sizeof(T)); - } - - template - void insert(Rpc_in_buffer const &b) - { - size_t const size = b.size(); - insert(size); - insert(b.base(), size); - } - - /** - * Write bytes to send buffer - */ - void insert(char const *src_addr, unsigned num_bytes) - { - /* check buffer range */ - if (_write_offset + num_bytes >= _snd_buf_size) return; - - /* copy buffer */ - memcpy(&_snd_buf[_write_offset], src_addr, num_bytes); - - /* increment write pointer to next dword-aligned value */ - _write_offset += align_natural(num_bytes); - } - - /** - * Insert capability to message buffer - */ - void insert(Native_capability const &cap); - - template - void insert(Capability const &typed_cap) - { - Native_capability untyped_cap = typed_cap; - insert(untyped_cap); - } - - Ipc_marshaller(Msgbuf_base &snd_msg) : _snd_msg(snd_msg) { } -}; - - /** * Unmarshal arguments from receive buffer */ @@ -131,8 +48,9 @@ class Genode::Ipc_unmarshaller : Noncopyable { protected: - Msgbuf_base &_rcv_msg; - unsigned _read_offset = 0; + Msgbuf_base &_rcv_msg; + unsigned _read_offset = 0; + unsigned _read_cap_index = 0; private: @@ -141,6 +59,9 @@ class Genode::Ipc_unmarshaller : Noncopyable public: + /** + * Obtain typed capability from message buffer + */ template void extract(Capability &typed_cap) { @@ -149,6 +70,16 @@ class Genode::Ipc_unmarshaller : Noncopyable typed_cap = reinterpret_cap_cast(untyped_cap); } + /** + * Obtain capability from message buffer + */ + void extract(Native_capability &cap) + { + cap = _read_cap_index < _rcv_msg.used_caps() + ? _rcv_msg.cap(_read_cap_index) : Native_capability(); + _read_cap_index++; + } + /** * Read 'Rpc_in_buffer' from receive buffer */ @@ -165,7 +96,7 @@ class Genode::Ipc_unmarshaller : Noncopyable * Note: The addr of the Rpc_in_buffer_base is a null pointer when this * condition triggers. */ - if (_read_offset + size >= _rcv_buf_size) { + if (_read_offset + size > _rcv_buf_size) { PERR("message buffer overrun"); return; } @@ -174,11 +105,6 @@ class Genode::Ipc_unmarshaller : Noncopyable _read_offset += align_natural(size); } - /** - * Obtain capability from message buffer - */ - void extract(Native_capability &cap); - /** * Read value of type T from buffer */ @@ -186,7 +112,7 @@ class Genode::Ipc_unmarshaller : Noncopyable void extract(T &value) { /* check receive buffer range */ - if (_read_offset + sizeof(T) >= _rcv_buf_size) return; + if (_read_offset + sizeof(T) > _rcv_buf_size) return; /* return value from receive buffer */ value = *reinterpret_cast(&_rcv_buf[_read_offset]); @@ -195,8 +121,6 @@ class Genode::Ipc_unmarshaller : Noncopyable _read_offset += align_natural(sizeof(T)); } - public: - Ipc_unmarshaller(Msgbuf_base &rcv_msg) : _rcv_msg(rcv_msg) { } }; diff --git a/repos/base/include/base/ipc_msgbuf.h b/repos/base/include/base/ipc_msgbuf.h new file mode 100644 index 0000000000..a8493a4b58 --- /dev/null +++ b/repos/base/include/base/ipc_msgbuf.h @@ -0,0 +1,244 @@ +/* + * \brief IPC message buffer layout + * \author Norman Feske + * \date 2015-05-10 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_ +#define _INCLUDE__BASE__IPC_MSGBUF_H_ + +#include +#include +#include +#include +#include + +namespace Genode { + + class Msgbuf_base; + template class Msgbuf; +} + + +class Genode::Msgbuf_base : Noncopyable +{ + public: + + enum { MAX_CAPS_PER_MSG = 4 }; + + private: + + /* + * Resolve ambiguity if the header is included from a libc-using + * program. + */ + typedef Genode::size_t size_t; + + /* + * Capabilities to be transferred + */ + Native_capability _caps[MAX_CAPS_PER_MSG]; + + /** + * Number of marshalled capabilities + */ + size_t _used_caps = 0; + + /** + * Pointer to buffer for data payload + */ + char * const _data; + + /** + * Maximum size of plain-data message payload + */ + size_t const _capacity; + + /** + * Actual size of plain-data message payload + */ + size_t _data_size = 0; + + char *_data_last() { return &_data[_data_size]; } + + void _clear(size_t const num_bytes) + { + size_t const num_words = min(num_bytes, _capacity)/sizeof(long); + for (unsigned i = 0; i < num_words; i++) + word(i) = 0; + } + + protected: + + struct Headroom { long space[16]; }; + + Msgbuf_base(char *buf, size_t capacity) + : + _data(buf), _capacity(capacity) + { + _clear(capacity); + } + + public: + + /** + * Return reference to platform-specific header in front of the message + */ + template + T &header() + { + static_assert(sizeof(T) <= sizeof(Headroom), + "Header size exceeds message headroom"); + return *reinterpret_cast(_data - sizeof(T)); + } + + /** + * Return reference to the message word at the specified index + */ + unsigned long &word(unsigned i) + { + return reinterpret_cast(_data)[i]; + } + + /** + * Return size of message buffer + */ + size_t capacity() const { return _capacity; } + + /** + * Reset message buffer + * + * This function is used at the server side for reusing the same + * message buffer for subsequent requests. + */ + void reset() + { + for (Genode::size_t i = 0; i < _used_caps; i++) + _caps[i] = Native_capability(); + + _clear(_data_size); + + _used_caps = 0; + _data_size = 0; + } + + /** + * Return pointer to start of message-buffer content + */ + void const *data() const { return _data; } + void *data() { return _data; } + + /** + * Return size of marshalled data payload in bytes + */ + size_t data_size() const { return _data_size; } + + void data_size(size_t data_size) { _data_size = data_size; } + + /** + * Exception type + */ + class Too_many_caps : public Exception { }; + + /** + * Return number of marshalled capabilities + */ + size_t used_caps() const { return _used_caps; } + + void used_caps(size_t used_caps) { _used_caps = used_caps; } + + Native_capability &cap(unsigned i) { return _caps[i]; } + Native_capability const &cap(unsigned i) const { return _caps[i]; } + + /** + * Append value to message buffer + */ + template + void insert(T const &value) + { + /* check buffer range */ + if (_data_size + sizeof(T) > _capacity) return; + + /* write value to buffer */ + *reinterpret_cast(_data_last()) = value; + + /* increment write pointer to next dword-aligned value */ + _data_size += align_natural(sizeof(T)); + } + + /** + * Insert content of 'Rpc_in_buffer' into message buffer + */ + template + void insert(Rpc_in_buffer const &b) + { + size_t const size = b.size(); + insert(size); + insert(b.base(), size); + } + + /** + * Write bytes to message buffer + */ + void insert(char const *src_addr, unsigned num_bytes) + { + /* check buffer range */ + if (_data_size + num_bytes > _capacity) return; + + /* copy buffer */ + memcpy(_data_last(), src_addr, num_bytes); + + /* increment write pointer to next dword-aligned value */ + _data_size += align_natural(num_bytes); + } + + /** + * Insert capability to message buffer + */ + void insert(Native_capability const &cap) + { + if (_used_caps == MAX_CAPS_PER_MSG) + throw Too_many_caps(); + + _caps[_used_caps++] = cap; + } + + /** + * Insert typed capability into message buffer + */ + template + void insert(Capability const &typed_cap) + { + Native_capability untyped_cap = typed_cap; + insert(untyped_cap); + } +}; + + +template +struct Genode::Msgbuf : Msgbuf_base +{ + /** + * Headroom in front of the actual message payload + * + * This space is used on some platforms to prepend the message with a + * protocol header. + */ + Headroom headroom; + + /** + * Buffer for data payload + */ + char buf[BUF_SIZE]; + + Msgbuf() : Msgbuf_base(buf, BUF_SIZE) { } +}; + +#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */ diff --git a/repos/base/include/base/rpc_client.h b/repos/base/include/base/rpc_client.h index d03f2ce0d6..bac73ec9ff 100644 --- a/repos/base/include/base/rpc_client.h +++ b/repos/base/include/base/rpc_client.h @@ -58,12 +58,12 @@ namespace Genode { template template void Capability:: - _marshal_args(Ipc_marshaller &marshaller, ATL &args) const + _marshal_args(Msgbuf_base &msg, ATL &args) const { if (Trait::Rpc_direction::Type::IN) - marshaller.insert(args.get()); + msg.insert(args.get()); - _marshal_args(marshaller, args._2); + _marshal_args(msg, args._2); } @@ -129,9 +129,8 @@ namespace Genode { Rpc_opcode opcode(static_cast(Meta::Index_of::Value)); /* marshal opcode and RPC input arguments */ - Ipc_marshaller marshaller(call_buf); - marshaller.insert(opcode); - _marshal_args(marshaller, args); + call_buf.insert(opcode); + _marshal_args(call_buf, args); { Trace::Rpc_call trace_event(IF::name(), call_buf); diff --git a/repos/base/include/base/rpc_server.h b/repos/base/include/base/rpc_server.h index 9f1a1fddb9..51d2a354f2 100644 --- a/repos/base/include/base/rpc_server.h +++ b/repos/base/include/base/rpc_server.h @@ -74,7 +74,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE void _read_args(Ipc_unmarshaller &, Meta::Empty) { } template - void _write_results(Ipc_marshaller &msg, ARG_LIST &args) + void _write_results(Msgbuf_base &msg, ARG_LIST &args) { if (Trait::Rpc_direction::Type::OUT) msg.insert(args._1); @@ -82,7 +82,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE _write_results(msg, args._2); } - void _write_results(Ipc_marshaller &, Meta::Empty) { } + void _write_results(Msgbuf_base &, Meta::Empty) { } template Rpc_exception_code _do_serve(typename RPC_FUNCTION::Server_args &args, @@ -111,7 +111,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE template Rpc_exception_code _do_dispatch(Rpc_opcode opcode, - Ipc_unmarshaller &in, Ipc_marshaller &out, + Ipc_unmarshaller &in, Msgbuf_base &out, Meta::Overload_selector) { using namespace Meta; @@ -158,7 +158,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE } Rpc_exception_code _do_dispatch(Rpc_opcode opcode, - Ipc_unmarshaller &, Ipc_marshaller &, + Ipc_unmarshaller &, Msgbuf_base &, Meta::Overload_selector) { PERR("invalid opcode %ld\n", opcode.value); @@ -169,7 +169,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE * Handle corner case of having an RPC interface with no RPC functions */ Rpc_exception_code _do_dispatch(Rpc_opcode opcode, - Ipc_unmarshaller &, Ipc_marshaller &, + Ipc_unmarshaller &, Msgbuf_base &, Meta::Overload_selector >) { return Rpc_exception_code(Rpc_exception_code::SUCCESS); @@ -185,7 +185,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE public: Rpc_exception_code dispatch(Rpc_opcode opcode, - Ipc_unmarshaller &in, Ipc_marshaller &out) + Ipc_unmarshaller &in, Msgbuf_base &out) { return _do_dispatch(opcode, in, out, Meta::Overload_selector()); @@ -207,7 +207,7 @@ class Genode::Rpc_object_base : public Object_pool::Entry * \param out outgoing message for storing method results */ virtual Rpc_exception_code - dispatch(Rpc_opcode op, Ipc_unmarshaller &in, Ipc_marshaller &out) = 0; + dispatch(Rpc_opcode op, Ipc_unmarshaller &in, Msgbuf_base &out) = 0; }; @@ -225,7 +225,7 @@ struct Genode::Rpc_object : Rpc_object_base, Rpc_dispatcher::dispatch(opcode, in, out); } @@ -287,13 +287,13 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool protected: - Ipc_server *_ipc_server; - Lock _cap_valid; /* thread startup synchronization */ - Lock _delay_start; /* delay start of request dispatching */ - Lock _delay_exit; /* delay destructor until server settled */ - Pd_session &_pd_session; /* for creating capabilities */ - Exit_handler _exit_handler; - Capability _exit_cap; + Native_capability _caller; + Lock _cap_valid; /* thread startup synchronization */ + Lock _delay_start; /* delay start of request dispatching */ + Lock _delay_exit; /* delay destructor until server settled */ + Pd_session &_pd_session; /* for creating capabilities */ + Exit_handler _exit_handler; + Capability _exit_cap; /** * Access to kernel-specific part of the PD session interface @@ -402,7 +402,7 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool * Typically, a capability obtained via this method is used as * argument of 'intermediate_reply'. */ - Untyped_capability reply_dst(); + Untyped_capability reply_dst() { return _caller; } /** * Prevent reply of current request @@ -417,7 +417,7 @@ class Genode::Rpc_entrypoint : Thread_base, public Object_pool * request. At a later time, the server may chose to unblock the * client via the 'intermedate_reply' method. */ - void omit_reply(); + void omit_reply() { _caller = Native_capability(); } /** * Send a reply out of the normal call-reply order diff --git a/repos/base/run/rm_fault.run b/repos/base/run/rm_fault.run index 919da24db9..335cec2d46 100644 --- a/repos/base/run/rm_fault.run +++ b/repos/base/run/rm_fault.run @@ -1,4 +1,4 @@ -if {[have_spec linux] || [have_spec pistachio]} { +if {[have_spec linux]} { puts "Platform does not support managed dataspaces"; exit } build "core init test/rm_fault" @@ -30,4 +30,4 @@ build_boot_image "core init test-rm_fault" append qemu_args "-nographic -m 64" -run_genode_until {child "test-rm_fault" exited with exit value 0.*} 10 +run_genode_until {child "test-rm_fault" exited with exit value 0.*} 300 diff --git a/repos/base/src/base/ipc/ipc_marshal_cap.cc b/repos/base/src/base/ipc/ipc_marshal_cap.cc deleted file mode 100644 index f3292a2ccf..0000000000 --- a/repos/base/src/base/ipc/ipc_marshal_cap.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * \brief Marshalling/unmarshalling of plain-data capabilities - * \author Norman Feske - * \date 2013-02-13 - */ - -/* - * Copyright (C) 2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#include - -using namespace Genode; - - -/** - * Marshalling of capabilities as plain data representation - */ -void Ipc_marshaller::insert(Native_capability const &cap) -{ - insert((char const *)&cap, sizeof(Native_capability)); -} - - -/** - * Unmarshalling of capabilities as plain data representation - */ -void Ipc_unmarshaller::extract(Native_capability &cap) -{ - struct Raw { char buf[sizeof(Native_capability)]; } raw; - extract(raw); - (Raw &)(cap) = raw; -} diff --git a/repos/base/src/base/server/common.cc b/repos/base/src/base/server/common.cc index 213de0c715..eb81d656d2 100644 --- a/repos/base/src/base/server/common.cc +++ b/repos/base/src/base/server/common.cc @@ -43,35 +43,12 @@ void Rpc_entrypoint::_block_until_cap_valid() } -Untyped_capability Rpc_entrypoint::reply_dst() -{ - return _ipc_server ? _ipc_server->caller() : Untyped_capability(); -} - - -void Rpc_entrypoint::omit_reply() -{ - /* set current destination to an invalid capability */ - if (_ipc_server) _ipc_server->caller(Untyped_capability()); -} - - void Rpc_entrypoint::reply_signal_info(Untyped_capability reply_cap, unsigned long imprint, unsigned long cnt) { - if (!_ipc_server) return; - - /* backup reply capability of current request */ - Untyped_capability last_reply_cap = _ipc_server->caller(); - - /* direct ipc server to the specified reply destination */ - _ipc_server->ret(Rpc_exception_code(Rpc_exception_code::SUCCESS)); - _ipc_server->caller(reply_cap); - _ipc_server->insert(Signal_source::Signal(imprint, cnt)); - _ipc_server->reply(); - - /* restore reply capability of the original request */ - _ipc_server->caller(last_reply_cap); + Msgbuf snd_buf; + snd_buf.insert(Signal_source::Signal(imprint, cnt)); + ipc_reply(reply_cap, Rpc_exception_code(Rpc_exception_code::SUCCESS), snd_buf); } diff --git a/repos/base/src/base/server/server.cc b/repos/base/src/base/server/server.cc index 60a77ac892..5138c5d445 100644 --- a/repos/base/src/base/server/server.cc +++ b/repos/base/src/base/server/server.cc @@ -2,22 +2,18 @@ * \brief Default version of platform-specific part of RPC framework * \author Norman Feske * \date 2006-05-12 - * - * This version is suitable for platforms similar to L4. Each platform - * for which this implementation is not suited contains a platform- - * specific version in its respective 'base-' repository. */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* Genode includes */ +#include #include -#include #include /* base-internal includes */ @@ -32,8 +28,7 @@ using namespace Genode; Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) { - Untyped_capability ep_cap = Native_capability(_cap.dst(), 0); - Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, ep_cap); + Untyped_capability new_obj_cap = _alloc_rpc_cap(_pd_session, _cap); /* add server object to object pool */ obj->cap(new_obj_cap); @@ -46,11 +41,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) void Rpc_entrypoint::entry() { - using Pool = Object_pool; - - Native_connection_state cs; - Ipc_server srv(cs, _snd_buf, _rcv_buf); - _ipc_server = &srv; + Ipc_server srv; _cap = srv; _cap_valid.unlock(); @@ -63,27 +54,32 @@ void Rpc_entrypoint::entry() */ _delay_start.lock(); + Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); + while (!_exit_handler.exit) { - Rpc_opcode opcode(0); + Rpc_request const request = ipc_reply_wait(_caller, exc, _snd_buf, _rcv_buf); + _caller = request.caller; - srv.reply_wait(); - srv.extract(opcode); + Ipc_unmarshaller unmarshaller(_rcv_buf); + Rpc_opcode opcode(0); + unmarshaller.extract(opcode); /* set default return value */ - srv.ret(Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT)); + exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); + _snd_buf.reset(); - Pool::apply(srv.badge(), [&] (Rpc_object_base *obj) + apply(request.badge, [&] (Rpc_object_base *obj) { if (!obj) { return;} - try { - srv.ret(obj->dispatch(opcode, srv, srv)); - } catch(Blocking_canceled&) { } + try { exc = obj->dispatch(opcode, unmarshaller, _snd_buf); } + catch(Blocking_canceled&) { } }); } /* answer exit call, thereby wake up '~Rpc_entrypoint' */ - srv.reply(); + Msgbuf<16> snd_buf; + ipc_reply(_caller, Rpc_exception_code(Rpc_exception_code::SUCCESS), snd_buf); /* defer the destruction of 'Ipc_server' until '~Rpc_entrypoint' is ready */ _delay_exit.lock(); diff --git a/repos/base/src/base/signal/signal.cc b/repos/base/src/base/signal/signal.cc index 00b3c8e57d..03bd61ffa2 100644 --- a/repos/base/src/base/signal/signal.cc +++ b/repos/base/src/base/signal/signal.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -278,6 +279,11 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source) /* look up context as pointed to by the signal imprint */ Signal_context *context = (Signal_context *)(source_signal.imprint()); + if (!context) { + PERR("received null signal imprint, stop signal handling"); + sleep_forever(); + } + if (!signal_context_registry()->test_and_lock(context)) { PWRN("encountered dead signal context"); continue; diff --git a/repos/base/src/core/pager_object.cc b/repos/base/src/core/pager_object.cc index ac59dd8f44..ce8678f876 100644 --- a/repos/base/src/core/pager_object.cc +++ b/repos/base/src/core/pager_object.cc @@ -11,6 +11,9 @@ * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ +#include + /* core includes */ #include @@ -19,11 +22,7 @@ using namespace Genode; void Pager_object::wake_up() { - /* notify pager to wake up faulter */ - Msgbuf<16> snd, rcv; - Ipc_marshaller marshaller(snd); - marshaller.insert(this); - ipc_call(cap(), snd, rcv, 0); + PWRN("user-level page fault handling is not supported on this platform"); } diff --git a/repos/base/src/include/base/internal/ipc_server.h b/repos/base/src/include/base/internal/ipc_server.h index 11128421c9..c97945d1ce 100644 --- a/repos/base/src/include/base/internal/ipc_server.h +++ b/repos/base/src/include/base/internal/ipc_server.h @@ -18,73 +18,43 @@ #include #include -/* base-internal includes */ -#include - namespace Genode { - class Native_connection_state; - class Ipc_server; + struct Ipc_server; + + /** + * Send reply to caller + */ + void ipc_reply(Native_capability caller, Rpc_exception_code, + Msgbuf_base &snd_msg); + + typedef Native_capability Reply_capability; + + struct Rpc_request + { + Reply_capability caller; + unsigned long badge = ~0; + + Rpc_request() { } + + Rpc_request(Reply_capability caller, unsigned long badge) + : caller(caller), badge(badge) { } + }; + + /** + * Send result of previous RPC request and wait for new one + */ + Rpc_request ipc_reply_wait(Reply_capability const &caller, + Rpc_exception_code reply_exc, + Msgbuf_base &reply_msg, + Msgbuf_base &request_msg); } -class Genode::Ipc_server : public Ipc_marshaller, public Ipc_unmarshaller, - public Native_capability +struct Genode::Ipc_server : Native_capability { - private: - - bool _reply_needed = false; /* false for the first reply_wait */ - - Native_capability _caller; - - Native_connection_state &_rcv_cs; - - void _prepare_next_reply_wait(); - - unsigned long _badge = 0; - - Rpc_exception_code _exception_code { 0 }; - - public: - - /** - * Constructor - */ - Ipc_server(Native_connection_state &, - Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg); - - ~Ipc_server(); - - /** - * Send reply to destination - */ - void reply(); - - /** - * Send result of previous RPC request and wait for new one - */ - void reply_wait(); - - /** - * Set return value of server call - */ - void ret(Rpc_exception_code code) { _exception_code = code; } - - /** - * Read badge that was supplied with the message - */ - unsigned long badge() const { return _badge; } - - /** - * Set reply destination - */ - void caller(Native_capability const &caller) - { - _caller = caller; - _reply_needed = caller.valid(); - } - - Native_capability caller() const { return _caller; } + Ipc_server(); + ~Ipc_server(); }; #endif /* _INCLUDE__BASE__INTERNAL__IPC_SERVER_H_ */ diff --git a/repos/base/src/include/base/internal/native_connection_state.h b/repos/base/src/include/base/internal/native_connection_state.h deleted file mode 100644 index 9f3e877102..0000000000 --- a/repos/base/src/include/base/internal/native_connection_state.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * \brief Dummy connection state - * \author Norman Feske - * \date 2016-03-03 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ -#define _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ - -#include - -namespace Genode { struct Native_connection_state { }; } - -#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_CONNECTION_STATE_H_ */