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