Norman Feske 356506a67a base: remove base/blocking.h
This patch removes the obsolete exception type 'Blocking_canceled'.

Issue #4768
2023-02-27 08:22:49 +01:00

244 lines
6.6 KiB
C++

/*
* \brief IPC implementation for OKL4
* \author Norman Feske
* \date 2009-03-25
*/
/*
* Copyright (C) 2009-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
#include <base/ipc.h>
#include <base/sleep.h>
/* base-internal includes */
#include <base/internal/ipc_server.h>
#include <base/internal/native_utcb.h>
#include <base/internal/capability_space_tpl.h>
#include <base/internal/okl4.h>
using namespace Genode;
using namespace Okl4;
/*
* Message layout within the UTCB
*
* The message tag contains the information about the number of message words
* to send. The tag is always supplied in message register 0. Message register
* 1 is used for the local name (when the client calls the server) or the
* exception code (when the server replies to the client). Message register
* 2 holds the number of transferred capability arguments. It is followed
* by a tuple of (thread ID, local name) for each capability. All subsequent
* message registers hold the message payload.
*/
/**
* Copy message registers from UTCB to destination message buffer
*
* \return local name / exception code
*/
static L4_Word_t extract_msg_from_utcb(L4_MsgTag_t rcv_tag, Msgbuf_base &rcv_msg)
{
rcv_msg.reset();
unsigned const num_msg_words = (int)L4_UntypedWords(rcv_tag);
if (num_msg_words < 3)
return Rpc_exception_code::INVALID_OBJECT;
L4_Word_t protocol_word = 0;
L4_StoreMR(1, &protocol_word);
L4_Word_t num_caps = 0;
L4_StoreMR(2, &num_caps);
/* each capability is represened as two message words (tid, local name) */
for (unsigned i = 0; i < num_caps; i++) {
L4_Word_t local_name = 0;
L4_ThreadId_t tid;
L4_StoreMR(3 + 2*i, &tid.raw);
L4_StoreMR(3 + 2*i + 1, &local_name);
Rpc_obj_key const rpc_obj_key(local_name);
bool const cap_valid = tid.raw != 0UL;
Native_capability cap;
if (cap_valid) {
cap = Capability_space::lookup(rpc_obj_key);
if (!cap.valid())
cap = Capability_space::import(tid, rpc_obj_key);
}
rcv_msg.insert(cap);
}
unsigned const data_start_idx = 3 + 2*num_caps;
if (num_msg_words < data_start_idx)
return Rpc_exception_code::INVALID_OBJECT;
unsigned const num_data_words = num_msg_words - data_start_idx;
if (num_data_words*sizeof(L4_Word_t) > rcv_msg.capacity()) {
error("receive message buffer too small,"
"msg size=", num_data_words*sizeof(L4_Word_t), ", "
"buf size=", rcv_msg.capacity());
return Rpc_exception_code::INVALID_OBJECT;
}
/* read message payload into destination message buffer */
L4_StoreMRs(data_start_idx, num_data_words, (L4_Word_t *)rcv_msg.data());
rcv_msg.data_size(sizeof(num_data_words));
return protocol_word;
}
/**
* Copy message payload to UTCB message registers
*/
static void copy_msg_to_utcb(Msgbuf_base const &snd_msg, L4_Word_t local_name)
{
uint8_t const num_header_words = (uint8_t)(3 + 2*snd_msg.used_caps());
uint8_t const num_data_words = (uint8_t)(snd_msg.data_size()/sizeof(L4_Word_t));
uint8_t const num_msg_words = num_data_words + num_header_words;
if (num_msg_words >= L4_GetMessageRegisters()) {
raw("Message does not fit into UTCB message registers, num_msg_words=", num_msg_words);
L4_LoadMR(0, 0);
return;
}
L4_MsgTag_t snd_tag;
snd_tag.raw = 0;
snd_tag.X.u = (num_msg_words & 0x3f); /* bitfield X.u has 6 bits */
L4_LoadMR(0, snd_tag.raw);
L4_LoadMR(1, local_name);
L4_LoadMR(2, snd_msg.used_caps());
for (unsigned i = 0; i < snd_msg.used_caps(); i++) {
Native_capability cap = snd_msg.cap(i);
if (cap.valid()) {
Capability_space::Ipc_cap_data const cap_data =
Capability_space::ipc_cap_data(snd_msg.cap(i));
L4_LoadMR(3 + i*2, (L4_Word_t)cap_data.dst.raw);
L4_LoadMR(3 + i*2 + 1, (L4_Word_t)cap_data.rpc_obj_key.value());
} else {
L4_LoadMR(3 + i*2, (L4_Word_t)0UL);
L4_LoadMR(3 + i*2 + 1, (L4_Word_t)0UL);
}
}
L4_LoadMRs(num_header_words, num_data_words, (L4_Word_t *)snd_msg.data());
}
/****************
** IPC client **
****************/
Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msg, Msgbuf_base &rcv_msg,
size_t)
{
Capability_space::Ipc_cap_data const dst_data =
Capability_space::ipc_cap_data(dst);
/* copy call message to the UTCBs message registers */
copy_msg_to_utcb(snd_msg, dst_data.rpc_obj_key.value());
L4_Accept(L4_UntypedWordsAcceptor);
L4_MsgTag_t rcv_tag = L4_Call(dst_data.dst);
if (L4_IpcFailed(rcv_tag)) {
raw("Ipc failed");
sleep_forever();
}
return Rpc_exception_code(extract_msg_from_utcb(rcv_tag, rcv_msg));
}
/****************
** IPC server **
****************/
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
/* copy reply to the UTCBs message registers */
copy_msg_to_utcb(snd_msg, exc.value);
/*
* Perform non-blocking IPC-send operation
*
* Errors are deliberately ignored. The operation may fail if the
* client disappeared during the IPC call. But this condition does
* not concern the server side.
*/
(void)L4_Reply(Capability_space::ipc_cap_data(caller).dst);
}
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
L4_MsgTag_t rcv_tag;
Okl4::L4_ThreadId_t caller = L4_nilthread;
if (last_caller.valid()) {
/* copy reply to the UTCBs message registers */
copy_msg_to_utcb(reply_msg, exc.value);
rcv_tag = L4_ReplyWait(Capability_space::ipc_cap_data(last_caller).dst,
&caller);
} else {
rcv_tag = L4_Wait(&caller);
}
/* copy request message from the UTCBs message registers */
unsigned long const badge = extract_msg_from_utcb(rcv_tag, request_msg);
return Rpc_request(Capability_space::import(caller, Rpc_obj_key()), badge);
}
/**
* Return the global thread ID of the calling thread
*
* On OKL4 we cannot use 'L4_Myself()' to determine our own thread's
* identity. By convention, each thread stores its global ID in a
* defined entry of its UTCB.
*/
static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
{
Okl4::L4_ThreadId_t myself;
myself.raw = Okl4::__L4_TCR_ThreadWord(UTCB_TCR_THREAD_WORD_MYSELF);
return myself;
}
Ipc_server::Ipc_server()
:
Native_capability(Capability_space::import(thread_get_my_global_id(), Rpc_obj_key()))
{ }
Ipc_server::~Ipc_server() { }