blob: 4a232f42d945f68e1128d1c58dd126bccdc5455c [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/*- import 'helpers/error.c' as error with context -*/
/*- import 'helpers/marshal.c' as marshal with context -*/
/*? assert(isinstance(connector, namespace)) ?*/
#include <autoconf.h>
#include <sel4camkes/gen_config.h>
#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <camkes/error.h>
#include <camkes/marshal_macros.h>
#include <camkes/tls.h>
#include <sel4/sel4.h>
#include <camkes/dataport.h>
#include <utils/util.h>
/*? macros.show_includes(me.instance.type.includes) ?*/
/*? macros.show_includes(me.interface.type.includes) ?*/
/*- set instance = me.instance.name -*/
/*- set interface = me.interface.name -*/
/* Interface-specific error handling */
/*- set error_handler = '%s_error_handler' % me.interface.name -*/
/*? error.make_error_handler(interface, error_handler) ?*/
#define CAMKES_INTERFACE_NAME "/*? interface ?*/"
#define CAMKES_INSTANCE_NAME "/*? instance ?*/"
#define CAMKES_ERROR_HANDLER /*? error_handler ?*/
/*# Construct a dict from interface types to list of from ends indecies #*/
/*- set type_dict = {} -*/
/*- for f in me.parent.from_ends -*/
/*- set cur_list = type_dict.get(f.interface.type, []) -*/
/*- do cur_list.append(loop.index0) -*/
/*- do type_dict.update({f.interface.type: cur_list}) -*/
/*- endfor -*/
/*- for j, from_type in enumerate(type_dict.keys()) -*/
/*-- set methods_len = len(from_type.methods) -*/
/*-- for m in from_type.methods -*/
extern /*- if m.return_type is not none --*/
/*? macros.show_type(m.return_type) ?*/ /*- else --*/
void /*- endif --*/
/*?- me.interface.name ?*/_/*? m.name ?*/(
/*?- marshal.show_input_parameter_list(m.parameters, ['in', 'refin', 'out', 'inout']) ?*/
/*-- if len(m.parameters) == 0 -*/
void
/*-- endif --*/
);
/*- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/
/*? marshal.make_unmarshal_input_symbols(m.name, '%s_unmarshal_inputs' % m.name, methods_len, input_parameters, connector.recv_buffer_size_fixed) ?*/
/*- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/
/*? marshal.make_marshal_output_symbols(m.name, '%s_marshal_outputs' % m.name, output_parameters, m.return_type) ?*/
/*- endfor -*/
/*- endfor -*/
/*- set passive = options.realtime and configuration[me.instance.name].get("%s_passive" % me.interface.name, False) -*/
/*# Passive interface "run" functions must be passed a ntfn cap as part of the passive thread init protocol.
*# As such if this is a passive interface, a different function prototype is needed for "run".
#*/
int /*- if passive -*/
/*?- me.interface.name ?*/__run_passive(seL4_CPtr init_ntfn)
/*-- else -*/
/*?- me.interface.name ?*/__run(void)
/*-- endif -*/
{
unsigned size;
unsigned length = 0;
/*- if passive -*/
/*? recv_first_rpc(connector, "size", me.might_block(), notify_cptr = "init_ntfn") ?*/
/*- else -*/
/*? recv_first_rpc(connector, "size", me.might_block()) ?*/
/*- endif -*/
while (1) {
/*- if len(type_dict.keys()) > 1 -*/
switch (/*? connector.badge_symbol ?*/) {
/*- endif -*/
/*- for from_index, from_type in enumerate(type_dict.keys()) -*/
/*- set methods_len = len(from_type.methods) -*/
/*- if len(type_dict.keys()) > 1 -*/
/*- for from_index in type_dict.get(from_type) -*/
case /*? connector.badges[from_index] ?*/: {
/*- endfor -*/
/*- endif -*/
/*- if methods_len <= 1 -*/
unsigned call = 0;
unsigned * call_ptr = &call;
/*- else -*/
/*- set type = macros.type_to_fit_integer(methods_len) -*/
/*? type ?*/ call;
/*? type ?*/ * call_ptr = &call;
unsigned offset = 0;
UNMARSHAL_PARAM(call_ptr, /*? connector.recv_buffer ?*/, size , offset, "/*? me.interface.name ?*/", "method_index", ({
/*? complete_recv(connector) ?*/
goto begin_recv;
}));
/*- endif -*/
switch (* call_ptr) {
/*-- for i, m in enumerate(from_type.methods) -*/
case /*? i ?*/: { /*? '%s%s%s%s%s' % ('/', '* ', m.name, ' *', '/') ?*/
/*#- Declare parameters. #*/
/*-- for p in m.parameters -*/
/*-- if p.array -*/
size_t p_/*? p.name ?*/_sz;
size_t * p_/*? p.name ?*/_sz_ptr = &p_/*? p.name ?*/_sz;
/*-- if p.type == 'string' -*/
char ** p_/*? p.name ?*/ = NULL;
char *** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/;
/*-- else -*/
/*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/ = NULL;
/*? macros.show_type(p.type) ?*/ ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/;
/*-- endif -*/
/*-- elif p.type == 'string' -*/
char * p_/*? p.name ?*/ = NULL;
char ** p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/;
/*-- else -*/
/*? macros.show_type(p.type) ?*/ p_/*? p.name ?*/;
/*? macros.show_type(p.type) ?*/ * p_/*? p.name ?*/_ptr = &p_/*? p.name ?*/;
/*-- endif -*/
/*-- endfor -*/
/* Unmarshal parameters */
/*-- set input_parameters = list(filter(lambda('x: x.direction in [\'refin\', \'in\', \'inout\']'), m.parameters)) -*/
int err = /*? marshal.call_unmarshal_input('%s_unmarshal_inputs' % m.name, connector.recv_buffer, "size", input_parameters, namespace_prefix='p_') ?*/;
if (unlikely(err != 0)) {
/* Error in unmarshalling; return to event loop. */
/*?- complete_recv(connector) ?*/
goto begin_recv;
}
/* Call the implementation */
/*-- set ret = "%s_ret" % (m.name) -*/
/*-- set ret_sz = "%s_ret_sz" % (m.name) -*/
/*-- set ret_ptr = "%s_ret_ptr" % (m.name) -*/
/*-- set ret_sz_ptr = "%s_ret_sz_ptr" % (m.name) -*/
/*-- if m.return_type is not none -*/
/*-- if m.return_type == 'string' -*/
char * /*? ret ?*/;
char ** /*? ret_ptr ?*/ = &/*? ret ?*/;
/*-- else -*/
/*? macros.show_type(m.return_type) ?*/ /*? ret ?*/;
/*? macros.show_type(m.return_type) ?*/ * /*? ret_ptr ?*/ = &/*? ret ?*/;
/*-- endif --*/
* /*? ret_ptr ?*/ =
/*-- endif --*/
/*? me.interface.name ?*/_/*? m.name ?*/(
/*-- for p in m.parameters -*/
/*-- if p.array -*/
/*-- if p.direction == 'in' -*/* /*- endif --*/
p_/*? p.name ?*/_sz_ptr,
/*-- endif -*/
/*-- if p.direction =='in' --*/* /*- endif --*/
p_/*? p.name ?*/_ptr
/*-- if not loop.last -*/,/*- endif --*/
/*-- endfor --*/
);
/*? complete_recv(connector) ?*/
/*? begin_reply(connector) ?*/
/* Marshal the response */
/*-- set output_parameters = list(filter(lambda('x: x.direction in [\'out\', \'inout\']'), m.parameters)) -*/
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_') ?*/;
/*#- We no longer need anything we previously malloced #*/
/*-- if m.return_type == 'string' -*/
free(* /*? ret_ptr ?*/);
/*-- endif -*/
/*-- for p in m.parameters -*/
/*-- if p.array -*/
/*-- if p.type == 'string' -*/
for (int mcount = 0; mcount < * p_/*? p.name ?*/_sz_ptr; mcount++) {
free((* p_/*? p.name ?*/_ptr)[mcount]);
}
/*-- endif -*/
free(* p_/*? p.name ?*/_ptr);
/*-- elif p.type == 'string' -*/
free(* p_/*? p.name ?*/_ptr);
/*-- endif -*/
/*-- endfor -*/
/* Check if there was an error during marshalling. We do
* this after freeing internal parameter variables to avoid
* leaking memory on errors.
*/
if (unlikely(length == UINT_MAX)) {
/*?- complete_reply(connector) ?*/
goto begin_recv;
}
goto reply_recv;
}
/*- endfor -*/
default: {
ERR(/*? error_handler ?*/, ((camkes_error_t){
.type = CE_INVALID_METHOD_INDEX,
.instance = "/*? instance ?*/",
.interface = "/*? interface ?*/",
.description = "invalid method index received in /*? me.interface.name ?*/",
.lower_bound = 0,
.upper_bound = /*? methods_len ?*/ - 1,
.invalid_index = * call_ptr,
}), ({
/*? complete_recv(connector) ?*/
goto begin_recv;
}));
}
}
/*- if len(type_dict.keys()) > 1 -*/
break;
}
/*- endif -*/
/*- endfor -*/
/*- if len(type_dict.keys()) > 1 -*/
default:
ERR(/*? error_handler ?*/, ((camkes_error_t){
.type = CE_MALFORMED_RPC_PAYLOAD,
.instance = "/*? instance ?*/",
.interface = "/*? interface ?*/",
.description = "unknown badge while unmarshalling method in /*? me.interface.name ?*/",
.length = size,
.current_index = /*? connector.badge_symbol ?*/,
}), ({
/*? complete_recv(connector) ?*/
goto begin_recv;
}));
break;
}
/*- endif -*/
/* These labels are used to reduce the same code getting generated for each
* case statement.
*/
reply_recv: {
/*? reply_recv(connector, "length", "size", me.might_block()) ?*/
continue;
}
begin_recv: {
/*? begin_recv(connector, "size", me.might_block()) ?*/
continue;
}
}
UNREACHABLE();
}