L4Re - L4 Runtime Environment
ipc_server
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 #pragma once
19 #pragma GCC system_header
20 
21 #include <l4/sys/cxx/ipc_basics>
22 #include <l4/sys/cxx/ipc_iface>
23 #include <l4/sys/__typeinfo.h>
24 #include <stddef.h>
25 
26 namespace L4 {
27 namespace Ipc {
28 namespace Msg {
29 namespace Detail {
30 
31 template<typename T> struct Sizeof { enum { size = sizeof(T) }; };
32 template<> struct Sizeof<void> { enum { size = 0 }; };
33 
34 /**
35  * Argument data structure for server-function arguments.
36  */
37 template<typename ...> struct Arg_pack
38 {
39  template<typename DIR>
40  unsigned get(char *, unsigned offset, unsigned)
41  { return offset; }
42 
43  template<typename DIR>
44  unsigned set(char *, unsigned offset, unsigned, long)
45  { return offset; }
46 
47  template<typename F, typename ...ARGS>
48  long call(F f, ARGS ...args)
49  { return f(args...); }
50 
51  template<typename O, typename FUNC, typename ...ARGS>
52  long obj_call(O *o, ARGS ...args)
53  {
54  typedef typename FUNC::template fwd<O> Fwd;
55  return Fwd(o).template call<ARGS...>(args...);
56  //return o->op_dispatch(args...);
57  }
58 };
59 
60 /**
61  * Data member for server-function argument T.
62  */
63 template<typename T, typename SVR_TYPE, typename ...M>
64 struct Svr_arg : Svr_xmit<T>, Arg_pack<M...>
65 {
66  typedef Arg_pack<M...> Base;
67 
68  typedef SVR_TYPE svr_type;
69  typedef typename _Elem<T>::svr_arg_type svr_arg_type;
70 
71  svr_type v;
72 
73  template<typename DIR>
74  int get(char *msg, unsigned offset, unsigned limit)
75  {
76  typedef Svr_xmit<T> ct;
77  int r = ct::to_svr(msg, offset, limit, this->v,
78  typename DIR::dir(), typename DIR::cls());
79  if (L4_LIKELY(r >= 0))
80  return Base::template get<DIR>(msg, r, limit);
81 
82  if (_Elem<T>::Is_optional)
83  {
84  v = svr_type();
85  return Base::template get<DIR>(msg, offset, limit);
86  }
87  return r;
88  }
89 
90  template<typename DIR>
91  int set(char *msg, unsigned offset, unsigned limit, long ret)
92  {
93  typedef Svr_xmit<T> ct;
94  int r = ct::from_svr(msg, offset, limit, ret, this->v,
95  typename DIR::dir(), typename DIR::cls());
96  if (L4_UNLIKELY(r < 0))
97  return r;
98  return Base::template set<DIR>(msg, r, limit, ret);
99  }
100 
101  template<typename F, typename ...ARGS>
102  long call(F f, ARGS ...args)
103  {
104  //As_arg<value_type> check;
105  return Base::template
106  call<F, ARGS..., svr_arg_type>(f, args..., this->v);
107  }
108 
109  template<typename O, typename FUNC, typename ...ARGS>
110  long obj_call(O *o, ARGS ...args)
111  {
112  //As_arg<value_type> check;
113  return Base::template
114  obj_call<O,FUNC, ARGS..., svr_arg_type>(o, args..., this->v);
115  }
116 };
117 
118 template<typename T, typename ...M>
119 struct Svr_arg<T, void, M...> : Arg_pack<M...>
120 {
121  typedef Arg_pack<M...> Base;
122 
123  template<typename DIR>
124  int get(char *msg, unsigned offset, unsigned limit)
125  { return Base::template get<DIR>(msg, offset, limit); }
126 
127  template<typename DIR>
128  int set(char *msg, unsigned offset, unsigned limit, long ret)
129  { return Base::template set<DIR>(msg, offset, limit, ret); }
130 
131  template<typename F, typename ...ARGS>
132  long call(F f, ARGS ...args)
133  {
134  return Base::template call<F, ARGS...>(f, args...);
135  }
136 
137  template<typename O, typename FUNC, typename ...ARGS>
138  long obj_call(O *o, ARGS ...args)
139  {
140  return Base::template obj_call<O, FUNC, ARGS...>(o, args...);
141  }
142 };
143 
144 template<typename A, typename ...M>
145 struct Arg_pack<A, M...> : Svr_arg<A, typename _Elem<A>::svr_type, M...>
146 {};
147 
148 } // namespace Detail
149 
150 //---------------------------------------------------------------------
151 /**
152  * Server-side RPC arguments data structure used to provide arguments
153  * to the server-side implementation of an RPC function.
154  */
155 template<typename IPC_TYPE> struct Svr_arg_pack;
156 
157 template<typename R, typename ...ARGS>
158 struct Svr_arg_pack<R (ARGS...)> : Detail::Arg_pack<ARGS...>
159 {
160  typedef Detail::Arg_pack<ARGS...> Base;
161  template<typename DIR>
162  int get(void *msg, unsigned offset, unsigned limit)
163  {
164  return Base::template get<DIR>((char *)msg, offset, limit);
165  }
166 
167  template<typename DIR>
168  int set(void *msg, unsigned offset, unsigned limit, long ret)
169  {
170  return Base::template set<DIR>((char *)msg, offset, limit, ret);
171  }
172 };
173 
174 /**
175  * Handle an incoming RPC call and forward it to o->op_dispatch().
176  */
177 template<typename IPC_TYPE, typename O, typename ...ARGS>
178 static l4_msgtag_t
179 handle_svr_obj_call(O *o, l4_utcb_t *utcb, l4_msgtag_t tag, ARGS ...args)
180 {
181  typedef Svr_arg_pack<typename IPC_TYPE::rpc::ipc_type> Pack;
182  enum
183  {
184  Do_reply = IPC_TYPE::rpc::flags_type::Is_call,
185  Short_err = Do_reply ? -L4_EMSGTOOSHORT : -L4_ENOREPLY,
186  };
187 
188  // XXX: send a reply or just do not reply in case of a cheating client
189  if (L4_UNLIKELY(tag.words() + tag.items() * Item_words > Mr_words))
190  return l4_msgtag(Short_err, 0, 0, 0);
191 
192  // our whole arguments data structure
193  Pack pack;
194  l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
195 
196  int in_pos = Detail::Sizeof<typename IPC_TYPE::opcode_type>::size;
197 
198  unsigned const in_bytes = tag.words() * Word_bytes;
199 
200  in_pos = pack.template get<Do_in_data>(&mrs->mr[0], in_pos, in_bytes);
201 
202  if (L4_UNLIKELY(in_pos < 0))
203  return l4_msgtag(Short_err, 0, 0, 0);
204 
205  if (L4_UNLIKELY(pack.template get<Do_out_data>(mrs->mr, 0, Mr_bytes) < 0))
206  return l4_msgtag(Short_err, 0, 0, 0);
207 
208 
209  in_pos = pack.template get<Do_in_items>(&mrs->mr[tag.words()], 0,
210  tag.items() * Item_bytes);
211 
212  if (L4_UNLIKELY(in_pos < 0))
213  return l4_msgtag(Short_err, 0, 0, 0);
214 
215  asm volatile ("" : "=m" (mrs->mr));
216 
217  // call the server function
218  long ret = pack.template obj_call<O, typename IPC_TYPE::rpc, ARGS...>(o, args...);
219 
220  if (!Do_reply)
221  return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
222 
223  // our convention says that negative return value means no
224  // reply data
225  if (L4_UNLIKELY(ret < 0))
226  return l4_msgtag(ret, 0, 0, 0);
227 
228  // reply with the reply data from the server function
229  int bytes = pack.template set<Do_out_data>(mrs->mr, 0, Mr_bytes, ret);
230  if (L4_UNLIKELY(bytes < 0))
231  return l4_msgtag(-L4_EMSGTOOLONG, 0, 0, 0);
232 
233  unsigned words = (bytes + Word_bytes - 1) / Word_bytes;
234  bytes = pack.template set<Do_out_items>(&mrs->mr[words], 0,
235  Mr_bytes - words * Word_bytes,
236  ret);
237  if (L4_UNLIKELY(bytes < 0))
238  return l4_msgtag(-L4_EMSGTOOLONG, 0, 0, 0);
239 
240  unsigned const items = bytes / Item_bytes;
241  return l4_msgtag(ret, words, items, 0);
242 }
243 
244 //-------------------------------------------------------------------------
245 
246 template<typename RPCS, typename OPCODE_TYPE>
247 struct Dispatch_call;
248 
249 template<typename CLASS>
250 struct Dispatch_call<L4::Typeid::Raw_ipc<CLASS>, void>
251 {
252  template<typename OBJ, typename ...ARGS>
253  static l4_msgtag_t
254  call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, ARGS ...a)
255  {
256  return o->op_dispatch(utcb, tag, a...);
257  }
258 };
259 
260 template<typename RPCS>
261 struct Dispatch_call<RPCS, void>
262 {
263  constexpr static unsigned rmask()
264  { return RPCS::rpc::flags_type::Rights & 3UL; }
265 
266  template<typename OBJ, typename ...ARGS>
267  static l4_msgtag_t
268  call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
269  {
270  if ((rights & rmask()) != rmask())
271  return l4_msgtag(-L4_EPERM, 0, 0, 0);
272 
273  typedef L4::Typeid::Rights<typename RPCS::rpc::class_type> Rights;
274  return handle_svr_obj_call<RPCS>(o, utcb, tag,
275  Rights(rights), a...);
276 
277  }
278 };
279 
280 template<typename RPCS, typename OPCODE_TYPE>
281 struct Dispatch_call
282 {
283  constexpr static unsigned rmask()
284  { return RPCS::rpc::flags_type::Rights & 3UL; }
285 
286  template<typename OBJ, typename ...ARGS>
287  static l4_msgtag_t
288  _call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, OPCODE_TYPE op, ARGS ...a)
289  {
290  if (L4::Types::Same<typename RPCS::opcode_type, void>::value
291  || RPCS::Opcode == op)
292  {
293  if ((rights & rmask()) != rmask())
294  return l4_msgtag(-L4_EPERM, 0, 0, 0);
295 
296  typedef L4::Typeid::Rights<typename RPCS::rpc::class_type> Rights;
297  return handle_svr_obj_call<RPCS>(o, utcb, tag,
298  Rights(rights), a...);
299  }
300  return Dispatch_call<typename RPCS::next, OPCODE_TYPE>::template
301  _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
302  }
303 
304  template<typename OBJ, typename ...ARGS>
305  static l4_msgtag_t
306  call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
307  {
308  OPCODE_TYPE op;
309  unsigned limit = tag.words() * Word_bytes;
310  typedef Svr_xmit<OPCODE_TYPE> S;
311  int err = S::to_svr((char *)l4_utcb_mr_u(utcb)->mr, 0, limit, op,
312  Dir_in(), Cls_data());
313  if (L4_UNLIKELY(err < 0))
314  return l4_msgtag(-L4_EMSGTOOSHORT, 0, 0, 0);
315 
316  return _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
317  }
318 };
319 
320 template<>
321 struct Dispatch_call<Typeid::Detail::Rpcs_end, void>
322 {
323  template<typename OBJ, typename ...ARGS>
324  static l4_msgtag_t
325  _call(OBJ *, l4_utcb_t *, l4_msgtag_t, unsigned, int, ARGS ...)
326  { return l4_msgtag(-L4_ENOSYS, 0, 0, 0); }
327 
328  template<typename OBJ, typename ...ARGS>
329  static l4_msgtag_t
330  call(OBJ *, l4_utcb_t *, l4_msgtag_t, unsigned, ARGS ...)
331  { return l4_msgtag(-L4_ENOSYS, 0, 0, 0); }
332 };
333 
334 template<typename OPCODE_TYPE>
335 struct Dispatch_call<Typeid::Detail::Rpcs_end, OPCODE_TYPE> :
336  Dispatch_call<Typeid::Detail::Rpcs_end, void> {};
337 
338 template<typename RPCS, typename OBJ, typename ...ARGS>
339 static l4_msgtag_t
340 dispatch_call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
341 {
342  return Dispatch_call<typename RPCS::type, typename RPCS::opcode_type>::template
343  call<OBJ, ARGS...>(o, utcb, tag, rights, a...);
344 }
345 
346 } // namespace Msg
347 } // namesapce Ipc
348 } // namespace L4
349 
350