/* * \brief Generic IPC infrastructure * \author Norman Feske * \date 2006-06-12 */ /* * 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_H_ #define _INCLUDE__BASE__IPC_H_ #include #include #include #include namespace Genode { struct Ipc_error : Exception { }; class Ipc_unmarshaller; /** * Invoke capability to call an RPC function * * \param rcv_caps number of capabilities expected as result * \throw Blocking_canceled * * \noapi * * The 'rcv_caps' value is used on kernels like NOVA to allocate the * receive window for incoming capability selectors. */ Rpc_exception_code ipc_call(Native_capability dst, Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg, size_t rcv_caps); } /** * Unmarshal arguments from receive buffer */ class Genode::Ipc_unmarshaller : Noncopyable { protected: Msgbuf_base &_rcv_msg; unsigned _read_offset = 0; unsigned _read_cap_index = 0; private: char *_rcv_buf = (char *)_rcv_msg.data(); size_t const _rcv_buf_size = _rcv_msg.capacity(); public: /** * Obtain typed capability from message buffer */ template void extract(Capability &typed_cap) { typed_cap = extract(Meta::Overload_selector >()); } template Capability extract(Meta::Overload_selector >) { Native_capability untyped_cap = extract(Meta::Overload_selector()); return reinterpret_cap_cast(untyped_cap); } /** * Obtain capability from message buffer */ void extract(Native_capability &cap) { cap = extract(Meta::Overload_selector()); } Native_capability extract(Meta::Overload_selector) { Native_capability cap = _read_cap_index < _rcv_msg.used_caps() ? _rcv_msg.cap(_read_cap_index) : Native_capability(); _read_cap_index++; return cap; } /** * Read 'Rpc_in_buffer' from receive buffer */ template void extract(Rpc_in_buffer &b) { b = Rpc_in_buffer(0, 0); /* * Check receive buffer range * * Note: The addr of the Rpc_in_buffer_base is a null pointer when this * condition triggers. */ try { b = extract(Meta::Overload_selector >()); } catch (Ipc_error) { } } template Rpc_in_buffer extract(Meta::Overload_selector >) { size_t size = extract(Meta::Overload_selector()); if (_read_offset + size > _rcv_buf_size) { error("message buffer overrun"); throw Ipc_error(); } Rpc_in_buffer buf(&_rcv_buf[_read_offset], size); _read_offset += align_natural(size); return buf; } /** * Read value of type T from buffer */ template void extract(T &value) { value = extract(Meta::Overload_selector()); } template T extract(Meta::Overload_selector) { /* check receive buffer range */ if (_read_offset + sizeof(T) > _rcv_buf_size) throw Ipc_error(); /* return value from receive buffer */ T value = *reinterpret_cast(&_rcv_buf[_read_offset]); /* increment read pointer to next dword-aligned value */ _read_offset += align_natural(sizeof(T)); return value; } Ipc_unmarshaller(Msgbuf_base &rcv_msg) : _rcv_msg(rcv_msg) { } }; #endif /* _INCLUDE__BASE__IPC_H_ */