1/* 2 * Copyright 2020, 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 14/*- from 'rpc-connector.c' import establish_recv_rpc, recv_first_rpc, complete_recv, begin_recv, begin_reply, complete_reply, reply_recv with context -*/ 15/*- from 'global-endpoint.template.c' import allocate_rpc_endpoint_cap with context -*/ 16/*- import 'helpers/error.c' as error with context -*/ 17/*- import 'helpers/marshal.c' as marshal with context -*/ 18 19#include <autoconf.h> 20#include <sel4camkes/gen_config.h> 21#include <assert.h> 22#include <limits.h> 23#include <stddef.h> 24#include <stdlib.h> 25#include <string.h> 26#include <camkes/error.h> 27#include <camkes/marshal_macros.h> 28#include <camkes/tls.h> 29#include <sel4/sel4.h> 30#include <camkes/dataport.h> 31#include <utils/util.h> 32 33/*? macros.show_includes(me.instance.type.includes) ?*/ 34/*? macros.show_includes(me.interface.type.includes) ?*/ 35 36/*- set connector = namespace() -*/ 37 38/*- set connector.language = 'c' -*/ 39/*# Establish the buffer for message contents #*/ 40/*- set connector.userspace_ipc = False -*/ 41/*- set base = '((void*)&seL4_GetIPCBuffer()->msg[0])' -*/ 42/*- set buffer_size = '(seL4_MsgMaxLength * sizeof(seL4_Word))' -*/ 43/*- set connector.lock = False -*/ 44/*- set connector.send_buffer = base -*/ 45/*- set connector.recv_buffer = base -*/ 46/*- set connector.send_buffer_size = buffer_size -*/ 47/*- set connector.recv_buffer_size = buffer_size -*/ 48/*- set connector.recv_buffer_size_fixed = connector.userspace_ipc -*/ 49 50/*# Ensure the endpoint is allocated #*/ 51/*- do allocate_rpc_endpoint_cap(me, is_reader=True, other_end=me.parent.from_ends[0]) -*/ 52/*- set connector.badges = pop('badges') -*/ 53/*- set connector.ep = pop('endpoint') -*/ 54/*- set connector.badge_symbol = '%s_badge' % me.interface.name -*/ 55#include <sel4/sel4.h> 56static seL4_Word /*? connector.badge_symbol ?*/ = 0; 57 58seL4_Word /*? me.interface.name ?*/_get_sender_id(void) { 59 switch (/*? connector.badge_symbol ?*/) { 60 /*- for from_end in me.parent.from_ends -*/ 61 case /*? connector.badges[loop.index0] ?*/: 62 return /*? loop.index0 ?*/; 63 break; 64 /*- endfor -*/ 65 default: 66 ZF_LOGE("Invalid Badge: %"PRIdPTR" doesn't match any client ID", /*? connector.badge_symbol ?*/); 67 } 68 69 return -1; 70} 71 72 73/*- set instance = me.instance.name -*/ 74/*- set interface = me.interface.name -*/ 75 76/* Interface-specific error handling */ 77/*- set error_handler = '%s_error_handler' % me.interface.name -*/ 78/*? error.make_error_handler(interface, error_handler) ?*/ 79 80#define CAMKES_INTERFACE_NAME "/*? interface ?*/" 81#define CAMKES_INSTANCE_NAME "/*? instance ?*/" 82#define CAMKES_ERROR_HANDLER /*? error_handler ?*/ 83 84/*# Construct a dict from interface types to list of from ends indecies #*/ 85/*- set type_dict = {} -*/ 86/*- for f in me.parent.from_ends -*/ 87 /*- set cur_list = type_dict.get(f.interface.type, []) -*/ 88 /*- do cur_list.append(loop.index0) -*/ 89 /*- do type_dict.update({f.interface.type: cur_list}) -*/ 90/*- endfor -*/ 91 92/*- for j, from_type in enumerate(type_dict.keys()) -*/ 93 /*-- set methods_len = len(from_type.methods) -*/ 94 /*-- for m in from_type.methods -*/ 95 extern /*- if m.return_type is not none --*/ 96 /*? macros.show_type(m.return_type) ?*/ /*- else --*/ 97 void /*- endif --*/ 98 /*?- me.interface.name ?*/_/*? m.name ?*/( 99 /*?- marshal.show_input_parameter_list(m.parameters, ['in', 'refin', 'out', 'inout']) ?*/ 100 /*-- if len(m.parameters) == 0 -*/ 101 void 102 /*-- endif --*/ 103 ); 104 105 /*- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/ 106 /*? marshal.make_unmarshal_input_symbols(m.name, '%s_unmarshal_inputs' % m.name, methods_len, input_parameters, connector.recv_buffer_size_fixed) ?*/ 107 108 /*- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/ 109 /*? marshal.make_marshal_output_symbols(m.name, '%s_marshal_outputs' % m.name, output_parameters, m.return_type) ?*/ 110 111 /*- endfor -*/ 112/*- endfor -*/ 113 114 115int /*? me.interface.name ?*/_handle_message(seL4_MessageInfo_t *info, seL4_Word badge) 116{ 117 118 unsigned size = seL4_MessageInfo_get_length(*info) * sizeof(seL4_Word); 119 assert(size <= seL4_MsgMaxLength * sizeof(seL4_Word)); 120 unsigned length = 0; 121 /*? connector.badge_symbol ?*/ = badge; 122 /*- if len(type_dict.keys()) > 1 -*/ 123 switch (/*? connector.badge_symbol ?*/) { 124 /*- endif -*/ 125 /*- for from_index, from_type in enumerate(type_dict.keys()) -*/ 126 /*- set methods_len = len(from_type.methods) -*/ 127 /*- if len(type_dict.keys()) > 1 -*/ 128 /*- for from_index in type_dict.get(from_type) -*/ 129 case /*? connector.badges[from_index] ?*/: { 130 /*- endfor -*/ 131 /*- endif -*/ 132 133 /*- if methods_len <= 1 -*/ 134 unsigned call = 0; 135 unsigned * call_ptr = &call; 136 /*- else -*/ 137 /*- set type = macros.type_to_fit_integer(methods_len) -*/ 138 /*? type ?*/ call; 139 /*? type ?*/ * call_ptr = &call; 140 unsigned offset = 0; 141 UNMARSHAL_PARAM(call_ptr, /*? connector.recv_buffer ?*/, size , offset, "/*? me.interface.name ?*/", "method_index", ({ 142 /*? complete_recv(connector) ?*/ 143 goto begin_recv; 144 })); 145 /*- endif -*/ 146 147 switch (* call_ptr) { 148 /*-- for i, m in enumerate(from_type.methods) -*/ 149 case /*? i ?*/: { /*? '%s%s%s%s%s' % ('/', '* ', m.name, ' *', '/') ?*/ 150 /*#- Declare parameters. #*/ 151 /*-- for p in m.parameters -*/ 152 153 /*-- if p.array -*/ 154 size_t p_/*? p.name ?*/_sz; 155 size_t * p_/*? p.name ?*/_sz_ptr = &p_/*? p.name ?*/_sz; 156 /*-- if p.type == 'string' -*/ 157 char ** p_/*? p.name ?*/ = NULL; 158 char *** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 159 /*-- else -*/ 160 /*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/ = NULL; 161 /*? macros.show_type(p.type) ?*/ ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 162 /*-- endif -*/ 163 /*-- elif p.type == 'string' -*/ 164 char * p_/*? p.name ?*/ = NULL; 165 char ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 166 /*-- else -*/ 167 /*? macros.show_type(p.type) ?*/ p_/*? p.name ?*/; 168 /*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/; 169 /*-- endif -*/ 170 /*-- endfor -*/ 171 172 /* Unmarshal parameters */ 173 /*-- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/ 174 int err = /*? marshal.call_unmarshal_input('%s_unmarshal_inputs' % m.name, connector.recv_buffer, "size", input_parameters, namespace_prefix='p_') ?*/; 175 if (unlikely(err != 0)) { 176 /* Error in unmarshalling; return to event loop. */ 177 /*?- complete_recv(connector) ?*/ 178 goto begin_recv; 179 } 180 /* Call the implementation */ 181 /*-- set ret = "%s_ret" % (m.name) -*/ 182 /*-- set ret_sz = "%s_ret_sz" % (m.name) -*/ 183 /*-- set ret_ptr = "%s_ret_ptr" % (m.name) -*/ 184 /*-- set ret_sz_ptr = "%s_ret_sz_ptr" % (m.name) -*/ 185 /*-- if m.return_type is not none -*/ 186 /*-- if m.return_type == 'string' -*/ 187 char * /*? ret ?*/; 188 char ** /*? ret_ptr ?*/ = &/*? ret ?*/; 189 /*-- else -*/ 190 /*? macros.show_type(m.return_type) ?*/ /*? ret ?*/; 191 /*? macros.show_type(m.return_type) ?*/ * /*? ret_ptr ?*/ = &/*? ret ?*/; 192 /*-- endif --*/ 193 * /*? ret_ptr ?*/ = 194 /*-- endif --*/ 195 /*? me.interface.name ?*/_/*? m.name ?*/( 196 /*-- for p in m.parameters -*/ 197 /*-- if p.array -*/ 198 /*-- if p.direction == 'in' -*/* /*- endif --*/ 199 p_/*? p.name ?*/_sz_ptr, 200 /*-- endif -*/ 201 /*-- if p.direction =='in' --*/* /*- endif --*/ 202 p_/*? p.name ?*/_ptr 203 /*-- if not loop.last -*/,/*- endif --*/ 204 /*-- endfor --*/ 205 ); 206 207 /*? complete_recv(connector) ?*/ 208 /*? begin_reply(connector) ?*/ 209 210 /* Marshal the response */ 211 /*-- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/ 212 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_') ?*/; 213 214 /*#- We no longer need anything we previously malloced #*/ 215 /*-- if m.return_type == 'string' -*/ 216 free(* /*? ret_ptr ?*/); 217 /*-- endif -*/ 218 /*-- for p in m.parameters -*/ 219 /*-- if p.array -*/ 220 /*-- if p.type == 'string' -*/ 221 for (int mcount = 0; mcount < * p_/*? p.name ?*/_sz_ptr; mcount++) { 222 free((* p_/*? p.name ?*/_ptr)[mcount]); 223 } 224 /*-- endif -*/ 225 free(* p_/*? p.name ?*/_ptr); 226 /*-- elif p.type == 'string' -*/ 227 free(* p_/*? p.name ?*/_ptr); 228 /*-- endif -*/ 229 /*-- endfor -*/ 230 231 /* Check if there was an error during marshalling. We do 232 * this after freeing internal parameter variables to avoid 233 * leaking memory on errors. 234 */ 235 if (unlikely(length == UINT_MAX)) { 236 /*?- complete_reply(connector) ?*/ 237 goto begin_recv; 238 } 239 240 goto reply_recv; 241 } 242 /*- endfor -*/ 243 default: { 244 ERR(/*? error_handler ?*/, ((camkes_error_t){ 245 .type = CE_INVALID_METHOD_INDEX, 246 .instance = "/*? instance ?*/", 247 .interface = "/*? interface ?*/", 248 .description = "invalid method index received in /*? me.interface.name ?*/", 249 .lower_bound = 0, 250 .upper_bound = /*? methods_len ?*/ - 1, 251 .invalid_index = * call_ptr, 252 }), ({ 253 /*? complete_recv(connector) ?*/ 254 goto begin_recv; 255 })); 256 } 257 } 258 /*- if len(type_dict.keys()) > 1 -*/ 259 break; 260 } 261 /*- endif -*/ 262 /*- endfor -*/ 263 /*- if len(type_dict.keys()) > 1 -*/ 264 default: 265 ERR(/*? error_handler ?*/, ((camkes_error_t){ 266 .type = CE_MALFORMED_RPC_PAYLOAD, 267 .instance = "/*? instance ?*/", 268 .interface = "/*? interface ?*/", 269 .description = "unknown badge while unmarshalling method in /*? me.interface.name ?*/", 270 .length = size, 271 .current_index = /*? connector.badge_symbol ?*/, 272 }), ({ 273 /*? complete_recv(connector) ?*/ 274 goto begin_recv; 275 })); 276 break; 277 } 278 /*- endif -*/ 279 280/* These labels are used to reduce the same code getting generated for each 281 * case statement. 282 */ 283reply_recv: { 284 *info = seL4_MessageInfo_new(0, 0, 0, ROUND_UP_UNSAFE(length, sizeof(seL4_Word)) / sizeof(seL4_Word)); 285 return 1; 286} 287 288begin_recv: { 289 return 0; 290} 291 292} 293