1/*
2 * Copyright 2016, 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(D61_BSD)
11 */
12
13/**
14 * @file   rpc.h
15 * @date   Fri 09 Aug 2013 13:00:56 EST
16 *
17 * @brief  seL4 CIDL RPC Backend Interface
18 *
19 * This library provides the backend which the code generated from CIDL - Simple C IDL compiler
20 * uses in order to work. This library must deal with basic serialisation / deserialisation,
21 * manage basic client state on server side, and manage the communication channel in between.
22 * The CIDL generated code expects this library to be there.
23 *
24 * NOTE: All of the implementations here may _NOT_ themselves send RPCs, with few exception.
25 * Remember that if your printf involves an IPC to a server, this means no printf unless you
26 * use another IPC buffer. Likewise with malloc.
27 */
28
29#ifndef _REFOS_RPC_H_
30#define _REFOS_RPC_H_
31
32#include <stdio.h>
33#include <stdint.h>
34#include <stdlib.h>
35#include <stdbool.h>
36#include <string.h>
37#include <assert.h>
38
39/**
40 * Maximum number of tracked objects for a single RPC call. Shouldn't need to be too long unless
41 * you have functions which take a lot of arguments.
42 */
43#define RPC_MAX_TRACKED_OBJS 32
44
45// -------------------------------------------------------------------------------------------------
46// ------------------------------------------ IDL Declarations -------------------------------------
47// -------------------------------------------------------------------------------------------------
48
49#define _SEL4_
50#ifdef _SEL4_
51    #include <sel4/sel4.h>
52    #define ENDPT seL4_CPtr
53    typedef char byte;
54    typedef seL4_CPtr cptr;
55    typedef seL4_CPtr cslot;
56    typedef seL4_CPtr seL4_CSlot;
57    typedef seL4_MessageInfo_t msginfo_t;
58#else
59    #error "Unimplemented backend."
60#endif
61
62// -------------------------------------------------------------------------------------------------
63// ------------------------------------------- RPC Helper ------------------------------------------
64// -------------------------------------------------------------------------------------------------
65
66/**
67 * A helper function to allocate & manage the allocated memory for an RPC. Works like cstdlib
68 * malloc().
69 * @param[in] sz       Size of memory to allocate in bytes.
70 * @return             Pointer to allocated memory.
71 */
72void* rpc_malloc(size_t sz);
73
74/**
75 * Free the given object at memory address. Works like cstdlib free().
76 * @param[in] addr     The address ti free.
77 */
78void rpc_free(void *addr);
79
80/**
81 * Use the given cslot as the destination slot for cap transfer. If this isn't called explicitly,
82 * the provided client/server interface below should automatically call this with a default cslot.
83 * @param[in] recv_cslot CSpace slot to use to recieve caps.
84 */
85void rpc_setup_recv(cslot recv_cslot);
86
87/**
88 * Use the given cslot as the destination slot for cap transfer. This version does not assume
89 * default cspace.
90 * @param[in] cspace Root of the thread's CSpace.
91 * @param[in] recv_cslot Address of CSpace slot to use to recieve caps.
92 * @param[in] depth Number of bits of the capability address to be translated.
93 */
94void rpc_setup_recv_cspace(seL4_CPtr cspace, seL4_CPtr recv_cslot, seL4_Word depth);
95
96/**
97 * Resets the data pointers (e.g. current IPC MR number and cap number) in the client's send buffer.
98 * @param[in] cl       Generic reference to caller client state structure (optional).
99 */
100void rpc_reset_contents(void *cl);
101
102// -------------------------------------------------------------------------------------------------
103// ---------------------------------------------- Client RPC ---------------------------------------
104// -------------------------------------------------------------------------------------------------
105
106/**
107 * Initialise client state, ready for a new RPC call.
108 * @param[in] name_str Name of call being initiated (for easier debugging, may ignore this).
109 * @param[in] label    The call enum label which server will use to identify which call.
110 */
111void rpc_init(const char* name_str, int32_t label);
112
113/**
114 * Set a custom destination endpoint. By default the destination endpoint used is the one specified
115 * in the interface XML file. To support interfaces which make sense to be served by multiple
116 * servers, the IDL param mode='connect_ep' is used. CIDL will see this flag and call this function
117 * with the marked parameter.
118 * @param[in] dest     Destination server endpoint that the next rpc_call_server will invoke.
119 */
120void rpc_set_dest(ENDPT dest);
121
122/**
123 * Add a new integer type variable to the end of the current global RPC packet.
124 * @param[in] v        Value of integer to add.
125 */
126void rpc_push_uint(uint32_t v);
127
128/**
129 * Add a new C string type variable to the end of the current global RPC packet.
130 * @param[in] v        String to add.
131 */
132void rpc_push_str(const char* v);
133
134/**
135 * Add a new generic buffer object to the end of the current global RPC packet.
136 * @param[in] v        Pointer to buffer obj to add.
137 * @param[in] sz       Size of the buffer obj in bytes.
138 */
139void rpc_push_buf(void* v, size_t sz);
140
141/**
142 * Add a new array of generic buffer objects to the end of the current global RPC packet.
143 * @param[in] v        Pointer to array of buffer objects to add.
144 * @param[in] sz       Size of a single buffer obj in bytes.
145 * @param[in] count    Number of objects in v.
146 */
147void rpc_push_buf_array(void* v, size_t sz, uint32_t count);
148
149/**
150 * Add a new capablity to the end of the current global RPC packet.
151 * @param[in] v        Capability to add.
152 */
153void rpc_push_cptr(ENDPT v);
154
155/**
156 * Read the next integer type variable from current global RPC packet.
157 * @return             Value of next integer.
158 */
159uint32_t rpc_pop_uint();
160
161/**
162 * Read the next C string from current global RPC packet.
163 * NOTE: Using a string as output is not safe in standard C function calls, and likewise it is also
164 * not a good idea at all for RPC calls, and is prone to buffer overflow.
165 * @param[out] v       Pointer to allocated string to read into.
166 */
167void rpc_pop_str(char* v);
168
169/**
170 * Read the next generic buffer object from current global RPC packet.
171 * @param[out] v       Pointer to allocated buffer object to read into.
172 * @param[in] sz       Size of generic object to read in bytes.
173 */
174void rpc_pop_buf(void* v, size_t sz);
175
176/**
177 * Read the next capability from current global RPC packet. Note that this function may choose to
178 * copy out the recieved cap from the recieve slot in this function and leave an empty stub in
179 * rpc_copyout_cptr, or alternatively it may just simply return the recieve slot here and then
180 * implement copyout in rpc_copyout_cptr. See @ref rpc_copyout_cptr.
181 * @return             CSpace pointer to recieved capability.
182 */
183ENDPT rpc_pop_cptr();
184
185/**
186 * Read the next buffer object array from current global RPC packet.
187 * @param[out] v       Pointer to allocated buffer object to read into.
188 * @param[in] sz       Size of generic object to read in bytes.
189 * @param[in] count    Max. number of objects in array (only used for checking).
190 */
191void rpc_pop_buf_array(void* v, size_t sz, uint32_t count);
192
193/**
194 * Invoke the server. The destination endpoint may be automatically determined from the label for
195 * simplicity, unless overridden by a call to @ref rpc_set_dest.
196 * @return             0 on success, non-zero otherwise.
197 */
198int rpc_call_server();
199
200/**
201 * Finish up the current client RPC call and release all allocated objects.
202 */
203void rpc_release();
204
205/**
206 * Allocate a new cslot, and then copy out the given recieved capabiliy from the recieve cslot to a
207 * new cslot. This function exists to optionally separate @ref rpc_pop_cptr from allocating a new
208 * cslot. This function useful in the case where allocating a cslot itself requires an RPC call,
209 * as RPC calling from @ref rpc_pop_cptr may result in munging the IPC buffer. This function may need
210 * to temporarily copy the given cap to an empty slot, in order to IPC to allocate a new cslot.
211 * @param[in] v        CSpace pointer to capability to copy out.
212 * @return             CSpace pointer to copied out capability.
213 */
214ENDPT rpc_copyout_cptr(ENDPT v);
215
216// -------------------------------------------------------------------------------------------------
217// ------------------------------------------- Server RPC ------------------------------------------
218// -------------------------------------------------------------------------------------------------
219
220/**
221 * Helper structure which stores the basic state needed for an RPC server to manage a single RPC
222 * client. Note that the rpc_sv server interface here passes generic void* as client struct and
223 * does not assume you use this struct, so this struct is provided for convenience and using this
224 * struct is optional. The default implementation assumes the void *cl parameters to be
225 * a valid rpc_client_state_t* object;
226 *
227 * A good way to use this structure is to 'inherit' it by putting it as the first element of your
228 * own client structure. Then you may pointer case freely between your own client structure and a
229 * rpc_client_state_t.
230 */
231typedef struct rpc_client_state_s {
232    msginfo_t minfo;
233    void* obj[RPC_MAX_TRACKED_OBJS];
234    uint32_t num_obj;
235
236    bool skip_reply;
237    ENDPT reply;
238
239    void *userptr;
240} rpc_client_state_t;
241
242/**
243 * A simple buffer structure. Buffer array (pointer / length combinations in C) are converted to
244 * this on server side.
245 */
246typedef struct rpc_buffer_s {
247    void *data;
248    uint32_t count;
249} rpc_buffer_t;
250
251/**
252 * Initialise server's client state, ready for a new RPC call.
253 * @param[in] cl       Generic reference to caller client state structure.
254 */
255void rpc_sv_init(void *cl);
256
257/**
258 * Read next integer from recieved RPC packet.
259 * @param[in] cl       Generic reference to caller client state structure.
260 * @return             The next integer in packet.
261 */
262uint32_t rpc_sv_pop_uint(void *cl);
263
264/**
265 * Read next string from recieved RPC packet.
266 * @param[in] cl       Generic reference to caller client state structure.
267 * @return             The allocated and read string.
268 */
269char* rpc_sv_pop_str(void *cl);
270
271/**
272 * Read next buffer object from recieved RPC packet.
273 * @param[in] cl       Generic reference to caller client state structure.
274 * @param[out] v        Allocated buffer obj to read into.
275 * @param[in] sz       Size of buffer object in bytes.
276 */
277void rpc_sv_pop_buf(void *cl, void *v, size_t sz);
278
279/**
280 * Read next array of buffer objects from recieved RPC packet.
281 * @param[in] cl       Generic reference to caller client state structure.
282 * @param[in] sz       Size of a single buffer object in bytes.
283 * @return             The allocated and read buffer obj array.
284 */
285rpc_buffer_t rpc_sv_pop_buf_array(void *cl, size_t sz);
286
287/**
288 * Read next capability from recieved RPC packet. For an unwrapped capability, the unwrapped badge
289 * value is returned from this function. In the case of a transferred cap, it is _NOT_ copied out
290 * here (i.e. the value of recv_cslot in given @ref rpc_setup_recv is simply returned. It is up to
291 * the server handler to copy out given transferred caps. It is also up to the server handler to
292 * know (and check) which caps are unwrapped and which are transferred.
293 * @param[in] cl       Generic reference to caller client state structure.
294 * @return             The next capability.
295 */
296ENDPT rpc_sv_pop_cptr(void *cl);
297
298/**
299 * Add a new integer variable to the end of the current global RPC packet.
300 * @param[in] cl       Generic reference to caller client state structure.
301 * @param[in] v        String to add.
302 */
303void rpc_sv_push_uint(void *cl, uint32_t v);
304
305/**
306 * Add a new buffer object to the end of the current global RPC packet.
307 * @param[in] cl       Generic reference to caller client state structure.
308 * @param[in] v        Pointer to buffer object to add.
309 * @param[in] sz       size of the given buffer object in bytes.
310 */
311void rpc_sv_push_buf(void *cl, void* v, size_t sz);
312
313/**
314 * Add a capability to the end of the current global RPC packet.
315 * @param[in] cl       Generic reference to caller client state structure.
316 * @param[in] v        CPtr to capability to add and transfer.
317 */
318void rpc_sv_push_cptr(void *cl, ENDPT v);
319
320/**
321 * Add an array of objects to the end of the current global RPC packet.
322 * @param[in] cl       Generic reference to caller client state structure.
323 * @param[in] v        A value rpc_buffer_t containing pointer to buffer and count info.
324 * @param[in] sz       size of the a single object in bytes.
325 */
326void rpc_sv_push_buf_array(void *cl, rpc_buffer_t v, size_t sz);
327
328/**
329 * Reply to the client RPC. Depending on whether the reply is immediate or saved-first then replied
330 * later, this function should send to the correct corresponding reply endpoint in either case.
331 * @param[in] cl       Generic reference to caller client state structure.
332 */
333void rpc_sv_reply(void* cl);
334
335/**
336 * End the current RPC for the given client caller and release all tis allocated objects.
337 * @param[in] cl       Generic reference to caller client state structure.
338 */
339void rpc_sv_release(void *cl);
340
341/**
342 * Optionally save the current client RPC reply cap to reply later. A default weak definition is
343 * provided, and servers may want to override this. If this function returns True, the generated
344 * reply_*() functions are not called and must be invoked manually by the server. Useful
345 * for implementing server-side asynchronous syscalls which providing a synchronous syscall
346 * interface to clients. You may RPC from this function.
347 * @param[in] cl       Generic reference to caller client state structure.
348 * @return             False to reply immediately, True if the reply endpoint was saved.
349 */
350bool rpc_sv_save_reply(void *cl);
351
352/**
353 * Retrieve the saved reply endpoint if it has been saved, or 0 otherwise.
354 * @param[in] cl       Generic reference to caller client state structure.
355 * @return             saved reply endpoint if it was saved, 0 otherwise to reply immediately.
356 */
357ENDPT rpc_sv_get_reply_endpoint(void *cl);
358
359void rpc_sv_track_obj(void* cl, void* addr);
360
361void rpc_sv_free_tracked_objs(void* cl);
362
363bool rpc_sv_skip_reply(void *cl);
364
365#endif /* _REFOS_RPC_H_ */
366
367