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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2012-2017 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2012-05-30 20:13:09 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* 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 <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-15 20:01:59 +01:00
|
|
|
#include <base/internal/ipc_server.h>
|
2016-06-13 13:53:58 +02:00
|
|
|
#include <base/internal/native_env.h>
|
2016-06-15 15:04:54 +02:00
|
|
|
#include <base/internal/capability_space.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
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
/**
|
|
|
|
* 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());
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_caps; i++)
|
2016-06-15 15:04:54 +02:00
|
|
|
utcb.cap_set(i, Capability_space::capid(snd_msg.cap(i)));
|
2016-03-18 22:53:25 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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++) {
|
2016-06-15 15:04:54 +02:00
|
|
|
rcv_msg.cap(i) = Capability_space::import(utcb.cap_get(i));
|
2016-03-18 22:53:25 +01:00
|
|
|
if (rcv_msg.cap(i).valid())
|
2016-06-15 15:04:54 +02:00
|
|
|
Kernel::ack_cap(Capability_space::capid(rcv_msg.cap(i)));
|
2016-03-18 22:53:25 +01:00
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
rcv_msg.used_caps(num_caps);
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
/* copy data payload */
|
|
|
|
size_t const data_size = min(utcb.data_size(),
|
|
|
|
min(utcb.capacity(), rcv_msg.capacity()));
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
memcpy(rcv_msg.data(), utcb.data(), data_size);
|
|
|
|
|
|
|
|
rcv_msg.data_size(data_size);
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
2016-03-15 20:01:59 +01:00
|
|
|
** IPC client **
|
2012-05-30 20:13:09 +02:00
|
|
|
****************/
|
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
Rpc_exception_code Genode::ipc_call(Native_capability dst,
|
|
|
|
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
|
|
|
|
size_t rcv_caps)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2016-05-04 12:27:17 +02:00
|
|
|
Native_utcb &utcb = *Thread::myself()->utcb();
|
2016-03-15 20:01:59 +01:00
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
retry<Genode::Allocator::Out_of_memory>(
|
|
|
|
[&] () {
|
|
|
|
|
2016-05-04 12:27:17 +02:00
|
|
|
copy_msg_to_utcb(snd_msg, *Thread::myself()->utcb());
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2016-06-15 15:04:54 +02:00
|
|
|
switch (Kernel::send_request_msg(Capability_space::capid(dst), rcv_caps)) {
|
2015-05-19 14:18:40 +02:00
|
|
|
case -1: throw Blocking_canceled();
|
|
|
|
case -2: throw Allocator::Out_of_memory();
|
|
|
|
default:
|
2016-03-18 22:53:25 +01:00
|
|
|
copy_utcb_to_msg(utcb, rcv_msg);
|
2015-05-19 14:18:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
},
|
2017-06-13 14:54:08 +02:00
|
|
|
[&] () { upgrade_capability_slab(); });
|
2016-03-13 22:55:48 +01:00
|
|
|
|
2016-03-15 20:01:59 +01:00
|
|
|
return Rpc_exception_code(utcb.exception_code());
|
2016-03-13 22:55:48 +01:00
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
2016-03-18 22:53:25 +01:00
|
|
|
** IPC server **
|
2012-05-30 20:13:09 +02:00
|
|
|
****************/
|
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
|
|
|
|
Msgbuf_base &snd_msg)
|
2013-10-17 13:51:17 +02:00
|
|
|
{
|
2016-05-04 12:27:17 +02:00
|
|
|
Native_utcb &utcb = *Thread::myself()->utcb();
|
2016-03-18 22:53:25 +01:00
|
|
|
copy_msg_to_utcb(snd_msg, utcb);
|
|
|
|
utcb.exception_code(exc.value);
|
|
|
|
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-18 22:53:25 +01:00
|
|
|
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
|
|
|
Rpc_exception_code exc,
|
|
|
|
Msgbuf_base &reply_msg,
|
|
|
|
Msgbuf_base &request_msg)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2016-05-04 12:27:17 +02:00
|
|
|
Native_utcb &utcb = *Thread::myself()->utcb();
|
2013-10-17 16:07:47 +02:00
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
retry<Genode::Allocator::Out_of_memory>(
|
|
|
|
[&] () {
|
2016-03-15 20:01:59 +01:00
|
|
|
int ret = 0;
|
2016-03-18 22:53:25 +01:00
|
|
|
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);
|
2016-03-15 20:01:59 +01:00
|
|
|
} else {
|
2016-03-18 22:53:25 +01:00
|
|
|
ret = Kernel::await_request_msg(Msgbuf_base::MAX_CAPS_PER_MSG);
|
2016-03-15 20:01:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (ret) {
|
2015-05-19 14:18:40 +02:00
|
|
|
case -1: throw Blocking_canceled();
|
|
|
|
case -2: throw Allocator::Out_of_memory();
|
2016-03-15 20:01:59 +01:00
|
|
|
default: break;
|
2015-05-19 14:18:40 +02:00
|
|
|
}
|
|
|
|
},
|
2017-06-13 14:54:08 +02:00
|
|
|
[&] () { upgrade_capability_slab(); });
|
2016-03-15 20:01:59 +01:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
copy_utcb_to_msg(utcb, request_msg);
|
2016-03-15 20:01:59 +01:00
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
return Rpc_request(Native_capability(), utcb.destination());
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
2016-03-11 21:47:12 +01:00
|
|
|
|
|
|
|
|
2016-03-18 22:53:25 +01:00
|
|
|
Ipc_server::Ipc_server()
|
2016-03-13 22:55:48 +01:00
|
|
|
:
|
2016-05-04 12:27:17 +02:00
|
|
|
Native_capability(Thread::myself() ? Thread::myself()->native_thread().cap
|
|
|
|
: Hw::_main_thread_cap)
|
2016-03-18 22:53:25 +01:00
|
|
|
{ }
|
2016-03-13 22:55:48 +01:00
|
|
|
|
|
|
|
|
2016-03-11 21:47:12 +01:00
|
|
|
Ipc_server::~Ipc_server() { }
|