C Microkernel Realtime eXecutive
Realtime Operating System for Cortex-M based microcontrollers
 
Loading...
Searching...
No Matches
rpc.h
1
6#pragma once
7
8#include <arch/sysenter.h>
9#include <stddef.h>
10
11// Return 1 if type of x is pointer-to-something, 0 otherwise
12#define __is_pointer(x) (__builtin_classify_type(x) == 5)
13// Convert x to pointer to something if it is not already
14#define __make_pointer_to(x) __builtin_choose_expr(!__is_pointer(x), &(x), (x))
15// Dereference x if it is pointer. Do nothing if it is not.
16#define __strip_pointer_from(x) *(__make_pointer_to(x))
17
18/*
19 * Rearrange arguments to rpc_call syscall.
20 * We want to move RPC call arguments to occupy argument 1 .. 4 position.
21 * service and method goes next. The macro magic below deals with varying amount
22 * of arguments so that all calls to rpc_call() with less than 4 RPC arguments are
23 * padded to actual 4 arguments.
24 */
25
26#define CMRX_RPC_GET_ARG_COUNT_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
27#ifdef __clang__
28# define CMRX_RPC_GET_ARG_COUNT(...) CMRX_RPC_GET_ARG_COUNT_HELPER(10, ## __VA_ARGS__ , 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
29#else
30# define CMRX_RPC_GET_ARG_COUNT(...) CMRX_RPC_GET_ARG_COUNT_HELPER(__VA_ARGS__ __VA_OPT__(,) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
31#endif
32
33#define CMRX_RPC_PASTER(argcount) CMRX_RPC_CALL_ ## argcount
34#define CMRX_RPC_EVALUATOR(argcount) CMRX_RPC_PASTER(argcount)
35#define CMRX_RPC_CALL_4(si, mi, _0, _1, _2, _3) _rpc_call((unsigned long) _0, (unsigned long) _1, (unsigned long) _2, (unsigned long) _3, si, mi, 0xAA55AA55)
36#define CMRX_RPC_CALL_3(si, mi, _0, _1, _2) _rpc_call((unsigned long) _0, (unsigned long) _1, (unsigned long) _2, 0, si, mi, 0xAA55AA55)
37#define CMRX_RPC_CALL_2(si, mi, _0, _1) _rpc_call((unsigned long) _0, (unsigned long) _1, 0, 0, si, mi, 0xAA55AA55)
38#define CMRX_RPC_CALL_1(si, mi, _0) _rpc_call((unsigned long) _0, 0, 0, 0, (void *) si, mi, 0xAA55AA55)
39#define CMRX_RPC_CALL_0(si, mi) _rpc_call(0, 0, 0, 0, si, mi, 0xAA55AA55)
40
41/*
42 * Perform compile time type checking of the RPC call arguments.
43 * This will emit code which apparently calls the rpc method directly. This call
44 * is never made in the runtime (and is optimized out as dead code anyway) but it will
45 * emit a fairly readable error if types of arguments to the RPC call don't match.
46 */
47
48#if defined __clang__
49# define CMRX_RPC_TYPE_CHECKER(argcount, object, ...) if (0) { object((void *) 0 , ##__VA_ARGS__); }
50#else
51# define CMRX_RPC_TYPE_CHECKER(argcount, object, ...) if (0) { object((void *) 0 __VA_OPT__(,) __VA_ARGS__); }
52#endif
53
54#define CMRX_RPC_CHECK_TYPE_4(object, _0, _1, _2, _3) CMRX_RPC_CHECK_TYPE(object, (_0, _1, _2, _3))
55#define CMRX_RPC_CHECK_TYPE_3(object, _0, _1, _2) CMRX_RPC_CHECK_TYPE(object, (_0, _1, _2))
56#define CMRX_RPC_CHECK_TYPE_2(object, _0, _1) CMRX_RPC_CHECK_TYPE(object, (_0, _1))
57#define CMRX_RPC_CHECK_TYPE_1(object, _0) CMRX_RPC_CHECK_TYPE(object, (_0))
58#define CMRX_RPC_CHECK_TYPE_0(object, foo) CMRX_RPC_CHECK_TYPE(object, ())
59
60#define CMRX_RPC_CHECK_TYPE(object, args) if (0) { object ## args }
61
62/*
63 * Checker to make sure that the service instance is being called by pointer.
64 */
65
66#define CMRX_RPC_SERVICE_FORM_CHECKER_IMPL(object) "Service `" #object "` must be of a pointer to structure type!"
67#define CMRX_RPC_SERVICE_FORM_CHECKER_AUX(object) CMRX_RPC_SERVICE_FORM_CHECKER_IMPL(object)
68#define CMRX_RPC_SERVICE_FORM_CHECKER(object) _Static_assert(__builtin_classify_type(object) == 5, CMRX_RPC_SERVICE_FORM_CHECKER_AUX(object))
69
70/*
71 * Checker to make sure that the layout of type being used to perform calls is correct.
72 * The CMRX ABI requires, that the `vtable` member is the first member in the struct.
73 * Otherwise kernel won't be able to locate the virtual method table during rpc_call()
74 * execution.
75 */
76
77#define CMRX_RPC_INTERFACE_CHECKER_IMPL(service_instance) "Service `" #service_instance "` has invalid layout! VTable must be the first member!"
78#define CMRX_RPC_INTERFACE_CHECKER_AUX(service_instance) CMRX_RPC_INTERFACE_CHECKER_IMPL(service_instance)
79#define CMRX_RPC_INTERFACE_CHECKER(service_instance) _Static_assert(offsetof(typeof(*(service_instance)), vtable) == 0, CMRX_RPC_INTERFACE_CHECKER_AUX(service_instance))
80
81/*
82 * The master RPC call macro.
83 * This macro will emit several checks:
84 * - check that RPC service instance is a pointer to something.
85 * - check that va_args are actually compatible to what RPC method expects.
86 * - check the layout of RPC service (especially the position of the VTable)
87 * If all the checks will pass then RPC call is emitted. Note that all
88 * the checking is performed in the compile time.
89 */
90
91#define CMRX_RPC_CALL(service_instance, method_name, ...) \
92 CMRX_RPC_EVALUATOR(CMRX_RPC_GET_ARG_COUNT(__VA_ARGS__))(\
93 (service_instance), \
94 offsetof(typeof(*((service_instance)->vtable)), method_name) / sizeof(void *), \
95 ##__VA_ARGS__); \
96 CMRX_RPC_SERVICE_FORM_CHECKER(service_instance); \
97 CMRX_RPC_TYPE_CHECKER(CMRX_RPC_GET_ARG_COUNT(__VA_ARGS__), (service_instance)->vtable->method_name, ##__VA_ARGS__) \
98 CMRX_RPC_INTERFACE_CHECKER(service_instance); \
99
114#define interface_cast(type, service) _Generic(((service)->vtable), typeof((*((type*) 0))->vtable) : (type) service, default: service)
115
130#ifdef __clang__
131#define rpc_call(service_instance, method_name, ...) CMRX_RPC_CALL(service_instance, method_name, ##__VA_ARGS__)
132#else
133#define rpc_call(service_instance, method_name, ...) CMRX_RPC_CALL(service_instance, method_name __VA_OPT__(,) __VA_ARGS__)
134#endif
152__SYSCALL int _rpc_call(unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, void * service, unsigned method, unsigned canary);
153
160
__SYSCALL void rpc_return(void)
The way how RPC returns.
int _rpc_call(void)
#define __SYSCALL
Mark function as syscall entrypoint in userspace.
Definition sysenter.h:14