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 20#include "types" 21#include "ipc_basics" 22#include "ipc_types" 23 24namespace L4 { namespace Ipc L4_EXPORT { 25 26/// Default type for passing length of an array. 27typedef unsigned short Array_len_default; 28 29/** 30 * Array reference data type for arrays located in the message. 31 * \note Use Array for normal RPC interfaces, Array_ref is usually used 32 * as server-side argument, see Array. 33 * \tparam ELEM_TYPE The data type of an array element, should be 'const' 34 * when used as input. 35 * \tparam LEN_TYPE Data type used to store the number of elements in 36 * the array. 37 */ 38template< typename ELEM_TYPE, typename LEN_TYPE = Array_len_default > 39struct Array_ref 40{ 41 typedef ELEM_TYPE *ptr_type; 42 typedef LEN_TYPE len_type; 43 44 len_type length; 45 ptr_type data; 46 Array_ref() = default; 47 Array_ref(len_type length, ptr_type data) 48 : length(length), data(data) 49 {} 50 51 template<typename X> struct Non_const 52 { typedef Array_ref<X, LEN_TYPE> type; }; 53 54 template<typename X> struct Non_const<X const> 55 { typedef Array_ref<X, LEN_TYPE> type; }; 56 57 Array_ref(typename Non_const<ELEM_TYPE>::type const &other) 58 : length(other.length), data(other.data) 59 {} 60}; 61 62/** 63 * Array data type for dynamically sized arrays in RPCs. 64 * \tparam ELEM_TYPE The data type of an array element, should be 'const' 65 * when used as input. 66 * \tparam LEN_TYPE Data type used to store the number of elements in 67 * the array. 68 * 69 * An Array generally encapsulates a data pointer and a length (number of 70 * elements). Array does \em not provide any storage for the data itself. 71 * The storage is either provided by a client-side caller or in the case 72 * of Array_ref is the message itself. 73 * 74 * Arrays can be used as input or as output arguments, when used as input 75 * ELEM_TYPE should be qualified \a const, when used as output a reference 76 * to an array must be used and the ELEM_TYPE must \em not be qualified 77 * \a const. It is the caller's responsibility to provide an array buffer 78 * of sufficient length. If a message from the server is too large it will 79 * be silently truncated. 80 * 81 * If backward compatibility with Ipc::Stream is required, then LEN_TYPE must 82 * be `unsigned long`. 83 */ 84template<typename ELEM_TYPE, typename LEN_TYPE = Array_len_default> 85struct Array : Array_ref<ELEM_TYPE , LEN_TYPE> 86{ 87 /// Make array 88 Array() {} 89 /// Make array from length and data pointer. 90 Array(LEN_TYPE length, ELEM_TYPE *data) 91 : Array_ref<ELEM_TYPE, LEN_TYPE>(length, data) 92 {} 93 94 template<typename X> struct Non_const 95 { typedef Array<X, LEN_TYPE> type; }; 96 97 template<typename X> struct Non_const<X const> 98 { typedef Array<X, LEN_TYPE> type; }; 99 100 /// Make a const array from a non-const array 101 Array(typename Non_const<ELEM_TYPE>::type const &other) 102 : Array_ref<ELEM_TYPE, LEN_TYPE>(other.length, other.data) 103 {} 104}; 105 106/** 107 * Server-side copy in buffer for Array. 108 * \tparam ELEM_TYPE Data type of an array element. 109 * \tparam LEN_TYPE Data type for the number of elements in the array. 110 * \tparam MAX The maximum number of elements in the buffer. 111 * If the actual message is longer than the buffer, it 112 * will be silently truncated. 113 * 114 * This type is assignment compatible to Array_ref<ELEM_TYPE, LEN_TYPE> and 115 * provides a transparent server-side copy-in mechanism for array parameters. 116 * The Array_in_buf provides the storage for the array data and receives a 117 * copy of the data passed to the server-function. 118 */ 119template< typename ELEM_TYPE, 120 typename LEN_TYPE = Array_len_default, 121 LEN_TYPE MAX = (L4_UTCB_GENERIC_DATA_SIZE * 122 sizeof(l4_umword_t)) / sizeof(ELEM_TYPE) > 123struct Array_in_buf 124{ 125 typedef Array_ref<ELEM_TYPE, LEN_TYPE> array; 126 typedef Array_ref<ELEM_TYPE const, LEN_TYPE> const_array; 127 128 /// The data elements 129 ELEM_TYPE data[MAX]; 130 /// The length of the array 131 LEN_TYPE length; 132 133 /// copy in data from a source array 134 void copy_in(const_array a) 135 { 136 length = a.length; 137 if (length > MAX) 138 length = MAX; 139 140 for (LEN_TYPE i = 0; i < length; ++i) 141 data[i] = a.data[i]; 142 } 143 144 /// Make Array_in_buf from a const array 145 Array_in_buf(const_array a) { copy_in(a); } 146 /// Make Array_in_buf from a non-const array 147 Array_in_buf(array a) { copy_in(a); } 148}; 149 150// implementation details for transmission 151namespace Msg { 152 153/// Array as input arguments 154template<typename A, typename LEN> 155struct Elem< Array<A, LEN> > 156{ 157 /// Array<> as argument at the interface 158 typedef Array<A, LEN> arg_type; 159 /// Array_ref<> at the server side 160 typedef Array_ref<A, LEN> svr_type; 161 typedef svr_type svr_arg_type; 162 enum { Is_optional = false }; 163}; 164 165/// Array as output argument 166template<typename A, typename LEN> 167struct Elem< Array<A, LEN> & > 168{ 169 /// Array<> & at the interface 170 typedef Array<A, LEN> &arg_type; 171 /// Array_ref<> as server storage type 172 typedef Array_ref<A, LEN> svr_type; 173 /// Array_ref<> & at the server side 174 typedef svr_type &svr_arg_type; 175 enum { Is_optional = false }; 176}; 177 178/// Array_ref as output argument 179template<typename A, typename LEN> 180struct Elem< Array_ref<A, LEN> & > 181{ 182 /// Array_ref<> at the interface 183 typedef Array_ref<A, LEN> &arg_type; 184 /// Array_ref<> as server storage 185 typedef Array_ref<typename L4::Types::Remove_const<A>::type, LEN> svr_type; 186 /// Array_ref<> & as server argument 187 typedef svr_type &svr_arg_type; 188 enum { Is_optional = false }; 189}; 190 191template<typename A> struct Class<Array<A> > : Class<A>::type {}; 192template<typename A> struct Class<Array_ref<A> > : Class<A>::type {}; 193 194namespace Detail { 195 196template<typename A, typename LEN, typename ARRAY, bool REF> 197struct Clnt_val_ops_d_in : Clnt_noops<ARRAY> 198{ 199 using Clnt_noops<ARRAY>::to_msg; 200 static int to_msg(char *msg, unsigned offset, unsigned limit, 201 ARRAY a, Dir_in, Cls_data) 202 { 203 offset = align_to<LEN>(offset); 204 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 205 return -L4_EMSGTOOLONG; 206 *reinterpret_cast<LEN *>(msg + offset) = a.length; 207 offset = align_to<A>(offset + sizeof(LEN)); 208 if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length))) 209 return -L4_EMSGTOOLONG; 210 typedef typename L4::Types::Remove_const<A>::type elem_type; 211 elem_type *data = reinterpret_cast<elem_type*>(msg + offset); 212 213 // we do not correctly handle overlaps 214 if (!REF || data != a.data) 215 for (LEN i = 0; i < a.length; ++i) 216 data[i] = a.data[i]; 217 218 return offset + a.length * sizeof(A); 219 } 220}; 221} // namespace Detail 222 223template<typename A, typename LEN> 224struct Clnt_val_ops<Array<A, LEN>, Dir_in, Cls_data> : 225 Detail::Clnt_val_ops_d_in<A, LEN, Array<A, LEN>, false> {}; 226 227template<typename A, typename LEN> 228struct Clnt_val_ops<Array_ref<A, LEN>, Dir_in, Cls_data> : 229 Detail::Clnt_val_ops_d_in<A, LEN, Array_ref<A, LEN>, true> {}; 230 231template<typename A, typename LEN, typename CLASS> 232struct Svr_val_ops< Array_ref<A, LEN>, Dir_in, CLASS > 233: Svr_noops< Array_ref<A, LEN> > 234{ 235 typedef Array_ref<A, LEN> svr_type; 236 237 using Svr_noops<svr_type>::to_svr; 238 static int to_svr(char *msg, unsigned offset, unsigned limit, 239 svr_type &a, Dir_in, Cls_data) 240 { 241 offset = align_to<LEN>(offset); 242 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 243 return -L4_EMSGTOOSHORT; 244 a.length = *reinterpret_cast<LEN *>(msg + offset); 245 offset = align_to<A>(offset + sizeof(LEN)); 246 if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length))) 247 return -L4_EMSGTOOSHORT; 248 a.data = reinterpret_cast<A*>(msg + offset); 249 return offset + a.length * sizeof(A); 250 } 251}; 252 253template<typename A, typename LEN> 254struct Svr_xmit< Array<A, LEN> > : Svr_xmit< Array_ref<A, LEN> > {}; 255 256template<typename A, typename LEN> 257struct Clnt_val_ops<Array<A, LEN>, Dir_out, Cls_data> : Clnt_noops<Array<A, LEN> > 258{ 259 typedef Array<A, LEN> type; 260 261 using Clnt_noops<type>::from_msg; 262 static int from_msg(char *msg, unsigned offset, unsigned limit, long, 263 type &a, Dir_out, Cls_data) 264 { 265 offset = align_to<LEN>(offset); 266 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 267 return -L4_EMSGTOOSHORT; 268 269 LEN l = *reinterpret_cast<LEN *>(msg + offset); 270 271 offset = align_to<A>(offset + sizeof(LEN)); 272 if (L4_UNLIKELY(!check_size<A>(offset, limit, l))) 273 return -L4_EMSGTOOSHORT; 274 275 A *data = reinterpret_cast<A*>(msg + offset); 276 277 if (l > a.length) 278 l = a.length; 279 else 280 a.length = l; 281 282 for (unsigned i = 0; i < l; ++i) 283 a.data[i] = data[i]; 284 285 return offset + l * sizeof(A); 286 }; 287}; 288 289template<typename A, typename LEN> 290struct Clnt_val_ops<Array_ref<A, LEN>, Dir_out, Cls_data> : 291 Clnt_noops<Array_ref<A, LEN> > 292{ 293 typedef Array_ref<A, LEN> type; 294 295 using Clnt_noops<type>::from_msg; 296 static int from_msg(char *msg, unsigned offset, unsigned limit, long, 297 type &a, Dir_out, Cls_data) 298 { 299 offset = align_to<LEN>(offset); 300 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 301 return -L4_EMSGTOOSHORT; 302 303 LEN l = *reinterpret_cast<LEN *>(msg + offset); 304 305 offset = align_to<A>(offset + sizeof(LEN)); 306 if (L4_UNLIKELY(!check_size<A>(offset, limit, l))) 307 return -L4_EMSGTOOSHORT; 308 309 a.data = reinterpret_cast<A*>(msg + offset); 310 a.length = l; 311 return offset + l * sizeof(A); 312 }; 313}; 314 315template<typename A, typename LEN, typename CLASS> 316struct Svr_val_ops<Array_ref<A, LEN>, Dir_out, CLASS> : 317 Svr_noops<Array_ref<typename L4::Types::Remove_const<A>::type, LEN> &> 318{ 319 typedef typename L4::Types::Remove_const<A>::type elem_type; 320 typedef Array_ref<elem_type, LEN> &svr_type; 321 322 using Svr_noops<svr_type>::to_svr; 323 static int to_svr(char *msg, unsigned offset, unsigned limit, 324 svr_type a, Dir_out, Cls_data) 325 { 326 offset = align_to<LEN>(offset); 327 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 328 return -L4_EMSGTOOLONG; 329 330 offset = align_to<A>(offset + sizeof(LEN)); 331 a.data = reinterpret_cast<elem_type *>(msg + offset); 332 a.length = (limit-offset) / sizeof(A); 333 return offset; 334 } 335 336 using Svr_noops<svr_type>::from_svr; 337 static int from_svr(char *msg, unsigned offset, unsigned limit, long, 338 svr_type a, Dir_out, Cls_data) 339 { 340 offset = align_to<LEN>(offset); 341 if (L4_UNLIKELY(!check_size<LEN>(offset, limit))) 342 return -L4_EMSGTOOLONG; 343 344 *reinterpret_cast<LEN *>(msg + offset) = a.length; 345 346 offset = align_to<A>(offset + sizeof(LEN)); 347 if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length))) 348 return -L4_EMSGTOOLONG; 349 350 return offset + a.length * sizeof(A); 351 } 352}; 353 354template<typename A, typename LEN> 355struct Svr_xmit<Array<A, LEN> &> : Svr_xmit<Array_ref<A, LEN> &> {}; 356 357// Pointer to array is not implemented. 358template<typename A, typename LEN> 359struct Is_valid_rpc_type< Array_ref<A, LEN> *> : L4::Types::False {}; 360 361// Optional input arrays are not implemented. 362template<typename A, typename LEN> 363struct Is_valid_rpc_type< Opt<Array_ref<A, LEN> > > : L4::Types::False {}; 364 365} // namespace Msg 366 367}} 368