Skip to content

Commit 09add3e

Browse files
committed
fastrpc: libhexagonrpc: add interpretation three of method call format
The method call format as interpreted last time had some limitations. First, input words could not appear after the input buffers, making it impossible to represent the apps_std_mkdir method accurately. Second, it was assumed that the lengths in the primary input buffer represent the number of bytes. In reality, the lengths represent the number of elements, which just happened to be octets in the majority of remote methods found, and the adsp_perf_get_usecs remote method could not be represented. Update the format for the third time to remove these limitations. This format allows the mixing of words and lengths of other buffers in the primary buffer by using 0 to denote words in an array of arguments. It also allows a greater size of elements, denoted by any non-zero value.
1 parent 2415d5f commit 09add3e

File tree

4 files changed

+279
-0
lines changed

4 files changed

+279
-0
lines changed

include/libhexagonrpc/fastrpc.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define FASTRPC_H
2424

2525
#include <stdarg.h>
26+
#include <stdbool.h>
2627
#include <stdint.h>
2728
#include <stdlib.h>
2829

@@ -41,6 +42,8 @@
4142
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0xff)
4243
#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0xff)
4344

45+
#define HEXAGONRPC_DELIMITER 0xFFFFFFFF
46+
4447
struct fastrpc_context {
4548
int fd;
4649
uint32_t handle;
@@ -54,6 +57,13 @@ struct fastrpc_function_def_interp2 {
5457
uint8_t out_bufs;
5558
};
5659

60+
struct hrpc_method_def_interp3 {
61+
uint32_t msg_id;
62+
bool has_prim_out;
63+
size_t n_args;
64+
const uint32_t *args;
65+
};
66+
5767
struct fastrpc_context *fastrpc_create_context(int fd, uint32_t handle);
5868

5969
static inline void fastrpc_destroy_context(struct fastrpc_context *ctx)
@@ -70,4 +80,14 @@ int fastrpc2(const struct fastrpc_function_def_interp2 *def,
7080
int fastrpc(const struct fastrpc_function_def_interp2 *def,
7181
const struct fastrpc_context *ctx, ...);
7282

83+
int vhexagonrpc2(const struct hrpc_method_def_interp3 *def,
84+
int fd, uint32_t handle, va_list list);
85+
int vhexagonrpc(const struct hrpc_method_def_interp3 *def,
86+
const struct fastrpc_context *ctx, va_list list);
87+
int hexagonrpc2(const struct hrpc_method_def_interp3 *def,
88+
int fd, uint32_t handle, ...);
89+
int hexagonrpc(const struct hrpc_method_def_interp3 *def,
90+
const struct fastrpc_context *ctx, ...);
91+
92+
7393
#endif

include/libhexagonrpc/interface.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
outnums, outbufs) \
3737
extern const struct fastrpc_function_def_interp2 name##_def;
3838

39+
#define HEXAGONRPC_DEFINE_REMOTE_METHOD3_EMPTY(mid, name) \
40+
extern const struct hrpc_method_def_interp3 name##_def;
41+
42+
#define HEXAGONRPC_DEFINE_REMOTE_METHOD3(mid, name, has_oprim, ...) \
43+
HEXAGONRPC_DEFINE_REMOTE_METHOD3_EMPTY(mid, name)
44+
3945
#else /* HEXAGONRPC_BUILD_METHOD_DEFINITIONS */
4046

4147
#define HEXAGONRPC_DEFINE_REMOTE_METHOD(mid, name, \
@@ -49,6 +55,23 @@
4955
.out_bufs = outbufs, \
5056
};
5157

58+
#define HEXAGONRPC_DEFINE_REMOTE_METHOD3_EMPTY(mid, name) \
59+
const struct hrpc_method_def_interp3 name##_def = { \
60+
.msg_id = mid, \
61+
.has_prim_out = false, \
62+
.n_args = 0, \
63+
.args = NULL, \
64+
};
65+
66+
#define HEXAGONRPC_DEFINE_REMOTE_METHOD3(mid, name, has_oprim, ...) \
67+
static const uint32_t name##_args[] = { __VA_ARGS__ }; \
68+
const struct hrpc_method_def_interp3 name##_def = { \
69+
.msg_id = mid, \
70+
.has_prim_out = has_oprim, \
71+
.n_args = sizeof(name##_args) / sizeof(*name##_args), \
72+
.args = name##_args, \
73+
};
74+
5275
#endif /* HEXAGONRPC_BUILD_METHOD_DEFINITIONS */
5376

