2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief Implementation of the Genode IPC-framework
|
|
|
|
* \author Martin Stein
|
2016-03-13 22:55:48 +01:00
|
|
|
* \author Norman Feske
|
2012-05-30 20:13:09 +02:00
|
|
|
* \date 2012-02-12
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* 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 */
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <base/env.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
#include <base/ipc.h>
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <base/allocator.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
#include <base/thread.h>
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <base/native_env.h>
|
|
|
|
#include <util/construct_at.h>
|
|
|
|
#include <util/retry.h>
|
2013-11-14 17:29:34 +01:00
|
|
|
|
2016-03-08 16:59:43 +01:00
|
|
|
/* base-internal includes */
|
|
|
|
#include <base/internal/native_utcb.h>
|
2016-03-11 17:32:43 +01:00
|
|
|
#include <base/internal/native_thread.h>
|
2016-03-08 16:59:43 +01:00
|
|
|
|
2013-11-14 17:29:34 +01:00
|
|
|
/* base-hw includes */
|
|
|
|
#include <kernel/interface.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
#include <kernel/log.h>
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
namespace Hw { extern Genode::Untyped_capability _main_thread_cap; }
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
/* size of the callee-local name of a targeted RPC object */
|
2016-03-08 17:44:54 +01:00
|
|
|
RPC_OBJECT_ID_SIZE = sizeof(Kernel::capid_t),
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The RPC framework marshalls a return value into reply messages to
|
|
|
|
* deliver exceptions, wich occured during the RPC call to the caller.
|
|
|
|
* This defines the size of this value.
|
|
|
|
*/
|
|
|
|
RPC_RETURN_VALUE_SIZE = sizeof(umword_t),
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
/*****************************
|
|
|
|
** IPC marshalling support **
|
|
|
|
*****************************/
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
void Ipc_marshaller::insert(Native_capability const &cap) {
|
|
|
|
_snd_msg.cap_add(cap); }
|
2015-05-19 14:18:40 +02:00
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
void Ipc_unmarshaller::extract(Native_capability &cap) {
|
|
|
|
cap = _rcv_msg.cap_get(); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
** Ipc_client **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
void Ipc_client::_call()
|
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
retry<Genode::Allocator::Out_of_memory>(
|
|
|
|
[&] () {
|
|
|
|
|
|
|
|
/* send request and receive corresponding reply */
|
2016-03-13 22:55:48 +01:00
|
|
|
Thread_base::myself()->utcb()->copy_from(_snd_msg, _write_offset);
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
switch (Kernel::send_request_msg(_dst.dst(),
|
|
|
|
_rcv_msg.cap_rcv_window())) {
|
2015-05-19 14:18:40 +02:00
|
|
|
case -1: throw Blocking_canceled();
|
|
|
|
case -2: throw Allocator::Out_of_memory();
|
|
|
|
default:
|
2016-03-13 22:55:48 +01:00
|
|
|
_rcv_msg.reset();
|
|
|
|
_snd_msg.reset();
|
|
|
|
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
|
2015-05-19 14:18:40 +02:00
|
|
|
|
|
|
|
/* reset unmarshaller */
|
|
|
|
_write_offset = _read_offset =
|
|
|
|
align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
[&] () { upgrade_pd_session_quota(3*4096); });
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
Ipc_client::Ipc_client(Native_capability const &dst,
|
|
|
|
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
|
|
|
|
unsigned short rcv_caps)
|
|
|
|
:
|
|
|
|
Ipc_marshaller(snd_msg), Ipc_unmarshaller(rcv_msg), _result(0), _dst(dst)
|
|
|
|
{
|
|
|
|
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
|
|
|
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
|
|
|
_snd_msg.reset();
|
|
|
|
|
|
|
|
_rcv_msg.cap_rcv_window(rcv_caps);
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
** Ipc_server **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
void Ipc_server::_prepare_next_reply_wait()
|
|
|
|
{
|
|
|
|
/* now we have a request to reply */
|
|
|
|
_reply_needed = true;
|
|
|
|
|
|
|
|
/* leave space for RPC method return value */
|
2015-05-19 14:18:40 +02:00
|
|
|
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE +
|
|
|
|
RPC_RETURN_VALUE_SIZE);
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* reset unmarshaller */
|
2015-05-19 14:18:40 +02:00
|
|
|
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
void Ipc_server::wait()
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
retry<Genode::Allocator::Out_of_memory>(
|
|
|
|
[&] () {
|
|
|
|
|
|
|
|
/* receive request */
|
|
|
|
switch (Kernel::await_request_msg(Msgbuf_base::MAX_CAP_ARGS)) {
|
|
|
|
case -1: throw Blocking_canceled();
|
|
|
|
case -2: throw Allocator::Out_of_memory();
|
|
|
|
default:
|
2016-03-13 22:55:48 +01:00
|
|
|
_rcv_msg.reset();
|
|
|
|
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
|
|
|
|
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
|
2015-05-19 14:18:40 +02:00
|
|
|
|
|
|
|
/* update server state */
|
|
|
|
_prepare_next_reply_wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
[&] () { upgrade_pd_session_quota(3*4096); });
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
void Ipc_server::reply()
|
2013-10-17 13:51:17 +02:00
|
|
|
{
|
2016-03-13 22:55:48 +01:00
|
|
|
Thread_base::myself()->utcb()->copy_from(_snd_msg, _write_offset);
|
|
|
|
_snd_msg.reset();
|
2015-05-19 14:18:40 +02:00
|
|
|
Kernel::send_reply_msg(0, false);
|
2013-10-17 13:51:17 +02:00
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
void Ipc_server::reply_wait()
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2013-10-17 16:07:47 +02:00
|
|
|
/* if there is no reply, wait for request */
|
2012-05-30 20:13:09 +02:00
|
|
|
if (!_reply_needed) {
|
2016-03-13 22:55:48 +01:00
|
|
|
wait();
|
2012-05-30 20:13:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2013-10-17 16:07:47 +02:00
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
retry<Genode::Allocator::Out_of_memory>(
|
|
|
|
[&] () {
|
|
|
|
/* send reply and receive next request */
|
2016-03-13 22:55:48 +01:00
|
|
|
Thread_base::myself()->utcb()->copy_from(_snd_msg, _write_offset);
|
2015-05-19 14:18:40 +02:00
|
|
|
switch (Kernel::send_reply_msg(Msgbuf_base::MAX_CAP_ARGS, true)) {
|
|
|
|
case -1: throw Blocking_canceled();
|
|
|
|
case -2: throw Allocator::Out_of_memory();
|
|
|
|
default:
|
2016-03-13 22:55:48 +01:00
|
|
|
_rcv_msg.reset();
|
|
|
|
_snd_msg.reset();
|
|
|
|
Thread_base::myself()->utcb()->copy_to(_rcv_msg);
|
|
|
|
_badge = *reinterpret_cast<unsigned long *>(_rcv_msg.data());
|
2015-05-19 14:18:40 +02:00
|
|
|
|
|
|
|
/* update server state */
|
|
|
|
_prepare_next_reply_wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
[&] () { upgrade_pd_session_quota(3*4096); });
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
2016-03-11 21:47:12 +01:00
|
|
|
|
|
|
|
|
2016-03-13 22:55:48 +01:00
|
|
|
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_base::myself() ? Thread_base::myself()->native_thread().cap
|
|
|
|
: Hw::_main_thread_cap),
|
|
|
|
_reply_needed(false), _rcv_cs(cs)
|
|
|
|
{
|
|
|
|
_read_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
|
|
|
_write_offset = align_natural<unsigned>(RPC_OBJECT_ID_SIZE);
|
|
|
|
_snd_msg.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-11 21:47:12 +01:00
|
|
|
Ipc_server::~Ipc_server() { }
|