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