5477
#endif /* LIBHEXAGONRPC_INTERFACE_H */

libhexagonrpc/context.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,21 @@ int fastrpc(const struct fastrpc_function_def_interp2 *def,
5454
return ret;
5555
}
5656

57+
int vhexagonrpc(const struct hrpc_method_def_interp3 *def,
58+
const struct fastrpc_context *ctx, va_list arg_list)
59+
{
60+
return vhexagonrpc2(def, ctx->fd, ctx->handle, arg_list);
61+
}
62+
63+
int hexagonrpc(const struct hrpc_method_def_interp3 *def,
64+
const struct fastrpc_context *ctx, ...)
65+
{
66+
va_list arg_list;
67+
int ret;
68+
69+
va_start(arg_list, ctx);
70+
ret = vhexagonrpc(def, ctx, arg_list);
71+
va_end(arg_list);
72+
73+
return ret;
74+
}

libhexagonrpc/fastrpc.c

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,221 @@ int fastrpc2(const struct fastrpc_function_def_interp2 *def,
250250

251251
return ret;
252252
}
253+
254+
/*
255+
* This populates relevant arguments with information necessary to receive
256+
* output from the remote processor.
257+
*
258+
* First, it allocates a new first output buffer to contain the returned 32-bit
259+
* integers. This output buffer must be freed after use.
260+
*
261+
* With a peek at the output arguments, it populates the fastrpc_invoke_args
262+
* struct to give information about the provided buffers to the kernel, and
263+
* adds an entry to the first input buffer to tell the remote processor the
264+
* size of the function-level output buffer.
265+
*/
266+
static void prepare_outbufs3(const struct hrpc_method_def_interp3 *def,
267+
struct fastrpc_invoke_args *args,
268+
size_t delim,
269+
uint32_t *n_prim_in, uint8_t *n_outbufs,
270+
uint32_t *prim,
271+
va_list peek)
272+
{
273+
uint32_t n_prim_out = 0;
274+
size_t i;
275+
276+
if (def->has_prim_out)
277+
*n_outbufs = 1;
278+
else
279+
*n_outbufs = 0;
280+
281+
for (i = delim; i < def->n_args; i++) {
282+
if (def->args[i]) {
283+
prim[*n_prim_in] = va_arg(peek, uint32_t);
284+
285+
args[*n_outbufs].length = prim[*n_prim_in] * def->args[i];
286+
args[*n_outbufs].ptr = (__u64) va_arg(peek, void *);
287+
args[*n_outbufs].fd = -1;
288+
289+
(*n_prim_in)++;
290+
(*n_outbufs)++;
291+
} else {
292+
va_arg(peek, uint32_t *);
293+
n_prim_out++;
294+
}
295+
}
296+
297+
if (def->has_prim_out) {
298+
args[0].length = sizeof(uint32_t) * n_prim_out;
299+
args[0].ptr = (__u64) &prim[*n_prim_in];
300+
args[0].fd = -1;
301+
}
302+
}
303+
304+
static void return_prim_out(const struct hrpc_method_def_interp3 *def,
305+
size_t delim,
306+
const uint32_t *prim_out,
307+
va_list list)
308+
{
309+
uint32_t *ptr;
310+
size_t i, j = 0;
311+
312+
for (i = delim; i < def->n_args; i++) {
313+
if (def->args[i]) {
314+
va_arg(list, uint32_t);
315+
va_arg(list, void *);
316+
} else {
317+
ptr = va_arg(list, uint32_t *);
318+
*ptr = prim_out[j];
319+
j++;
320+
}
321+
}
322+
}
323+
324+
/*
325+
* This is the main function to invoke a FastRPC procedure call. The first
326+
* parameter specifies how to populate the ioctl-level buffers. The second and
327+
* third parameters specify where to send the invocation to. The fourth is the
328+
* list of arguments that the procedure call should interact with.
329+
*
330+
* A good example for this would be the adsp_listener_next2 call:
331+
*
332+
* static inline void adsp_listener_next2(int fd, uint32_t handle,
333+
* uint32_t prev_ctx,
334+
* uint32_t prev_result,
335+
* uint32_t nested_outbufs_len,
336+
* void *nested_outbufs,
337+
* uint32_t *ctx,
338+
* uint32_t *nested_handle,
339+
* uint32_t *nested_sc,
340+
* uint32_t *nested_inbufs_len,
341+
* uint32_t nested_inbufs_size,
342+
* void *nested_inbufs)
343+
* {
344+
* uint32_t args[] = { 0, 0, 1, HEXAGONRPC_DELIMITER, 0, 0, 0, 1 };
345+
* struct hrpc_method_def_interp3 def = {
346+
* .mid = 4,
347+
* .has_out_prim = true,
348+
* .n_args = 8,
349+
* .args = args,
350+
* };
351+
* return vhexagonrpc2(def, fd, handle,
352+
* prev_ctx,
353+
* prev_result,
354+
* nested_outbufs_len,
355+
* nested_outbufs,
356+
* ctx,
357+
* nested_handle,
358+
* nested_sc,
359+
* nested_inbufs_len,
360+
* nested_inbufs_size,
361+
* nested_inbufs);
362+
* }
363+
*/
364+
int vhexagonrpc2(const struct hrpc_method_def_interp3 *def,
365+
int fd, uint32_t handle, va_list list)
366+
{
367+
va_list peek;
368+
struct fastrpc_invoke invoke;
369+
struct fastrpc_invoke_args *args;
370+
uint32_t *prim;
371+
uint32_t n_prim_in = 0;
372+
uint32_t msg_id;
373+
uint8_t n_inbufs = 1, n_outbufs;
374+
size_t i;
375+
int ret = -1;
376+
377+
/*
378+
* If there are only input buffers specified in the method definition,
379+
* we need an extra primary input argument for their sizes.
380+
*/
381+
args = malloc(sizeof(struct fastrpc_invoke_args) * (def->n_args + 1));
382+
if (args == NULL)
383+
return -1;
384+
385+
/*
386+
* The input and output buffers need a size in the primary input buffer
387+
* so all arguments except the optional delimiter contribute to the
388+
* primary buffers.
389+
*/
390+
prim = malloc(sizeof(uint32_t) * (def->n_args + 1));
391+
if (prim == NULL)
392+
goto err_free_args;
393+
394+
/*
395+
* The apps_std interface demonstrates that there is support
396+
* for more than 32 methods for a single interface. Support
397+
* extended method IDs that go beyond 5 bits and the ID
398+
* reserved for this purpose.
399+
*/
400+
if (def->msg_id >= 31) {
401+
prim[n_prim_in] = def->msg_id;
402+
n_prim_in++;
403+
msg_id = 31;
404+
} else {
405+
msg_id = def->msg_id;
406+
}
407+
408+
for (i = 0; i < def->n_args; i++) {
409+
if (def->args[i] == HEXAGONRPC_DELIMITER) {
410+
i++;
411+
break;
412+
}
413+
414+
prim[n_prim_in] = va_arg(list, uint32_t);
415+
416+
if (def->args[i]) {
417+
args[n_inbufs].length = prim[n_prim_in] * def->args[i];
418+
args[n_inbufs].ptr = (__u64) va_arg(list, const void *);
419+
args[n_inbufs].fd = -1;
420+
n_inbufs++;
421+
}
422+
423+
n_prim_in++;
424+
}
425+
426+
va_copy(peek, list);
427+
prepare_outbufs3(def, &args[n_inbufs], i, &n_prim_in, &n_outbufs, prim, peek);
428+
va_end(peek);
429+
430+
args[0].length = sizeof(uint32_t) * n_prim_in;
431+
args[0].ptr = (__u64) prim;
432+
args[0].fd = -1;
433+
434+
// Pass the primary input buffer if not empty, otherwise skip it.
435+
if (n_prim_in != 0) {
436+
invoke.args = (__u64) args;
437+
} else {
438+
invoke.args = (__u64) &args[1];
439+
n_inbufs--;
440+
}
441+
442+
invoke.handle = handle;
443+
invoke.sc = REMOTE_SCALARS_MAKE(msg_id, n_inbufs, n_outbufs);
444+
445+
ret = ioctl(fd, FASTRPC_IOCTL_INVOKE, (__u64) &invoke);
446+
if (ret == -1)
447+
goto err_free_prim;
448+
449+
return_prim_out(def, i, &prim[n_prim_in], list);
450+
451+
err_free_prim:
452+
free(prim);
453+
err_free_args:
454+
free(args);
455+
456+
return ret;
457+
}
458+
459+
int hexagonrpc2(const struct hrpc_method_def_interp3 *def,
460+
int fd, uint32_t handle, ...)
461+
{
462+
va_list list;
463+
int ret;
464+
465+
va_start(list, handle);
466+
ret = vhexagonrpc2(def, fd, handle, list);
467+
va_end(list);
468+
469+
return ret;
470+
}

0 commit comments

Comments
 (0)