1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 4 * Alexander Warg <warg@os.inf.tu-dresden.de> 5 * economic rights: Technische Universität Dresden (Germany) 6 * 7 * This file is part of TUD:OS and distributed under the terms of the 8 * GNU General Public License 2. 9 * Please see the COPYING-GPL-2 file for details. 10 * 11 * As a special exception, you may use this file as part of a free software 12 * library without restriction. Specifically, if other files instantiate 13 * templates or use macros or inline functions from this file, or you compile 14 * this file and link it with other files to produce an executable, this 15 * file does not by itself cause the resulting executable to be covered by 16 * the GNU General Public License. This exception does not however 17 * invalidate any other reasons why the executable file might be covered by 18 * the GNU General Public License. 19 */ 20 21#pragma once 22 23#include <l4/re/util/cap_alloc> 24#include <l4/re/util/unique_cap> 25#include <l4/re/consts> 26#include <l4/re/env> 27 28#include <l4/sys/cxx/ipc_server_loop> 29#include <l4/sys/factory> 30#include <l4/sys/task> 31#include <l4/sys/thread> 32#include <l4/sys/ipc_gate> 33 34#include <l4/cxx/exceptions> 35 36namespace L4Re { namespace Util { 37 38/** 39 * A registry that manages server objects and their attached IPC gates for 40 * a single server loop for a specific thread. 41 * 42 * This class manages most of the setup of a server object. If necessary, 43 * an IPC gate is created, the specified thread is bound to the IPC gate. 44 * Incoming IPC is dispatched to the server object based on 45 * the label of the IPC gate. 46 * 47 * The object registry is also able to manage IRQ endpoints. They require a 48 * different method for the object creation. Otherwise they are handled in 49 * the same way as IPC gates: a server object is responsible to process 50 * the incoming interrupts. 51 */ 52class Object_registry : 53 public L4::Basic_registry, 54 public L4::Registry_iface 55{ 56 /** 57 * Handler class for stale requests from servers that have been 58 * deregistered. 59 */ 60 struct Null_handler : L4::Epiface_t<Null_handler, L4::Kobject> 61 {}; 62 63protected: 64 L4::Cap<L4::Thread> _server; 65 L4::Cap<L4::Factory> _factory; 66 L4::Ipc_svr::Server_iface *_sif; 67 68private: 69 Null_handler _null_handler; 70 71public: 72 /** 73 * Create a registry for the main thread of the task using the default factory. 74 * 75 * \param sif Server loop interface. 76 */ 77 explicit 78 Object_registry(L4::Ipc_svr::Server_iface *sif) 79 : _server(L4Re::Env::env()->main_thread()), 80 _factory(L4Re::Env::env()->factory()), 81 _sif(sif) 82 {} 83 84 /** 85 * Create a registry for arbitrary threads. 86 * 87 * \param sif Server loop interface. 88 * \param server Capability to the thread that executes the server objects. 89 * \param factory Capability to a factory object capable of creating new 90 * IPC gates. 91 */ 92 Object_registry(L4::Ipc_svr::Server_iface *sif, 93 L4::Cap<L4::Thread> server, 94 L4::Cap<L4::Factory> factory) 95 : _server(server), _factory(factory), _sif(sif) 96 {} 97 98private: 99 typedef L4::Ipc_svr::Server_iface Server_iface; 100 typedef Server_iface::Demand Demand; 101 102 L4::Cap<L4::Rcv_endpoint> 103 _register_ep(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep, 104 Demand const &demand) 105 { 106 int err = _sif->alloc_buffer_demand(demand); 107 if (err < 0) 108 return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT); 109 110 l4_umword_t id = l4_umword_t(o); 111 err = l4_error(ep->bind_thread(_server, id)); 112 if (err < 0) 113 return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT); 114 115 err = o->set_server(_sif, ep); 116 if (err < 0) 117 return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT); 118 119 return ep; 120 } 121 122 L4::Cap<void> _register_ep(L4::Epiface *o, char const *service, 123 Demand const &demand) 124 { 125 L4::Cap<L4::Rcv_endpoint> cap = L4Re::Env::env()->get_cap<L4::Rcv_endpoint>(service); 126 if (!cap.is_valid()) 127 return cap; 128 129 return _register_ep(o, cap, demand); 130 } 131 132 L4::Cap<void> _register_gate(L4::Epiface *o, Demand const &demand) 133 { 134 int err = _sif->alloc_buffer_demand(demand); 135 if (err < 0) 136 return L4::Cap<void>(err | L4_INVALID_CAP_BIT); 137 138 auto cap = L4Re::Util::make_unique_cap<L4::Kobject>(); 139 140 if (!cap.is_valid()) 141 return cap.get(); 142 143 l4_umword_t id = l4_umword_t(o); 144 err = l4_error(_factory->create_gate(cap.get(), _server, id)); 145 if (err < 0) 146 return L4::Cap<void>(err | L4_INVALID_CAP_BIT); 147 148 err = o->set_server(_sif, cap.get(), true); 149 if (err < 0) 150 return L4::Cap<void>(err | L4_INVALID_CAP_BIT); 151 152 return cap.release(); 153 } 154 155 L4::Cap<L4::Irq> _register_irq(L4::Epiface *o, 156 Demand const &demand) 157 { 158 int err = _sif->alloc_buffer_demand(demand); 159 if (err < 0) 160 return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT); 161 162 auto cap = L4Re::Util::make_unique_cap<L4::Irq>(); 163 164 if (!cap.is_valid()) 165 return cap.get(); 166 167 l4_umword_t id = l4_umword_t(o); 168 err = l4_error(_factory->create(cap.get())); 169 if (err < 0) 170 return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT); 171 172 err = l4_error(cap->bind_thread(_server, id)); 173 if (err < 0) 174 return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT); 175 176 err = o->set_server(_sif, cap.get(), true); 177 if (err < 0) 178 return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT); 179 180 return cap.release(); 181 } 182 183 static Demand _get_buffer_demand(L4::Epiface *o) 184 { return o->get_buffer_demand(); } 185 186 template<typename T> 187 static Demand _get_buffer_demand(T *, 188 typename L4::Kobject_typeid<typename T::Interface>::Demand 189 d = typename L4::Kobject_typeid<typename T::Interface>::Demand()) 190 { return d; } 191 192public: 193 /** 194 * Register a new server object to a pre-allocated receive endpoint. 195 * 196 * \param o Server object that handles IPC requests. 197 * \param service Name of a pre-allocated receive endpoint. 198 * 199 * \retval L4::Cap<void> The capability known as `service` on success. 200 * \retval L4::Cap<void>::Invalid No capability with the given name found. 201 * 202 * The interface must be freed with unregister_obj() by the caller 203 * to unbind the thread from the capability. 204 */ 205 L4::Cap<void> register_obj(L4::Epiface *o, char const *service) override 206 { 207 return _register_ep(o, service, _get_buffer_demand(o)); 208 } 209 210 /** 211 * Register a new server object on a newly allocated capability. 212 * 213 * \param o Server object that handles IPC requests. 214 * 215 * \retval L4::Cap<void> A valid capability to a new IPC gate. 216 * \retval L4::Cap<void>::Invalid The allocation of the IPC gate 217 * has failed. 218 * 219 * The IPC gate will be allocated using the registry's factory. The 220 * caller must call unregister_obj() to free all resources. 221 */ 222 L4::Cap<void> register_obj(L4::Epiface *o) override 223 { 224 return _register_gate(o, _get_buffer_demand(o)); 225 } 226 227 /** 228 * Register a handler for an interrupt. 229 * 230 * \param o Server object that handles IRQs. 231 * 232 * \retval L4::Cap<L4::Irq> Capability to a new IRQ object on success. 233 * \retval L4::Cap<L4::Irq>::Invalid The allocation of the IRQ has failed. 234 * 235 * The IRQ will be newly allocated using the registry's factory object. The 236 * caller must call unregister_obj() to free all resources. 237 */ 238 L4::Cap<L4::Irq> register_irq_obj(L4::Epiface *o) override 239 { 240 return _register_irq(o, _get_buffer_demand(o)); 241 } 242 243 // pass access to deprecated register_irq_obj 244 using L4::Registry_iface::register_irq_obj; 245 246 /** 247 * Register a handler for an already existing interrupt. 248 * 249 * \param o Server object that handles the IPC. 250 * \param ep Capability to a receive endpoint, may be a hardware or 251 * software interrupt or an IPC gate. 252 * 253 * \retval L4::Cap<L4::Rcv_endpoint> Capability `ep` on success. 254 * \retval L4::Cap<L4::Rcv_endpoint>::Invalid The IRQ attach operation has failed. 255 * 256 * The interface must be freed with unregister_obj() by the caller 257 * to unbind the thread from the capability. 258 */ 259 L4::Cap<L4::Rcv_endpoint> 260 register_obj(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep) override 261 { 262 return _register_ep(o, ep, _get_buffer_demand(o)); 263 } 264 265 266 /** 267 * Remove a server object from the handler list. 268 * 269 * \param o Server object to unbind. 270 * \param unmap Specifies if the object capability shall be unmapped (true) 271 * or not. The default (true) is to unmap the capability. 272 * 273 * The capability used by the server object will be unmapped if `unmap` is 274 * true. 275 */ 276 void unregister_obj(L4::Epiface *o, bool unmap = true) override 277 { 278 L4::Epiface::Stored_cap c; 279 280 if (!o || !o->obj_cap().is_valid()) 281 return; 282 283 c = o->obj_cap(); 284 285 // make sure unhandled ipc ends up with the null handler 286 L4::Thread::Modify_senders todo; 287 todo.add(~3UL, reinterpret_cast<l4_umword_t>(o), 288 ~0UL, reinterpret_cast<l4_umword_t>((L4::Epiface*)&_null_handler)); 289 _server->modify_senders(todo); 290 291 if (unmap) 292 L4::Cap<L4::Task>(L4Re::This_task)->unmap(c.fpage(), L4_FP_ALL_SPACES); 293 294 // we use bit 4 to indicated an internally allocated cap 295 if (c.managed()) 296 cap_alloc.free(c); 297 298 o->set_server(0, L4::Cap<void>::Invalid); 299 } 300}; 301 302/** 303 * A server loop object which has a Object_registry included. 304 */ 305template< typename LOOP_HOOKS = L4::Ipc_svr::Default_loop_hooks > 306class Registry_server : public L4::Server<LOOP_HOOKS> 307{ 308private: 309 typedef L4::Server<LOOP_HOOKS> Base; 310 Object_registry _registry; 311 312public: 313 /** 314 * Create a new server loop object for the main thread of the task. 315 * 316 * \pre Must be called from the main thread or behaviour is undefined. 317 */ 318 Registry_server() : _registry(this) 319 {} 320 321 /** 322 * Create a new server loop object for an arbitrary thread and factory. 323 * 324 * \param utcb The UTCB of the thread running the server loop. 325 * \param server Capability to thread running the server loop. 326 * \param factory Capability to factory object used to create new IPC gates. 327 * 328 * \deprecated{Note that this variant of the constructor is deprecated, 329 * please do not supply the UTCB pointer, it's not used.} 330 */ 331 Registry_server(l4_utcb_t *, L4::Cap<L4::Thread> server, 332 L4::Cap<L4::Factory> factory) 333 : _registry(this, server, factory) 334 {} 335 336 /** 337 * Create a new server loop object for an arbitrary thread and factory. 338 * 339 * \param server Capability to thread running the server loop. 340 * \param factory Capability to factory object used to create new IPC gates. 341 */ 342 Registry_server(L4::Cap<L4::Thread> server, 343 L4::Cap<L4::Factory> factory) 344 : _registry(this, server, factory) 345 {} 346 347 /** Return registry of this server loop. */ 348 Object_registry const *registry() const { return &_registry; } 349 /** Return registry of this server loop. */ 350 Object_registry *registry() { return &_registry; } 351 352 /** 353 * Start the server loop. 354 * 355 * \param utcb The UTCB of the thread running the server loop, defaults to 356 * l4_utcb(). 357 */ 358 void L4_NORETURN loop(l4_utcb_t *utcb = l4_utcb()) 359 { Base::template loop<L4::Runtime_error, Object_registry &>(_registry, utcb); } 360}; 361 362}} 363