2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief Implementation of the Genode IPC-framework
|
|
|
|
* \author Martin Stein
|
|
|
|
* \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 */
|
|
|
|
#include <base/ipc.h>
|
|
|
|
#include <base/thread.h>
|
|
|
|
#include <kernel/syscalls.h>
|
|
|
|
#include <kernel/log.h>
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
/* size of the callee-local name of a targeted RPC object */
|
|
|
|
RPC_OBJECT_ID_SIZE = sizeof(umword_t),
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The RPC framework marshalls a return value into reply messages to
|
|
|
|
* deliver exceptions, wich occured during the RPC call to the caller.
|
|
|
|
* This defines the size of this value.
|
|
|
|
*/
|
|
|
|
RPC_RETURN_VALUE_SIZE = sizeof(umword_t),
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
/**
|
2012-12-19 15:49:44 +01:00
|
|
|
* Limit message size to the size of UTCB and message buffer
|
2012-05-30 20:13:09 +02:00
|
|
|
*/
|
2012-12-19 15:49:44 +01:00
|
|
|
void limit_msg_size(Msgbuf_base * const msgbuf, Native_utcb * const utcb,
|
|
|
|
size_t & size)
|
|
|
|
{
|
|
|
|
if (size > utcb->size() || size > msgbuf->size()) {
|
|
|
|
kernel_log() << __PRETTY_FUNCTION__ << ": truncate message\n";
|
|
|
|
size = utcb->size() < msgbuf->size() ? utcb->size() : msgbuf->size();
|
|
|
|
}
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy message payload to message buffer
|
|
|
|
*/
|
2012-12-19 15:49:44 +01:00
|
|
|
static void utcb_to_msgbuf(Msgbuf_base * const msgbuf, size_t size)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2012-12-19 15:49:44 +01:00
|
|
|
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
|
|
|
limit_msg_size(msgbuf, utcb, size);
|
|
|
|
memcpy(msgbuf->buf, utcb->base(), size);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
2013-10-07 16:01:03 +02:00
|
|
|
/**
|
|
|
|
* Copy message payload with integrated size toion message buffer
|
|
|
|
*
|
|
|
|
* This function pioneers IPC messages with headers and will
|
|
|
|
* replace utcb_to_msgbuf sometime.
|
|
|
|
*/
|
|
|
|
static void sized_utcb_to_msgbuf(Msgbuf_base * const msgbuf)
|
|
|
|
{
|
|
|
|
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
|
|
|
size_t msg_size = utcb->ipc_msg_size();
|
|
|
|
if (msg_size > utcb->max_ipc_msg_size()) {
|
|
|
|
kernel_log() << "oversized IPC message\n";
|
|
|
|
msg_size = utcb->max_ipc_msg_size();
|
|
|
|
}
|
|
|
|
memcpy(msgbuf->buf, utcb->ipc_msg_base(), msg_size);
|
|
|
|
}
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy message payload to the UTCB
|
|
|
|
*/
|
2012-12-19 15:49:44 +01:00
|
|
|
static void msgbuf_to_utcb(Msgbuf_base * const msgbuf, size_t size,
|
|
|
|
unsigned const local_name)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2012-12-19 15:49:44 +01:00
|
|
|
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
|
|
|
*(unsigned *)utcb->base() = local_name;
|
|
|
|
size += sizeof(local_name);
|
|
|
|
limit_msg_size(msgbuf, utcb, size);
|
|
|
|
memcpy((unsigned *)utcb->base() + 1, (unsigned *)msgbuf->buf + 1, size);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
** Ipc_ostream **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
Ipc_ostream::Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg)
|
|
|
|
:
|
|
|
|
Ipc_marshaller(&snd_msg->buf[0], snd_msg->size()),
|
|
|
|
_snd_msg(snd_msg), _dst(dst)
|
|
|
|
{
|
|
|
|
_write_offset = RPC_OBJECT_ID_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
** Ipc_istream **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
void Ipc_istream::_wait()
|
|
|
|
{
|
|
|
|
/* FIXME this shall be not supported */
|
|
|
|
Kernel::pause_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
|
|
|
|
:
|
|
|
|
Ipc_unmarshaller(&rcv_msg->buf[0], rcv_msg->size()),
|
|
|
|
Native_capability(Genode::thread_get_my_native_id(), 0),
|
|
|
|
_rcv_msg(rcv_msg), _rcv_cs(-1)
|
|
|
|
{ _read_offset = RPC_OBJECT_ID_SIZE; }
|
|
|
|
|
|
|
|
|
|
|
|
Ipc_istream::~Ipc_istream() { }
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
** Ipc_client **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
void Ipc_client::_call()
|
|
|
|
{
|
|
|
|
using namespace Kernel;
|
|
|
|
|
|
|
|
/* send request and receive reply */
|
2012-12-19 15:49:44 +01:00
|
|
|
msgbuf_to_utcb(_snd_msg, _write_offset, Ipc_ostream::_dst.local_name());
|
2013-10-07 16:01:03 +02:00
|
|
|
int error = request_and_wait(Ipc_ostream::_dst.dst(), _write_offset);
|
|
|
|
if (error) { throw Blocking_canceled(); }
|
|
|
|
sized_utcb_to_msgbuf(_rcv_msg);
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* reset unmarshaller */
|
|
|
|
_write_offset = _read_offset = RPC_OBJECT_ID_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ipc_client::Ipc_client(Native_capability const &srv,
|
|
|
|
Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
|
|
|
|
: Ipc_istream(rcv_msg), Ipc_ostream(srv, snd_msg), _result(0) { }
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
** Ipc_server **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
Ipc_server::Ipc_server(Msgbuf_base *snd_msg,
|
|
|
|
Msgbuf_base *rcv_msg) :
|
|
|
|
Ipc_istream(rcv_msg),
|
|
|
|
Ipc_ostream(Native_capability(), snd_msg),
|
|
|
|
_reply_needed(false)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
void Ipc_server::_prepare_next_reply_wait()
|
|
|
|
{
|
|
|
|
/* now we have a request to reply */
|
|
|
|
_reply_needed = true;
|
|
|
|
|
|
|
|
/* leave space for RPC method return value */
|
|
|
|
_write_offset = RPC_OBJECT_ID_SIZE + RPC_RETURN_VALUE_SIZE;
|
|
|
|
|
|
|
|
/* reset unmarshaller */
|
|
|
|
_read_offset = RPC_OBJECT_ID_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Ipc_server::_wait()
|
|
|
|
{
|
|
|
|
/* receive next request */
|
2012-12-19 15:49:44 +01:00
|
|
|
utcb_to_msgbuf(_rcv_msg, Kernel::wait_for_request());
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* update server state */
|
|
|
|
_prepare_next_reply_wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-30 10:33:57 +01:00
|
|
|
void Ipc_server::_reply() { Kernel::reply(_write_offset, 0); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Ipc_server::_reply_wait()
|
|
|
|
{
|
|
|
|
/* if there is no reply simply do wait for request */
|
|
|
|
/* FIXME this shall be not supported */
|
|
|
|
if (!_reply_needed) {
|
|
|
|
_wait();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* send reply and receive next request */
|
2012-12-19 15:49:44 +01:00
|
|
|
msgbuf_to_utcb(_snd_msg, _write_offset, Ipc_ostream::_dst.local_name());
|
|
|
|
utcb_to_msgbuf(_rcv_msg, Kernel::reply(_write_offset, 1));
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* update server state */
|
|
|
|
_prepare_next_reply_wait();
|
|
|
|
}
|
|
|
|
|