1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com> 4 * 5 * This file is part of TUD:OS and distributed under the terms of the 6 * GNU General Public License 2. 7 * Please see the COPYING-GPL-2 file for details. 8 * 9 * As a special exception, you may use this file as part of a free software 10 * library without restriction. Specifically, if other files instantiate 11 * templates or use macros or inline functions from this file, or you compile 12 * this file and link it with other files to produce an executable, this 13 * file does not by itself cause the resulting executable to be covered by 14 * the GNU General Public License. This exception does not however 15 * invalidate any other reasons why the executable file might be covered by 16 * the GNU General Public License. 17 */ 18 19#pragma once 20 21#include <l4/re/util/cap_alloc> 22#include <l4/sys/cxx/ipc_server_loop> 23#include <l4/cxx/ipc_timeout_queue> 24#include <l4/sys/assert.h> 25 26namespace L4Re { namespace Util { 27 28/** 29 * \brief Buffer-register (BR) manager for L4::Server. 30 * \ingroup api_l4re_util 31 * 32 * Implementation of the L4::Ipc_svr::Server_iface API for managing the 33 * server-side receive buffers needed for a set of server objects running 34 * within a server. 35 */ 36class Br_manager : public L4::Ipc_svr::Server_iface 37{ 38private: 39 enum { _mem = 0, _ports = 0 }; 40 41public: 42 /// Make a buffer-register (BR) manager 43 Br_manager() : _caps(0), _cap_flags(L4_RCV_ITEM_LOCAL_ID) {} 44 45 Br_manager(Br_manager const &) = delete; 46 Br_manager &operator = (Br_manager const &) = delete; 47 48 Br_manager(Br_manager &&) = default; 49 Br_manager &operator = (Br_manager &&) = default; 50 51 ~Br_manager() 52 { 53 // Slots for received capabilities are placed at the beginning of the 54 // (shadowed) buffer registers. Free those. 55 for (unsigned i = 0; i < _caps; ++i) 56 cap_alloc.free(L4::Cap<void>(_brs[i] & L4_CAP_MASK)); 57 } 58 59 /* 60 * This implementation dynamically manages assignment of buffer registers for 61 * the necessary amount of receive buffers allocated by all calls to this 62 * function. 63 */ 64 int alloc_buffer_demand(Demand const &d) 65 { 66 using L4::Ipc::Small_buf; 67 68 // memory and IO port receive windows currently not supported 69 if (d.mem || d.ports) 70 return -L4_EINVAL; 71 72 // take two extra buffers for a possible timeout and a zero terminator 73 if (d.caps + d.mem * 2 + d.ports * 2 + 3 >= L4_UTCB_GENERIC_BUFFERS_SIZE) 74 return -L4_ERANGE; 75 76 if (d.caps > _caps) 77 { 78 while (_caps < d.caps) 79 { 80 L4::Cap<void> cap = cap_alloc.alloc(); 81 if (!cap) 82 return -L4_ENOMEM; 83 84 reinterpret_cast<Small_buf&>(_brs[_caps]) 85 = Small_buf(cap.cap(), _cap_flags); 86 ++_caps; 87 } 88 _brs[_caps] = 0; 89 } 90 91 return L4_EOK; 92 } 93 94 95 L4::Cap<void> get_rcv_cap(int i) const 96 { 97 if (i < 0 || i >= _caps) 98 return L4::Cap<void>::Invalid; 99 100 return L4::Cap<void>(_brs[i] & L4_CAP_MASK); 101 } 102 103 int realloc_rcv_cap(int i) 104 { 105 using L4::Ipc::Small_buf; 106 107 if (i < 0 || i >= _caps) 108 return -L4_EINVAL; 109 110 L4::Cap<void> cap = cap_alloc.alloc(); 111 if (!cap) 112 return -L4_ENOMEM; 113 114 reinterpret_cast<Small_buf&>(_brs[i]) 115 = Small_buf(cap.cap(), _cap_flags); 116 117 return L4_EOK; 118 } 119 120 /** 121 * Set the receive flags for the buffers. 122 * 123 * \pre Must be called before any handlers are registered. 124 * 125 * \param flags New receive capability flags, see #l4_msg_item_consts_t. 126 */ 127 void set_rcv_cap_flags(unsigned long flags) 128 { 129 l4_assert(_caps == 0); 130 131 _cap_flags = flags; 132 } 133 134 /// No timeouts handled by us. 135 int add_timeout(L4::Ipc_svr::Timeout *, l4_kernel_clock_t) 136 { return -L4_ENOSYS; } 137 138 /// No timeouts handled by us. 139 int remove_timeout(L4::Ipc_svr::Timeout *) 140 { return -L4_ENOSYS; } 141 142 /// setup_wait() used the server loop (L4::Server) 143 void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode) 144 { 145 l4_buf_regs_t *br = l4_utcb_br_u(utcb); 146 br->bdr = 0; 147 for (unsigned i = 0; i <= _caps; ++i) 148 br->br[i] = _brs[i]; 149 } 150 151protected: 152 /// Used for assigning BRs for a timeout 153 unsigned first_free_br() const 154 { 155 // we take the last BR here (this is c constant), 156 return L4_UTCB_GENERIC_BUFFERS_SIZE - 1; 157 // could also take _caps + _mem +_ports + 1 (would be dynamic) 158 // return _caps + _mem + _ports + 1; 159 } 160 161private: 162 unsigned short _caps; 163 unsigned long _cap_flags; 164 165 l4_umword_t _brs[L4_UTCB_GENERIC_BUFFERS_SIZE]; 166}; 167 168/** 169 * Predefined server-loop hooks for a server loop using the Br_manager. 170 * 171 * This class can be used whenever a server loop including full management of 172 * receive buffer resources is needed. 173 */ 174struct Br_manager_hooks 175: L4::Ipc_svr::Ignore_errors, 176 L4::Ipc_svr::Default_timeout, 177 L4::Ipc_svr::Compound_reply, 178 Br_manager 179{}; 180 181/** 182 * Predefined server-loop hooks for a server with using the Br_manager and 183 * a timeout queue. 184 * 185 * This class can be used for server loops that need the full package of 186 * buffer-register management and a timeout queue. 187 */ 188struct Br_manager_timeout_hooks : 189 public L4::Ipc_svr::Timeout_queue_hooks<Br_manager_timeout_hooks, Br_manager>, 190 public L4::Ipc_svr::Ignore_errors 191{ 192public: 193 static l4_kernel_clock_t now() 194 { return l4_kip_clock(l4re_kip()); } 195}; 196 197}} 198 199