1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/*- import 'helpers/error.c' as error with context -*/ 14/*- import 'helpers/marshal.c' as marshal with context -*/ 15 16/*? assert(isinstance(connector, namespace)) ?*/ 17 18#include <autoconf.h> 19#include <sel4camkes/gen_config.h> 20#include <assert.h> 21#include <limits.h> 22#include <stddef.h> 23#include <stdlib.h> 24#include <string.h> 25#include <camkes/error.h> 26#include <camkes/marshal_macros.h> 27#include <camkes/tls.h> 28#include <sel4/sel4.h> 29#include <camkes/dataport.h> 30#include <utils/util.h> 31 32/*? macros.show_includes(me.instance.type.includes) ?*/ 33/*? macros.show_includes(me.interface.type.includes) ?*/ 34 35/*- set instance = me.instance.name -*/ 36/*- set interface = me.interface.name -*/ 37 38/* Interface-specific error handling */ 39/*- set error_handler = '%s_error_handler' % me.interface.name -*/ 40/*? error.make_error_handler(interface, error_handler) ?*/ 41 42#define CAMKES_INTERFACE_NAME "/*? interface ?*/" 43#define CAMKES_INSTANCE_NAME "/*? instance ?*/" 44#define CAMKES_ERROR_HANDLER /*? error_handler ?*/ 45 46/*# Construct a dict from interface types to list of from ends indecies #*/ 47/*- set type_dict = {} -*/ 48/*- for f in me.parent.from_ends -*/ 49 /*- set cur_list = type_dict.get(f.interface.type, []) -*/ 50 /*- do cur_list.append(loop.index0) -*/ 51 /*- do type_dict.update({f.interface.type: cur_list}) -*/ 52/*- endfor -*/ 53 54/*- for j, from_type in enumerate(type_dict.keys()) -*/ 55 /*-- set methods_len = len(from_type.methods) -*/ 56 /*-- for m in from_type.methods -*/ 57 extern /*- if m.return_type is not none --*/ 58 /*? macros.show_type(m.return_type) ?*/ /*- else --*/ 59 void /*- endif --*/ 60 /*?- me.interface.name ?*/_/*? m.name ?*/( 61 /*?- marshal.show_input_parameter_list(m.parameters, ['in', 'refin', 'out', 'inout']) ?*/ 62 /*-- if len(m.parameters) == 0 -*/ 63 void 64 /*-- endif --*/ 65 ); 66 67 /*- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/ 68 /*? marshal.make_unmarshal_input_symbols(m.name, '%s_unmarshal_inputs' % m.name, methods_len, input_parameters, connector.recv_buffer_size_fixed) ?*/ 69 70 /*- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/ 71 /*? marshal.make_marshal_output_symbols(m.name, '%s_marshal_outputs' % m.name, output_parameters, m.return_type) ?*/ 72 73 /*- endfor -*/ 74/*- endfor -*/ 75 76/*- set passive = options.realtime and configuration[me.instance.name].get("%s_passive" % me.interface.name, False) -*/ 77 78/*# Passive interface "run" functions must be passed a ntfn cap as part of the passive thread init protocol. 79 *# As such if this is a passive interface, a different function prototype is needed for "run". 80 #*/ 81int /*- if passive -*/ 82 /*?- me.interface.name ?*/__run_passive(seL4_CPtr init_ntfn) 83/*-- else -*/ 84 /*?- me.interface.name ?*/__run(void) 85/*-- endif -*/ 86{ 87 88 unsigned size; 89 unsigned length = 0; 90 /*- if passive -*/ 91 /*? recv_first_rpc(connector, "size", me.might_block(), notify_cptr = "init_ntfn") ?*/ 92 /*- else -*/ 93 /*? recv_first_rpc(connector, "size", me.might_block()) ?*/ 94 /*- endif -*/ 95 96 while (1) { 97 /*- if len(type_dict.keys()) > 1 -*/ 98 switch (/*? connector.badge_symbol ?*/) { 99 /*- endif -*/ 100 /*- for from_index, from_type in enumerate(type_dict.keys()) -*/ 101 /*- set methods_len = len(from_type.methods) -*/ 102 /*- if len(type_dict.keys()) > 1 -*/ 103 /*- for from_index in type_dict.get(from_type) -*/ 104 case /*? connector.badges[from_index] ?*/: { 105 /*- endfor -*/ 106 /*- endif -*/ 107 108 /*- if methods_len <= 1 -*/ 109 unsigned call = 0; 110 unsigned * call_ptr = &call; 111 /*- else -*/ 112 /*- set type = macros.type_to_fit_integer(methods_len) -*/ 113 /*? type ?*/ call; 114 /*? type ?*/ * call_ptr = &call; 115 unsigned offset = 0; 116 UNMARSHAL_PARAM(call_ptr, /*? connector.recv_buffer ?*/, size , offset, "/*? me.interface.name ?*/", "method_index", ({ 117 /*? complete_recv(connector) ?*/ 118 goto begin_recv; 119 })); 120 /*- endif -*/ 121 122 switch (* call_ptr) { 123 /*-- for i, m in enumerate(from_type.methods) -*/ 124 case /*? i ?*/: { /*? '%s%s%s%s%s' % ('/', '* ', m.name, ' *', '/') ?*/ 125 /*#- Declare parameters. #*/ 126 /*-- for p in m.parameters -*/ 127 128 /*-- if p.array -*/ 129 size_t p_/*? p.name ?*/_sz; 130 size_t * p_/*? p.name ?*/_sz_ptr = &p_/*? p.name ?*/_sz; 131 /*-- if p.type == 'string' -*/ 132 char ** p_/*? p.name ?*/ = NULL; 133 char *** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 134 /*-- else -*/ 135 /*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/ = NULL; 136 /*? macros.show_type(p.type) ?*/ ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 137 /*-- endif -*/ 138 /*-- elif p.type == 'string' -*/ 139 char * p_/*? p.name ?*/ = NULL; 140 char ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 141 /*-- else -*/ 142 /*? macros.show_type(p.type) ?*/ p_/*? p.name ?*/; 143 /*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 144 /*-- endif -*/ 145 /*-- endfor -*/ 146 147 /* Unmarshal parameters */ 148 /*-- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/ 149 int err = /*? marshal.call_unmarshal_input('%s_unmarshal_inputs' % m.name, connector.recv_buffer, "size", input_parameters, namespace_prefix='p_') ?*/; 150 if (unlikely(err != 0)) { 151 /* Error in unmarshalling; return to event loop. */ 152 /*?- complete_recv(connector) ?*/ 153 goto begin_recv; 154 } 155 /* Call the implementation */ 156 /*-- set ret = "%s_ret" % (m.name) -*/ 157 /*-- set ret_sz = "%s_ret_sz" % (m.name) -*/ 158 /*-- set ret_ptr = "%s_ret_ptr" % (m.name) -*/ 159 /*-- set ret_sz_ptr = "%s_ret_sz_ptr" % (m.name) -*/ 160 /*-- if m.return_type is not none -*/ 161 /*-- if m.return_type == 'string' -*/ 162 char * /*? ret ?*/; 163 char ** /*? ret_ptr ?*/ = &/*? ret ?*/; 164 /*-- else -*/ 165 /*? macros.show_type(m.return_type) ?*/ /*? ret ?*/; 166 /*? macros.show_type(m.return_type) ?*/ * /*? ret_ptr ?*/ = &/*? ret ?*/; 167 /*-- endif --*/ 168 * /*? ret_ptr ?*/ = 169 /*-- endif --*/ 170 /*? me.interface.name ?*/_/*? m.name ?*/( 171 /*-- for p in m.parameters -*/ 172 /*-- if p.array -*/ 173 /*-- if p.direction == 'in' -*/* /*- endif --*/ 174 p_/*? p.name ?*/_sz_ptr, 175 /*-- endif -*/ 176 /*-- if p.direction =='in' --*/* /*- endif --*/ 177 p_/*? p.name ?*/_ptr 178 /*-- if not loop.last -*/,/*- endif --*/ 179 /*-- endfor --*/ 180 ); 181 182 /*? complete_recv(connector) ?*/ 183 /*? begin_reply(connector) ?*/ 184 185 /* Marshal the response */ 186 /*-- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/ 187 length = /*? marshal.call_marshal_output('%s_marshal_outputs' % m.name, connector.send_buffer, connector.send_buffer_size, output_parameters, m.return_type, ret_ptr, namespace_prefix='p_') ?*/; 188 189 /*#- We no longer need anything we previously malloced #*/ 190 /*-- if m.return_type == 'string' -*/ 191 free(* /*? ret_ptr ?*/); 192 /*-- endif -*/ 193 /*-- for p in m.parameters -*/ 194 /*-- if p.array -*/ 195 /*-- if p.type == 'string' -*/ 196 for (int mcount = 0; mcount < * p_/*? p.name ?*/_sz_ptr; mcount++) { 197 free((* p_/*? p.name ?*/_ptr)[mcount]); 198 } 199 /*-- endif -*/ 200 free(* p_/*? p.name ?*/_ptr); 201 /*-- elif p.type == 'string' -*/ 202 free(* p_/*? p.name ?*/_ptr); 203 /*-- endif -*/ 204 /*-- endfor -*/ 205 206 /* Check if there was an error during marshalling. We do 207 * this after freeing internal parameter variables to avoid 208 * leaking memory on errors. 209 */ 210 if (unlikely(length == UINT_MAX)) { 211 /*?- complete_reply(connector) ?*/ 212 goto begin_recv; 213 } 214 215 goto reply_recv; 216 } 217 /*- endfor -*/ 218 default: { 219 ERR(/*? error_handler ?*/, ((camkes_error_t){ 220 .type = CE_INVALID_METHOD_INDEX, 221 .instance = "/*? instance ?*/", 222 .interface = "/*? interface ?*/", 223 .description = "invalid method index received in /*? me.interface.name ?*/", 224 .lower_bound = 0, 225 .upper_bound = /*? methods_len ?*/ - 1, 226 .invalid_index = * call_ptr, 227 }), ({ 228 /*? complete_recv(connector) ?*/ 229 goto begin_recv; 230 })); 231 } 232 } 233 /*- if len(type_dict.keys()) > 1 -*/ 234 break; 235 } 236 /*- endif -*/ 237 /*- endfor -*/ 238 /*- if len(type_dict.keys()) > 1 -*/ 239 default: 240 ERR(/*? error_handler ?*/, ((camkes_error_t){ 241 .type = CE_MALFORMED_RPC_PAYLOAD, 242 .instance = "/*? instance ?*/", 243 .interface = "/*? interface ?*/", 244 .description = "unknown badge while unmarshalling method in /*? me.interface.name ?*/", 245 .length = size, 246 .current_index = /*? connector.badge_symbol ?*/, 247 }), ({ 248 /*? complete_recv(connector) ?*/ 249 goto begin_recv; 250 })); 251 break; 252 } 253 /*- endif -*/ 254 255/* These labels are used to reduce the same code getting generated for each 256 * case statement. 257 */ 258reply_recv: { 259 /*? reply_recv(connector, "length", "size", me.might_block()) ?*/ 260 continue; 261} 262 263begin_recv: { 264 /*? begin_recv(connector, "size", me.might_block()) ?*/ 265 continue; 266} 267 268 } 269 270 UNREACHABLE(); 271} 272