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 26namespace L4 { 27namespace Ipc { 28namespace Msg { 29namespace Detail { 30 31template<typename T> struct Sizeof { enum { size = sizeof(T) }; }; 32template<> struct Sizeof<void> { enum { size = 0 }; }; 33 34/** 35 * Argument data structure for server-function arguments. 36 */ 37template<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 */ 63template<typename T, typename SVR_TYPE, typename ...M> 64struct 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 118template<typename T, typename ...M> 119struct 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 144template<typename A, typename ...M> 145struct 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 */ 155template<typename IPC_TYPE> struct Svr_arg_pack; 156 157template<typename R, typename ...ARGS> 158struct 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 */ 177template<typename IPC_TYPE, typename O, typename ...ARGS> 178static l4_msgtag_t 179handle_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 246template<typename RPCS, typename OPCODE_TYPE> 247struct Dispatch_call; 248 249template<typename CLASS> 250struct 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 260template<typename RPCS> 261struct 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 280template<typename RPCS, typename OPCODE_TYPE> 281struct 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 320template<> 321struct 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 334template<typename OPCODE_TYPE> 335struct Dispatch_call<Typeid::Detail::Rpcs_end, OPCODE_TYPE> : 336 Dispatch_call<Typeid::Detail::Rpcs_end, void> {}; 337 338template<typename RPCS, typename OBJ, typename ...ARGS> 339static l4_msgtag_t 340dispatch_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 351