mirror of https://github.com/ARMmbed/mbed-os.git
uVisor: Add RPC API header files
parent
a5d2127e0c
commit
99ea8a3649
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef __UVISOR_API_RPC_H__
|
||||
#define __UVISOR_API_RPC_H__
|
||||
|
||||
#include "api/inc/uvisor_exports.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Specify the maximum number of incoming RPC messages for a box
|
||||
*
|
||||
* @param max_num_incoming_rpc The maximum number of incoming RPC messages for
|
||||
* a box
|
||||
*/
|
||||
/* FIXME This is a dummy implementation. */
|
||||
#define UVISOR_BOX_RPC_MAX_INCOMING(max_num_incoming_rpc)
|
||||
|
||||
/* This is the token to wait on for the result of an asynchronous RPC. */
|
||||
typedef uint32_t uvisor_rpc_result_t;
|
||||
|
||||
typedef uint32_t (*TFN_Ptr)(uint32_t, uint32_t, uint32_t, uint32_t);
|
||||
typedef int (*TFN_RPC_Callback)(int);
|
||||
|
||||
/** Wait for incoming RPC.
|
||||
*
|
||||
* @param fn_ptr_array an array of RPC function targets that this call to
|
||||
* `rpc_fncall_waitfor` should handle RPC to
|
||||
* @param fn_count the number of function targets in this array
|
||||
* @param timeout_ms specifies how long to wait (in ms) for an incoming RPC
|
||||
* message before returning
|
||||
*/
|
||||
int rpc_fncall_waitfor(const TFN_Ptr fn_ptr_array[], size_t fn_count, uint32_t timeout_ms);
|
||||
|
||||
#endif /* __UVISOR_API_RPC_H__ */
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright (c) 2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef __UVISOR_API_RPC_GATEWAY_H__
|
||||
#define __UVISOR_API_RPC_GATEWAY_H__
|
||||
|
||||
#include "api/inc/rpc_gateway_exports.h"
|
||||
#include "api/inc/rpc.h"
|
||||
#include "api/inc/uvisor_exports.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* ldr pc, [pc, #<label - instr + 4>]
|
||||
* LDR (immediate) - ARMv7M ARM section A7.7.42
|
||||
* 1111;1 00 0; 0 10 1; <Rn - 1111>; <Rt - 1111>; <imm12> (Encoding T3) */
|
||||
#define LDR_PC_PC_IMM_OPCODE(instr, label) \
|
||||
((uint32_t) (0xF000F8DFUL | ((((uint32_t) (label) - ((uint32_t) (instr) + 4)) & 0xFFFUL) << 16)))
|
||||
|
||||
/** Synchronous RPC Gateway
|
||||
*
|
||||
* This macro declares a new function pointer (with no name mangling) named
|
||||
* `gw_name` to perform a remote procedure call (RPC) to the target function
|
||||
* given by `fn_name`. RPCs are assembled into a read-only flash structure that
|
||||
* is read and validated by uVisor before performing the operation.
|
||||
*
|
||||
* Create function with following signature:
|
||||
* UVISOR_EXTERN fn_ret gw_name(uint32_t a, uint32_t b);
|
||||
*
|
||||
* @param box_name[in] The name of the source box as declared in
|
||||
* `UVISOR_BOX_CONFIG`
|
||||
* @param gw_name[in] The new, callable function pointer for performing RPC
|
||||
* @param fn_name[in] The function being designated as an RPC target
|
||||
* @param fn_ret[in] The return type of the function being designated as an
|
||||
* RPC target
|
||||
* @param __VA_ARGS__ The type of each parameter passed to the target
|
||||
* function. There can be up to 4 parameters in a target
|
||||
* function. Each parameter must be no more than uint32_t
|
||||
* in size. If the RPC target function accepts no
|
||||
* arguments, pass `void` here.
|
||||
*/
|
||||
#define UVISOR_BOX_RPC_GATEWAY_SYNC(box_name, gw_name, fn_name, fn_ret, ...) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(fn_ret) <= sizeof(uint32_t), gw_name ## _return_type_too_big); \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, __VA_ARGS__) \
|
||||
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, __VA_ARGS__) \
|
||||
/* Instanstiate the gateway. This gets resolved at link-time. */ \
|
||||
UVISOR_EXTERN TRPCGateway const gw_name ## _rpc_gateway = { \
|
||||
.ldr_pc = LDR_PC_PC_IMM_OPCODE(__UVISOR_OFFSETOF(TRPCGateway, ldr_pc), \
|
||||
__UVISOR_OFFSETOF(TRPCGateway, function)), \
|
||||
.magic = UVISOR_RPC_GATEWAY_MAGIC_SYNC, \
|
||||
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
|
||||
.function = (uint32_t) _sgw_sync_ ## fn_name, \
|
||||
}; \
|
||||
\
|
||||
/* Pointer to the gateway we just created. The pointer is located in a
|
||||
* discoverable linker section. */ \
|
||||
__attribute__((section(".keep.uvisor.rpc_gateway_ptr"))) \
|
||||
uint32_t const gw_name ## _rpc_gateway_ptr = (uint32_t) &gw_name ## _rpc_gateway; \
|
||||
\
|
||||
/* Declare the actual gateway. */ \
|
||||
UVISOR_EXTERN_C_BEGIN \
|
||||
fn_ret (*gw_name)(__VA_ARGS__) __attribute__((section(".rodata"))) = (fn_ret (*)(__VA_ARGS__)) ((uint32_t) &gw_name ## _rpc_gateway + 1); \
|
||||
UVISOR_EXTERN_C_END
|
||||
|
||||
/** Asynchronous RPC Gateway
|
||||
*
|
||||
* This macro declares a new function pointer (with no name mangling) named
|
||||
* `gw_name` to perform a remote procedure call (RPC) to the target function
|
||||
* given by `fn_name`. RPCs are assembled into a read-only flash structure that
|
||||
* is read and validated by uVisor before performing the operation.
|
||||
*
|
||||
* Create function with following signature:
|
||||
* UVISOR_EXTERN uvisor_rpc_result_t gw_name(uint32_t a, uint32_t b);
|
||||
*
|
||||
* @param box_name[in] The name of the source box as declared in
|
||||
* `UVISOR_BOX_CONFIG`
|
||||
* @param gw_name[in] The new, callable function pointer for performing RPC
|
||||
* @param fn_name[in] The function being designated as an RPC target
|
||||
* @param fn_ret[in] The return type of the function being designated as an
|
||||
* RPC target
|
||||
* @param __VA_ARGS__ The type of each parameter passed to the target
|
||||
* function. There can be up to 4 parameters in a target
|
||||
* function. Each parameter must be no more than uint32_t
|
||||
* in size. If the RPC target function accepts no
|
||||
* arguments, pass `void` here.
|
||||
*/
|
||||
#define UVISOR_BOX_RPC_GATEWAY_ASYNC(box_name, gw_name, fn_name, fn_ret, ...) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(fn_ret) <= sizeof(uint32_t), gw_name ## _return_type_too_big); \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, __VA_ARGS__) \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, __VA_ARGS__) \
|
||||
/* Instanstiate the gateway. This gets resolved at link-time. */ \
|
||||
UVISOR_EXTERN TRPCGateway const gw_name ## _rpc_gateway = { \
|
||||
.ldr_pc = LDR_PC_PC_IMM_OPCODE(__UVISOR_OFFSETOF(TRPCGateway, ldr_pc), \
|
||||
__UVISOR_OFFSETOF(TRPCGateway, function)), \
|
||||
.magic = UVISOR_RPC_GATEWAY_MAGIC_ASYNC, \
|
||||
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
|
||||
.function = (uint32_t) _sgw_async_ ## fn_name, \
|
||||
}; \
|
||||
\
|
||||
/* Pointer to the gateway we just created. The pointer is located in a
|
||||
* discoverable linker section. */ \
|
||||
__attribute__((section(".keep.uvisor.rpc_gateway_ptr"))) \
|
||||
uint32_t const gw_name ## _rpc_gateway_ptr = (uint32_t) &gw_name ## _rpc_gateway; \
|
||||
\
|
||||
/* Declare the actual gateway. */ \
|
||||
UVISOR_EXTERN_C_BEGIN \
|
||||
uvisor_rpc_result_t (*gw_name)(__VA_ARGS__) __attribute__((section(".rodata"))) = (uvisor_rpc_result_t (*)(__VA_ARGS__)) ((uint32_t) &gw_name ## _rpc_gateway + 1); \
|
||||
UVISOR_EXTERN_C_END
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK(gw_name, ...) \
|
||||
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_4, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_3, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_2, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_1, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_0)(gw_name, __VA_ARGS__)
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_0(gw_name)
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_1(gw_name, p0_type) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big);
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_2(gw_name, p0_type, p1_type) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big);
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_3(gw_name, p0_type, p1_type, p2_type) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p2_type) <= sizeof(uint32_t), gw_name ## _param_2_too_big);
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ARG_CHECK_4(gw_name, p0_type, p1_type, p2_type, p3_type) \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p0_type) <= sizeof(uint32_t), gw_name ## _param_0_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p1_type) <= sizeof(uint32_t), gw_name ## _param_1_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p2_type) <= sizeof(uint32_t), gw_name ## _param_2_too_big); \
|
||||
UVISOR_STATIC_ASSERT(sizeof(p3_type) <= sizeof(uint32_t), gw_name ## _param_3_too_big);
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, ...) \
|
||||
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0)(fn_name, __VA_ARGS__)
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0(fn_name, ...) \
|
||||
static uint32_t _sgw_sync_ ## fn_name(void) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_sync(0, 0, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1(fn_name, ...) \
|
||||
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_sync(p0, 0, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2(fn_name, ...) \
|
||||
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_sync(p0, p1, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3(fn_name, ...) \
|
||||
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_sync(p0, p1, p2, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4(fn_name, ...) \
|
||||
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_sync(p0, p1, p2, p3, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, ...) \
|
||||
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1, \
|
||||
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0)(fn_name, __VA_ARGS__)
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0(fn_name, ...) \
|
||||
static uvisor_rpc_result_t _sgw_async_ ## fn_name(void) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_async(0, 0, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1(fn_name, ...) \
|
||||
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_async(p0, 0, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2(fn_name, ...) \
|
||||
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_async(p0, p1, 0, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3(fn_name, ...) \
|
||||
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_async(p0, p1, p2, 0, fp); \
|
||||
}
|
||||
|
||||
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4(fn_name, ...) \
|
||||
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) \
|
||||
{ \
|
||||
TFN_Ptr fp = (TFN_Ptr) fn_name; \
|
||||
return rpc_fncall_async(p0, p1, p2, p3, fp); \
|
||||
}
|
||||
|
||||
/* This function is private to uvisor-lib, but needs to be publicly visible for
|
||||
* the RPC gateway creation macros to work. */
|
||||
UVISOR_EXTERN uint32_t rpc_fncall_sync(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const TFN_Ptr fn);
|
||||
|
||||
/* This function is private to uvisor-lib, but needs to be publicly visible for
|
||||
* the RPC gateway creation macros to work. */
|
||||
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);
|
||||
|
||||
#endif /* __UVISOR_API_RPC_GATEWAY_H__ */
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef __UVISOR_API_RPC_GATEWAY_EXPORTS_H__
|
||||
#define __UVISOR_API_RPC_GATEWAY_EXPORTS_H__
|
||||
|
||||
#include "api/inc/uvisor_exports.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* udf imm16
|
||||
* UDF - ARMv7M ARM section A7.7.191
|
||||
* 111 1;0 111;1111; <imm4>; 1 01 0; <imm12> (Encoding T2)
|
||||
*/
|
||||
#define UDF_OPCODE(imm16) \
|
||||
((uint32_t) (0xA000F7F0UL | (((uint32_t) (imm16) & 0xFFFU) << 16U) | (((uint32_t) (imm16) & 0xF000UL) >> 12)))
|
||||
|
||||
/** RPC gateway magics
|
||||
*
|
||||
* The following magics are used to verify an RPC gateway structure. The magics are
|
||||
* chosen to be one of the explicitly undefined Thumb-2 instructions.
|
||||
*/
|
||||
/* TODO Unify all sources of magic (for register gateway, rpc gateway, and
|
||||
* everybody else) */
|
||||
#if defined(__thumb__) && defined(__thumb2__)
|
||||
#define UVISOR_RPC_GATEWAY_MAGIC_ASYNC UDF_OPCODE(0x07C2)
|
||||
#define UVISOR_RPC_GATEWAY_MAGIC_SYNC UDF_OPCODE(0x07C3)
|
||||
#else
|
||||
#error "Unsupported instruction set. The ARM Thumb-2 instruction set must be supported."
|
||||
#endif /* __thumb__ && __thumb2__ */
|
||||
|
||||
|
||||
/** RPC gateway structure
|
||||
*
|
||||
* This struct is packed because we must ensure that the `ldr_pc` field has no
|
||||
* padding before itself and will be located at a valid instruction location,
|
||||
* and that the `function` field is at a pre-determined offset from the
|
||||
* `ldr_pc` field.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t ldr_pc;
|
||||
uint32_t magic;
|
||||
uint32_t box_ptr;
|
||||
uint32_t function; /* It's like a pretend literal pool. */
|
||||
} UVISOR_PACKED UVISOR_ALIGN(4) TRPCGateway;
|
||||
|
||||
#endif /* __UVISOR_API_RPC_GATEWAY_EXPORTS_H__ */
|
||||
Loading…
Reference in New Issue