222 lines
5.1 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief IPC implementation for Pistachio
* \author Julian Stecklina
* \author Norman Feske
* \date 2008-01-28
*/
/*
2013-01-10 21:44:47 +01:00
* Copyright (C) 2008-2013 Genode Labs GmbH
2011-12-22 16:19:25 +01: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 */
2011-12-22 16:19:25 +01:00
#include <base/printf.h>
#include <base/ipc.h>
#include <base/blocking.h>
#include <base/sleep.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
/* Pistachio includes */
2011-12-22 16:19:25 +01:00
namespace Pistachio {
#include <l4/types.h>
#include <l4/ipc.h>
#include <l4/kdebug.h>
}
using namespace Genode;
using namespace Pistachio;
#define VERBOSE_IPC 0
#if VERBOSE_IPC
/* Just a printf wrapper for now. */
#define IPCDEBUG(msg, ...) { \
if (L4_Myself().raw == 0xf4001) { \
(void)printf("IPC (thread = 0x%x) " msg, \
L4_ThreadNo(Pistachio::L4_Myself()) \
, ##__VA_ARGS__); \
} else {}
}
#else
#define IPCDEBUG(...)
#endif
2011-12-22 16:19:25 +01:00
/**
* Assert that we got 1 untyped word and 2 typed words
*/
static inline void check_ipc_result(L4_MsgTag_t result, L4_Word_t error_code)
{
/*
* Test for IPC cancellation via Core's cancel-blocking mechanism
*/
enum { ERROR_MASK = 0xe, ERROR_CANCELED = 3 << 1 };
if (L4_IpcFailed(result) &&
((L4_ErrorCode() & ERROR_MASK) == ERROR_CANCELED))
throw Genode::Blocking_canceled();
/*
* Provide diagnostic information on unexpected conditions
*/
if (L4_IpcFailed(result)) {
PERR("Error in thread %08lx. IPC failed.", L4_Myself().raw);
throw Genode::Ipc_error();
}
if (L4_UntypedWords(result) != 1) {
PERR("Error in thread %08lx. Expected one untyped word (local_name), but got %lu.\n",
L4_Myself().raw, L4_UntypedWords(result));
PERR("This should not happen. Inspect!");
throw Genode::Ipc_error();
}
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();
}
}
/****************
** IPC client **
2011-12-22 16:19:25 +01:00
****************/
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
2011-12-22 16:19:25 +01:00
{
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();
2011-12-22 16:19:25 +01:00
L4_MsgBuffer_t msgbuf;
/* prepare message buffer */
L4_Clear (&msgbuf);
L4_Append (&msgbuf, L4_StringItem (rcv_msg.capacity(), rcv_msg.data()));
2011-12-22 16:19:25 +01:00
L4_Accept(L4_UntypedWordsAcceptor);
L4_Accept(L4_StringItemsAcceptor, &msgbuf);
/* prepare sending parameters */
L4_Clear(&msg);
L4_Append(&msg, local_name);
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_MsgTag_t result = L4_Call(dst.dst());
2011-12-22 16:19:25 +01:00
L4_Clear(&msg);
L4_Store(result, &msg);
2011-12-22 16:19:25 +01:00
check_ipc_result(result, L4_ErrorCode());
return Rpc_exception_code(L4_Get(&msg, 0));
2011-12-22 16:19:25 +01:00
}
/****************
** Ipc_server **
****************/
void Ipc_server::_prepare_next_reply_wait()
{
_reply_needed = true;
_read_offset = _write_offset = 0;
2011-12-22 16:19:25 +01:00
}
void Ipc_server::reply()
2011-12-22 16:19:25 +01:00
{
L4_Msg_t msg;
L4_StringItem_t sitem = L4_StringItem(_write_offset, _snd_msg.data());
L4_Word_t const local_name = _caller.local_name();
2011-12-22 16:19:25 +01:00
L4_Clear(&msg);
L4_Append(&msg, local_name);
L4_Append(&msg, sitem);
L4_Load(&msg);
L4_MsgTag_t result = L4_Reply(_caller.dst());
2011-12-22 16:19:25 +01:00
if (L4_IpcFailed(result))
PERR("ipc error in _reply, ignored");
_prepare_next_reply_wait();
}
void Ipc_server::reply_wait()
2011-12-22 16:19:25 +01:00
{
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);
2011-12-22 16:19:25 +01:00
if (_reply_needed) {
/* 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);
/* 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);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
}
while (need_to_wait) {
/* wait for new request message */
request_tag = L4_Wait(&_rcv_cs.caller);
if (!L4_IpcFailed(request_tag))
need_to_wait = false;
}
/* extract request parameters */
L4_Msg_t msg;
L4_Clear(&msg);
L4_Store(request_tag, &msg);
/* remember badge of invoked object */
_badge = L4_Get(&msg, 0);
/* define destination of next reply */
_caller = Native_capability(_rcv_cs.caller, badge());
_prepare_next_reply_wait();
2011-12-22 16:19:25 +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(Pistachio::L4_Myself(), 0),
_rcv_cs(cs)
{
_read_offset = _write_offset = 0;
}
Ipc_server::~Ipc_server() { }