L4Re - L4 Runtime Environment
br_manager
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 
26 namespace 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  */
36 class Br_manager : public L4::Ipc_svr::Server_iface
37 {
38 private:
39  enum { _mem = 0, _ports = 0 };
40 
41 public:
42  /// Make a buffer-register (BR) manager
43  Br_manager() : _caps(0), _cap_flags(L4_RCV_ITEM_LOCAL_ID) {}
44 
45  /*
46  * This implementation dynamically manages assignment of buffer registers for
47  * the necessary amount of receive buffers allocated by all calls to this
48  * function.
49  */
50  int alloc_buffer_demand(Demand const &d)
51  {
52  using L4::Ipc::Small_buf;
53 
54  // memory and IO port receive windows currently not supported
55  if (d.mem || d.ports)
56  return -L4_EINVAL;
57 
58  // take two extra buffers for a possible timeout and a zero terminator
59  if (d.caps + d.mem * 2 + d.ports * 2 + 3 >= L4_UTCB_GENERIC_BUFFERS_SIZE)
60  return -L4_ERANGE;
61 
62  if (d.caps > _caps)
63  {
64  while (_caps < d.caps)
65  {
66  L4::Cap<void> cap = cap_alloc.alloc();
67  if (!cap)
68  return -L4_ENOMEM;
69 
70  reinterpret_cast<Small_buf&>(_brs[_caps])
71  = Small_buf(cap.cap(), _cap_flags);
72  ++_caps;
73  }
74  _brs[_caps] = 0;
75  }
76 
77  return L4_EOK;
78  }
79 
80 
81  L4::Cap<void> get_rcv_cap(int i) const
82  {
83  if (i < 0 || i >= _caps)
84  return L4::Cap<void>::Invalid;
85 
86  return L4::Cap<void>(_brs[i] & L4_CAP_MASK);
87  }
88 
89  int realloc_rcv_cap(int i)
90  {
91  using L4::Ipc::Small_buf;
92 
93  if (i < 0 || i >= _caps)
94  return -L4_EINVAL;
95 
96  L4::Cap<void> cap = cap_alloc.alloc();
97  if (!cap)
98  return -L4_ENOMEM;
99 
100  reinterpret_cast<Small_buf&>(_brs[i])
101  = Small_buf(cap.cap(), _cap_flags);
102 
103  return L4_EOK;
104  }
105 
106  /**
107  * Set the receive flags for the buffers.
108  *
109  * \pre Must be called before any handlers are registered.
110  *
111  * \param flags New receive capability flags, see #l4_msg_item_consts_t.
112  */
113  void set_rcv_cap_flags(unsigned long flags)
114  {
115  l4_assert(_caps == 0);
116 
117  _cap_flags = flags;
118  }
119 
120  /// No timeouts handled by us.
121  int add_timeout(L4::Ipc_svr::Timeout *, l4_kernel_clock_t)
122  { return -L4_ENOSYS; }
123 
124  /// No timeouts handled by us.
125  int remove_timeout(L4::Ipc_svr::Timeout *)
126  { return -L4_ENOSYS; }
127 
128  /// setup_wait() used the server loop (L4::Server)
129  void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode)
130  {
131  l4_buf_regs_t *br = l4_utcb_br_u(utcb);
132  br->bdr = 0;
133  for (unsigned i = 0; i <= _caps; ++i)
134  br->br[i] = _brs[i];
135  }
136 
137 protected:
138  /// Used for assigning BRs for a timeout
139  unsigned first_free_br() const
140  {
141  // we take the last BR here (this is c constant),
142  return L4_UTCB_GENERIC_BUFFERS_SIZE - 1;
143  // could also take _caps + _mem +_ports + 1 (would be dynamic)
144  // return _caps + _mem + _ports + 1;
145  }
146 
147 private:
148  unsigned short _caps;
149  unsigned long _cap_flags;
150 
151  l4_umword_t _brs[L4_UTCB_GENERIC_BUFFERS_SIZE];
152 };
153 
154 /**
155  * Predefined server-loop hooks for a server loop using the Br_manager.
156  *
157  * This class can be used whenever a server loop including full management of
158  * receive buffer resources is needed.
159  */
160 struct Br_manager_hooks
161 : L4::Ipc_svr::Ignore_errors,
162  L4::Ipc_svr::Default_timeout,
163  L4::Ipc_svr::Compound_reply,
164  Br_manager
165 {};
166 
167 /**
168  * Predefined server-loop hooks for a server with using the Br_manager and
169  * a timeout queue.
170  *
171  * This class can be used for server loops that need the full package of
172  * buffer-register management and a timeout queue.
173  */
174 struct Br_manager_timeout_hooks :
175  public L4::Ipc_svr::Timeout_queue_hooks<Br_manager_timeout_hooks, Br_manager>,
176  public L4::Ipc_svr::Ignore_errors
177 {
178 public:
179  static l4_kernel_clock_t now()
180  { return l4_kip_clock(l4re_kip()); }
181 };
182 
183 }}
184