Skip to content

Commit 99ea8a3

Browse files
committed
uVisor: Add RPC API header files
1 parent a5d2127 commit 99ea8a3

File tree

3 files changed

+347
-0
lines changed

3 files changed

+347
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef __UVISOR_API_RPC_H__
18+
#define __UVISOR_API_RPC_H__
19+
20+
#include "api/inc/uvisor_exports.h"
21+
#include <stdint.h>
22+
#include <stddef.h>
23+
24+
/** Specify the maximum number of incoming RPC messages for a box
25+
*
26+
* @param max_num_incoming_rpc The maximum number of incoming RPC messages for
27+
* a box
28+
*/
29+
/* FIXME This is a dummy implementation. */
30+
#define UVISOR_BOX_RPC_MAX_INCOMING(max_num_incoming_rpc)
31+
32+
/* This is the token to wait on for the result of an asynchronous RPC. */
33+
typedef uint32_t uvisor_rpc_result_t;
34+
35+
typedef uint32_t (*TFN_Ptr)(uint32_t, uint32_t, uint32_t, uint32_t);
36+
typedef int (*TFN_RPC_Callback)(int);
37+
38+
/** Wait for incoming RPC.
39+
*
40+
* @param fn_ptr_array an array of RPC function targets that this call to
41+
* `rpc_fncall_waitfor` should handle RPC to
42+
* @param fn_count the number of function targets in this array
43+
* @param timeout_ms specifies how long to wait (in ms) for an incoming RPC
44+
* message before returning
45+
*/
46+
int rpc_fncall_waitfor(const TFN_Ptr fn_ptr_array[], size_t fn_count, uint32_t timeout_ms);
47+
48+
#endif /* __UVISOR_API_RPC_H__ */
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* Copyright (c) 2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef __UVISOR_API_RPC_GATEWAY_H__
18+
#define __UVISOR_API_RPC_GATEWAY_H__
19+
20+
#include "api/inc/rpc_gateway_exports.h"
21+
#include "api/inc/rpc.h"
22+
#include "api/inc/uvisor_exports.h"
23+
#include <stdint.h>
24+
25+
/* ldr pc, [pc, #<label - instr + 4>]
26+
* LDR (immediate) - ARMv7M ARM section A7.7.42
27+
* 1111;1 00 0; 0 10 1; <Rn - 1111>; <Rt - 1111>; <imm12> (Encoding T3) */
28+
#define LDR_PC_PC_IMM_OPCODE(instr, label) \
29+
((uint32_t) (0xF000F8DFUL | ((((uint32_t) (label) - ((uint32_t) (instr) + 4)) & 0xFFFUL) << 16)))
30+
31+
/** Synchronous RPC Gateway
32+
*
33+
* This macro declares a new function pointer (with no name mangling) named
34+
* `gw_name` to perform a remote procedure call (RPC) to the target function
35+
* given by `fn_name`. RPCs are assembled into a read-only flash structure that
36+
* is read and validated by uVisor before performing the operation.
37+
*
38+
* Create function with following signature:
39+
* UVISOR_EXTERN fn_ret gw_name(uint32_t a, uint32_t b);
40+
*
41+
* @param box_name[in] The name of the source box as declared in
42+
* `UVISOR_BOX_CONFIG`
43+
* @param gw_name[in] The new, callable function pointer for performing RPC
44+
* @param fn_name[in] The function being designated as an RPC target
45+
* @param fn_ret[in] The return type of the function being designated as an
46+
* RPC target
47+
* @param __VA_ARGS__ The type of each parameter passed to the target
48+
* function. There can be up to 4 parameters in a target
49+
* function. Each parameter must be no more than uint32_t
50+
* in size. If the RPC target function accepts no
51+
* arguments, pass `void` here.
52+
*/
53+
#define UVISOR_BOX_RPC_GATEWAY_SYNC(box_name, gw_name, fn_name, fn_ret, ...) \
54+
UVISOR_STATIC_ASSERT(sizeof(fn_ret) <= sizeof(uint32_t), gw_name ## _return_type_too_big); \
55+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, __VA_ARGS__) \
56+
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, __VA_ARGS__) \
57+
/* Instanstiate the gateway. This gets resolved at link-time. */ \
58+
UVISOR_EXTERN TRPCGateway const gw_name ## _rpc_gateway = { \
59+
.ldr_pc = LDR_PC_PC_IMM_OPCODE(__UVISOR_OFFSETOF(TRPCGateway, ldr_pc), \
60+
__UVISOR_OFFSETOF(TRPCGateway, function)), \
61+
.magic = UVISOR_RPC_GATEWAY_MAGIC_SYNC, \
62+
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
63+
.function = (uint32_t) _sgw_sync_ ## fn_name, \
64+
}; \
65+
\
66+
/* Pointer to the gateway we just created. The pointer is located in a
67+
* discoverable linker section. */ \
68+
__attribute__((section(".keep.uvisor.rpc_gateway_ptr"))) \
69+
uint32_t const gw_name ## _rpc_gateway_ptr = (uint32_t) &gw_name ## _rpc_gateway; \
70+
\
71+
/* Declare the actual gateway. */ \
72+
UVISOR_EXTERN_C_BEGIN \
73+
fn_ret (*gw_name)(__VA_ARGS__) __attribute__((section(".rodata"))) = (fn_ret (*)(__VA_ARGS__)) ((uint32_t) &gw_name ## _rpc_gateway + 1); \
74+
UVISOR_EXTERN_C_END
75+
76+
/** Asynchronous RPC Gateway
77+
*
78+
* This macro declares a new function pointer (with no name mangling) named
79+
* `gw_name` to perform a remote procedure call (RPC) to the target function
80+
* given by `fn_name`. RPCs are assembled into a read-only flash structure that
81+
* is read and validated by uVisor before performing the operation.
82+
*
83+
* Create function with following signature:
84+
* UVISOR_EXTERN uvisor_rpc_result_t gw_name(uint32_t a, uint32_t b);
85+
*
86+
* @param box_name[in] The name of the source box as declared in
87+
* `UVISOR_BOX_CONFIG`
88+
* @param gw_name[in] The new, callable function pointer for performing RPC
89+
* @param fn_name[in] The function being designated as an RPC target
90+
* @param fn_ret[in] The return type of the function being designated as an
91+
* RPC target
92+
* @param __VA_ARGS__ The type of each parameter passed to the target
93+
* function. There can be up to 4 parameters in a target
94+
* function. Each parameter must be no more than uint32_t
95+
* in size. If the RPC target function accepts no
96+
* arguments, pass `void` here.
97+
*/
98+
#define UVISOR_BOX_RPC_GATEWAY_ASYNC(box_name, gw_name, fn_name, fn_ret, ...) \
99+
UVISOR_STATIC_ASSERT(sizeof(fn_ret) <= sizeof(uint32_t), gw_name ## _return_type_too_big); \
100+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, __VA_ARGS__) \
101+
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, __VA_ARGS__) \
102+
/* Instanstiate the gateway. This gets resolved at link-time. */ \
103+
UVISOR_EXTERN TRPCGateway const gw_name ## _rpc_gateway = { \
104+
.ldr_pc = LDR_PC_PC_IMM_OPCODE(__UVISOR_OFFSETOF(TRPCGateway, ldr_pc), \
105+
__UVISOR_OFFSETOF(TRPCGateway, function)), \
106+
.magic = UVISOR_RPC_GATEWAY_MAGIC_ASYNC, \
107+
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
108+
.function = (uint32_t) _sgw_async_ ## fn_name, \
109+
}; \
110+
\
111+
/* Pointer to the gateway we just created. The pointer is located in a
112+
* discoverable linker section. */ \
113+
__attribute__((section(".keep.uvisor.rpc_gateway_ptr"))) \
114+
uint32_t const gw_name ## _rpc_gateway_ptr = (uint32_t) &gw_name ## _rpc_gateway; \
115+
\
116+
/* Declare the actual gateway. */ \
117+
UVISOR_EXTERN_C_BEGIN \
118+
uvisor_rpc_result_t (*gw_name)(__VA_ARGS__) __attribute__((section(".rodata"))) = (uvisor_rpc_result_t (*)(__VA_ARGS__)) ((uint32_t) &gw_name ## _rpc_gateway + 1); \
119+
UVISOR_EXTERN_C_END
120+
121+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, ...) \
122+
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_4, \
123+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_3, \
124+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_2, \
125+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_1, \
126+
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_0)(gw_name, __VA_ARGS__)
127+
128+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_0(gw_name)
129+
130+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_1(gw_name, p0_type) \
131+
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big);
132+
133+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_2(gw_name, p0_type, p1_type) \
134+
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
135+
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big);
136+
137+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_3(gw_name, p0_type, p1_type, p2_type) \
138+
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
139+
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big); \
140+
UVISOR_STATIC_ASSERT(sizeof(p2_type) <= sizeof(uint32_t), gw_name ## _param_2_too_big);
141+
142+
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_4(gw_name, p0_type, p1_type, p2_type, p3_type) \
143+
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
144+
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big); \
145+
UVISOR_STATIC_ASSERT(sizeof(p2_type) <= sizeof(uint32_t), gw_name ## _param_2_too_big); \
146+
UVISOR_STATIC_ASSERT(sizeof(p3_type) <= sizeof(uint32_t), gw_name ## _param_3_too_big);
147+
148+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, ...) \
149+
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4, \
150+
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3, \
151+
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2, \
152+
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1, \
153+
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0)(fn_name, __VA_ARGS__)
154+
155+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0(fn_name, ...) \
156+
static uint32_t _sgw_sync_ ## fn_name(void) \
157+
{ \
158+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
159+
return rpc_fncall_sync(0, 0, 0, 0, fp); \
160+
}
161+
162+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1(fn_name, ...) \
163+
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0) \
164+
{ \
165+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
166+
return rpc_fncall_sync(p0, 0, 0, 0, fp); \
167+
}
168+
169+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2(fn_name, ...) \
170+
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1) \
171+
{ \
172+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
173+
return rpc_fncall_sync(p0, p1, 0, 0, fp); \
174+
}
175+
176+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3(fn_name, ...) \
177+
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2) \
178+
{ \
179+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
180+
return rpc_fncall_sync(p0, p1, p2, 0, fp); \
181+
}
182+
183+
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4(fn_name, ...) \
184+
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) \
185+
{ \
186+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
187+
return rpc_fncall_sync(p0, p1, p2, p3, fp); \
188+
}
189+
190+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, ...) \
191+
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4, \
192+
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3, \
193+
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2, \
194+
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1, \
195+
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0)(fn_name, __VA_ARGS__)
196+
197+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0(fn_name, ...) \
198+
static uvisor_rpc_result_t _sgw_async_ ## fn_name(void) \
199+
{ \
200+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
201+
return rpc_fncall_async(0, 0, 0, 0, fp); \
202+
}
203+
204+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1(fn_name, ...) \
205+
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0) \
206+
{ \
207+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
208+
return rpc_fncall_async(p0, 0, 0, 0, fp); \
209+
}
210+
211+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2(fn_name, ...) \
212+
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1) \
213+
{ \
214+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
215+
return rpc_fncall_async(p0, p1, 0, 0, fp); \
216+
}
217+
218+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3(fn_name, ...) \
219+
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2) \
220+
{ \
221+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
222+
return rpc_fncall_async(p0, p1, p2, 0, fp); \
223+
}
224+
225+
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4(fn_name, ...) \
226+
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) \
227+
{ \
228+
TFN_Ptr fp = (TFN_Ptr) fn_name; \
229+
return rpc_fncall_async(p0, p1, p2, p3, fp); \
230+
}
231+
232+
/* This function is private to uvisor-lib, but needs to be publicly visible for
233+
* the RPC gateway creation macros to work. */
234+
UVISOR_EXTERN uint32_t rpc_fncall_sync(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const TFN_Ptr fn);
235+
236+
/* This function is private to uvisor-lib, but needs to be publicly visible for
237+
* the RPC gateway creation macros to work. */
238+
UVISOR_EXTERN uvisor_rpc_result_t rpc_fncall_async(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const TFN_Ptr fn);
239+
240+
#endif /* __UVISOR_API_RPC_GATEWAY_H__ */
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef __UVISOR_API_RPC_GATEWAY_EXPORTS_H__
18+
#define __UVISOR_API_RPC_GATEWAY_EXPORTS_H__
19+
20+
#include "api/inc/uvisor_exports.h"
21+
#include <stdint.h>
22+
23+
/* udf imm16
24+
* UDF - ARMv7M ARM section A7.7.191
25+
* 111 1;0 111;1111; <imm4>; 1 01 0; <imm12> (Encoding T2)
26+
*/
27+
#define UDF_OPCODE(imm16) \
28+
((uint32_t) (0xA000F7F0UL | (((uint32_t) (imm16) & 0xFFFU) << 16U) | (((uint32_t) (imm16) & 0xF000UL) >> 12)))
29+
30+
/** RPC gateway magics
31+
*
32+
* The following magics are used to verify an RPC gateway structure. The magics are
33+
* chosen to be one of the explicitly undefined Thumb-2 instructions.
34+
*/
35+
/* TODO Unify all sources of magic (for register gateway, rpc gateway, and
36+
* everybody else) */
37+
#if defined(__thumb__) && defined(__thumb2__)
38+
#define UVISOR_RPC_GATEWAY_MAGIC_ASYNC UDF_OPCODE(0x07C2)
39+
#define UVISOR_RPC_GATEWAY_MAGIC_SYNC UDF_OPCODE(0x07C3)
40+
#else
41+
#error "Unsupported instruction set. The ARM Thumb-2 instruction set must be supported."
42+
#endif /* __thumb__ && __thumb2__ */
43+
44+
45+
/** RPC gateway structure
46+
*
47+
* This struct is packed because we must ensure that the `ldr_pc` field has no
48+
* padding before itself and will be located at a valid instruction location,
49+
* and that the `function` field is at a pre-determined offset from the
50+
* `ldr_pc` field.
51+
*/
52+
typedef struct {
53+
uint32_t ldr_pc;
54+
uint32_t magic;
55+
uint32_t box_ptr;
56+
uint32_t function; /* It's like a pretend literal pool. */
57+
} UVISOR_PACKED UVISOR_ALIGN(4) TRPCGateway;
58+
59+
#endif /* __UVISOR_API_RPC_GATEWAY_EXPORTS_H__ */

0 commit comments

Comments
 (0)