Merge pull request #2774 from AlessandroA/uvisor_rpc

uVisor: Update to v0.25.0
pull/2787/merge
Martin Kojtal 2016-09-23 09:48:07 +01:00 committed by GitHub
commit e4dde3460f
41 changed files with 963 additions and 132 deletions

View File

@ -1,7 +1,7 @@
567 Milosch Meriac
470 Alessandro Angelino
49 Jaeden Amero
42 Niklas Hauser
568 Milosch Meriac
477 Alessandro Angelino
72 Jaeden Amero
53 Niklas Hauser
3 Hugo Vincent
3 JaredCJR
3 Jim Huang

View File

@ -1 +1 @@
v0.24.1
v0.25.0

View File

@ -81,7 +81,7 @@ rsync:
# Copying licenses
cp $(UVISOR_DIR)/LICENSE* $(TARGET_SUPPORTED)
TARGET_M%: $(TARGET_SUPPORTED)/*/*/*_m%_*.a
TARGET_M%: $(TARGET_SUPPORTED)/*/*/*_cortex_m%*.a
@printf "#\n# Copying $@ files...\n"
mkdir $(foreach file,$^,$(dir $(file))$@)
$(foreach file,$^,mv $(file) $(dir $(file))$@/lib$(notdir $(file));)

View File

@ -19,6 +19,7 @@
#include "api/inc/uvisor_exports.h"
#include "api/inc/page_allocator_exports.h"
#include "api/inc/rpc_exports.h"
#include <stddef.h>
#include <stdint.h>
@ -43,10 +44,15 @@ UVISOR_EXTERN const uint32_t __uvisor_mode;
UVISOR_BOX_MAGIC, \
UVISOR_BOX_VERSION, \
0, \
0, \
sizeof(RtxBoxIndex), \
{ \
0, \
0, \
0, \
sizeof(uvisor_rpc_outgoing_message_queue_t), \
sizeof(uvisor_rpc_incoming_message_queue_t), \
sizeof(uvisor_rpc_fn_group_queue_t), \
}, \
NULL, \
NULL, \
acl_list, \
acl_list_count \
@ -74,7 +80,10 @@ UVISOR_EXTERN const uint32_t __uvisor_mode;
(UVISOR_MIN_STACK(stack_size) + \
(context_size) + \
(__uvisor_box_heapsize) + \
sizeof(RtxBoxIndex) \
sizeof(RtxBoxIndex) + \
sizeof(uvisor_rpc_outgoing_message_queue_t) + \
sizeof(uvisor_rpc_incoming_message_queue_t) + \
sizeof(uvisor_rpc_fn_group_queue_t) \
) \
* 8) \
/ 6)]; \
@ -83,9 +92,14 @@ UVISOR_EXTERN const uint32_t __uvisor_mode;
UVISOR_BOX_MAGIC, \
UVISOR_BOX_VERSION, \
UVISOR_MIN_STACK(stack_size), \
sizeof(RtxBoxIndex), \
context_size, \
__uvisor_box_heapsize, \
sizeof(RtxBoxIndex), \
{ \
context_size, \
sizeof(uvisor_rpc_outgoing_message_queue_t), \
sizeof(uvisor_rpc_incoming_message_queue_t), \
sizeof(uvisor_rpc_fn_group_queue_t), \
}, \
__uvisor_box_lib_config, \
__uvisor_box_namespace, \
acl_list, \
@ -139,13 +153,6 @@ UVISOR_EXTERN const uint32_t __uvisor_mode;
#define uvisor_ctx (*__uvisor_ps)
/* Return the numeric box ID of the current box. */
UVISOR_EXTERN int uvisor_box_id_self(void);
/* Return the numeric box ID of the box that is calling through the most recent
* secure gateway. Return -1 if there is no secure gateway calling box. */
UVISOR_EXTERN int uvisor_box_id_caller(void);
/* Copy the box namespace of the specified box ID to the memory provided by
* box_namespace. The box_namespace's length must be at least
* MAX_BOX_NAMESPACE_LENGTH bytes. Return how many bytes were copied into

View File

@ -0,0 +1,29 @@
/*
* 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_BOX_ID_H__
#define __UVISOR_API_BOX_ID_H__
#include "api/inc/uvisor_exports.h"
/* Return the numeric box ID of the current box. */
UVISOR_EXTERN int uvisor_box_id_self(void);
/* Return the numeric box ID of the box that is calling through the most recent
* secure gateway. Return -1 if there is no secure gateway calling box. */
UVISOR_EXTERN int uvisor_box_id_caller(void) UVISOR_DEPRECATED;
#endif /* __UVISOR_API_BOX_ID_H__ */

View File

@ -0,0 +1,24 @@
/*
* 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_BOX_INIT_H__
#define __UVISOR_API_BOX_INIT_H__
#include "api/inc/uvisor-lib.h"
UVISOR_EXTERN void __uvisor_lib_box_init(void * lib_config);
#endif

View File

@ -18,6 +18,7 @@
#define __UVISOR_API_NVIC_VIRTUAL_H__
#include "api/inc/interrupts.h"
#include "api/inc/unvic_exports.h"
#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping
#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping
@ -29,5 +30,6 @@
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority vIRQ_SetPriority
#define NVIC_GetPriority vIRQ_GetPriority
#define NVIC_SystemReset() vIRQ_SystemReset(RESET_REASON_NO_REASON)
#endif /* __UVISOR_API_NVIC_VIRTUAL_H__ */

View File

@ -18,6 +18,7 @@
#define __UVISOR_API_EXPORT_TABLE_EXPORTS_H__
#include "rt_OsEventObserver.h"
#include "api/inc/pool_queue_exports.h"
#include <stdint.h>
/* If this magic doesn't match what you get in a TUvisorExportTable, then you
@ -39,9 +40,21 @@ typedef struct {
OsEventObserver os_event_observer;
UvisorPoolTable pool;
/* This must be the last element of the table so that uvisor-input.S can
* export the size statically. */
uint32_t size;
} TUvisorExportTable;
static inline TUvisorExportTable const * uvisor_export_table(void)
{
/* Defined in uvisor-input.S */
extern uint32_t uvisor_config;
extern uint32_t uvisor_export_table_size;
uintptr_t uvisor_config_addr = (uintptr_t) &uvisor_config;
return (TUvisorExportTable *) (uvisor_config_addr - uvisor_export_table_size);
}
#endif

View File

@ -20,6 +20,11 @@
#define UVISOR_ERROR_INVALID_BOX_ID (-2)
#define UVISOR_ERROR_BUFFER_TOO_SMALL (-3)
#define UVISOR_ERROR_BOX_NAMESPACE_ANONYMOUS (-4)
#define UVISOR_ERROR_BAD_MAGIC (-5)
#define UVISOR_ERROR_BAD_VERSION (-6)
#define UVISOR_ERROR_OUT_OF_STRUCTURES (-7)
#define UVISOR_ERROR_INVALID_PARAMETERS (-8)
#define UVISOR_ERROR_NOT_IMPLEMENTED (-9)
#define UVISOR_ERROR_CLASS_MASK (0xFFFF0000UL)
@ -29,6 +34,7 @@
typedef enum {
USER_NOT_ALLOWED = 1,
DEBUG_BOX_HALT,
} THaltUserError;
typedef enum {

View File

@ -17,6 +17,7 @@
#ifndef __UVISOR_API_INTERRUPTS_H__
#define __UVISOR_API_INTERRUPTS_H__
#include "api/inc/unvic_exports.h"
#include "api/inc/uvisor_exports.h"
#include <stdint.h>
@ -60,4 +61,10 @@ UVISOR_EXTERN void vIRQ_DisableAll(void);
* ::vIRQ_DisableAll for more information. */
UVISOR_EXTERN void vIRQ_EnableAll(void);
/** Reset the device.
* @warning Currently only the debug box can reset the device.
* @param reason[in] Reason for rebooting. Currently not used.
*/
UVISOR_EXTERN void vIRQ_SystemReset(TResetReason reason);
#endif /* __UVISOR_API_INTERRUPTS_H__ */

View File

@ -0,0 +1,36 @@
/*
* 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_LIB_HOOK_EXPORTS_H__
#define __UVISOR_API_LIB_HOOK_EXPORTS_H__
#include <stdint.h>
/* Predeclaration */
typedef struct uvisor_semaphore UvisorSemaphore;
/*
* uVisor library hooks
*
* All functions that uVisor needs to call that are implemented in uvisor-lib.
* These functions will be run by unprivileged code only. */
typedef struct {
void (*box_init)(void * lib_config);
int (*semaphore_init)(UvisorSemaphore * semaphore, int32_t count);
int (*semaphore_pend)(UvisorSemaphore * semaphore, uint32_t timeout_ms);
} UvisorLibHooks;
#endif

View File

@ -0,0 +1,45 @@
/*
* 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_MAGIC_EXPORTS_H__
#define __UVISOR_API_MAGIC_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)))
/** Magics
*
* The following magics are used to verify various things within uVisor.The
* magics are chosen to be one of the explicitly undefined Thumb-2
* instructions.
*/
#if defined(__thumb__) && defined(__thumb2__)
#define UVISOR_RPC_GATEWAY_MAGIC_ASYNC UDF_OPCODE(0x07C2)
#define UVISOR_RPC_GATEWAY_MAGIC_SYNC UDF_OPCODE(0x07C3)
#define UVISOR_POOL_MAGIC UDF_OPCODE(0x07C4)
#define UVISOR_POOL_QUEUE_MAGIC UDF_OPCODE(0x07C5)
#else
#error "Unsupported instruction set. The ARM Thumb-2 instruction set must be supported."
#endif /* __thumb__ && __thumb2__ */
#endif /* __UVISOR_API_MAGIC_EXPORTS_H__ */

View File

@ -0,0 +1,208 @@
/*
* 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_POOL_QUEUE_EXPORTS_H
#define UVISOR_POOL_QUEUE_EXPORTS_H
#include "api/inc/magic_exports.h"
#include "api/inc/uvisor_exports.h"
#include "api/inc/uvisor_semaphore_exports.h"
#include "api/inc/uvisor_spinlock_exports.h"
#include <stdint.h>
#include <stddef.h>
#define UVISOR_POOL_QUEUE_NON_BLOCKING (0)
#define UVISOR_POOL_QUEUE_BLOCKING (1)
#define UVISOR_POOL_SLOT_INVALID ((uint8_t) 0xFFU)
#define UVISOR_POOL_SLOT_IS_DEQUEUED ((uint8_t) 0xFEU)
#define UVISOR_POOL_SLOT_IS_FREE ((uint8_t) 0xFDU)
#define UVISOR_POOL_MAX_VALID ((uint8_t) 0xFCU)
typedef uint8_t uvisor_pool_slot_t;
typedef struct uvisor_pool_queue_entry {
union {
struct {
/* The next slot in the queue */
uvisor_pool_slot_t next;
/* The previous slot in the queue */
uvisor_pool_slot_t prev;
} queued;
struct {
/* If the slot is free, the next available slot in the free list */
uvisor_pool_slot_t next;
/* If the slot is free or dequeued */
uvisor_pool_slot_t state;
} dequeued;
};
} uvisor_pool_queue_entry_t;
/* These are assumed to only be statically allocated, so the management array
* in in-place. */
typedef struct uvisor_pool {
/* Magic that identifies this as a uvisor_pool type. */
uint32_t magic;
/* The array holds slots of data. */
void const * array;
/* The distance between elements in the array. */
size_t stride;
/* The maximum number of elements that could be in the array. */
uvisor_pool_slot_t num;
/* Whether or not the queue can block callers who want to allocate slots
* from the pool. If non-zero, when no slots is available in the pool,
* callers will be blocked up to their timeout amount of time before giving
* up. */
int blocking;
/* The number of items currently allocated from the pool. For testing and
* debug purposes only. */
uvisor_pool_slot_t num_allocated;
/* The first free slot. */
uvisor_pool_slot_t first_free;
/* The semaphore is used to block allocations when the pool is full. */
UvisorSemaphore semaphore;
/* The spinlock serializes updates to the management array. */
UvisorSpinlock spinlock;
/* This must be at the end so we can allocate memory for pools by
* allocating enough room for the size of the pool appended by an array of
* entries. */
uvisor_pool_queue_entry_t management_array[];
} uvisor_pool_t;
typedef struct uvisor_pool_queue {
/* Magic that identifies this as a uvisor_pool_queue type. */
uint32_t magic;
/* The first allocated slot */
uvisor_pool_slot_t head;
/* The last allocated slot */
uvisor_pool_slot_t tail;
uvisor_pool_t * pool;
} uvisor_pool_queue_t;
/* Intialize a pool.
* Return 0 on success, non-zero otherwise. */
UVISOR_EXTERN int uvisor_pool_init(uvisor_pool_t * pool, void * array, size_t stride, size_t num, int blocking);
/* Initialize a pool queue.
* Return 0 on success, non-zero otherwise. */
UVISOR_EXTERN int uvisor_pool_queue_init(uvisor_pool_queue_t * pool_queue, uvisor_pool_t * pool, void * array, size_t stride, size_t num, int blocking);
/* Allocate a slot from the pool. If the pool has no more slots available,
* block up to the specified length of time in milliseconds. No blocking will
* occur if the timeout is zero or the pool was initialized as non-blocking.
* This doesn't put anything in the slot for you. It's up to you to do that.
* Return the index of the allocated slot, or UVISOR_POOL_SLOT_INVALID if
* timed out waiting for an available slot. This function will spin until the
* spin lock serializing access to the pool can be taken. */
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_allocate(uvisor_pool_t * pool, uint32_t timeout_ms);
/* Attempt to allocate a slot. This function will fail if the spin lock
* serializing access to the pool can not be taken. */
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_try_allocate(uvisor_pool_t * pool);
/* Enqueue the specified slot into the queue. */
UVISOR_EXTERN void uvisor_pool_queue_enqueue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot);
UVISOR_EXTERN int uvisor_pool_queue_try_enqueue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot);
/* Free the specified slot back into the pool. Invalid slots are ignored.
* Return the slot that was freed, or UVISOR_POOL_SLOT_IS_FREE if the slot was
* already freed, or UVISOR_POOL_SLOT_INVALID if the slot being requested to
* free is outside the range of the queue. */
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_free(uvisor_pool_t * pool, uvisor_pool_slot_t slot);
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_try_free(uvisor_pool_t * pool, uvisor_pool_slot_t slot);
/* Remove the specified slot from the queue. This function does not free the
* specified slot back into the pool. Return the slot that was dequeued, or
* UVISOR_POOL_SLOT_IS_DEQUEUED if the slot was already dequeued, or
* UVISOR_POOL_SLOT_INVALID if the slot being requested to dequeue is outside
* the range of the queue. */
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_dequeue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot);
/* Remove the first slot from the queue. This function does not free the
* specified slot back into the pool. Return the slot that was dequeued or
* UVISOR_POOL_SLOT_INVALID if the slot being requested to dequeue is outside
* the range of the queue. */
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_dequeue_first(uvisor_pool_queue_t * pool_queue);
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_dequeue_first(uvisor_pool_queue_t * pool_queue);
/* Find the first (in queue order) slot that the supplied query function
* returns non-zero for. The query function is provided with `context` on every
* invocation. This allows query functions to access additional data without
* having to use global variables. `uvisor_pool_queue_find_first` is reentrant. */
typedef int (*TQueryFN_Ptr)(uvisor_pool_slot_t slot, void * context);
UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_find_first(uvisor_pool_queue_t * pool_queue,
TQueryFN_Ptr query_fn, void * context);
/* Inline helper function to make allocating slots for pool queues easier and
* better encapsulated (clients don't need to pull the pool out of the pool
* queue, or even realize pool_queue is implemented with a pool) */
static inline uvisor_pool_slot_t uvisor_pool_queue_allocate(uvisor_pool_queue_t * pool_queue, uint32_t timeout_ms)
{
return uvisor_pool_allocate(pool_queue->pool, timeout_ms);
}
static inline uvisor_pool_slot_t uvisor_pool_queue_try_allocate(uvisor_pool_queue_t * pool_queue)
{
return uvisor_pool_try_allocate(pool_queue->pool);
}
/* Inline helper function to make freeing slots for pool queues easier and
* better encapsulated (clients don't need to pull the pool out of the pool
* queue, or even realize pool_queue is implemented with a pool) */
static inline uvisor_pool_slot_t uvisor_pool_queue_free(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot)
{
return uvisor_pool_free(pool_queue->pool, slot);
}
static inline uvisor_pool_slot_t uvisor_pool_queue_try_free(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot)
{
return uvisor_pool_try_free(pool_queue->pool, slot);
}
/* Return a pointer to the specified slot within the pool. */
static inline void * uvisor_pool_pointer_to(uvisor_pool_t * pool, uvisor_pool_slot_t slot)
{
if (slot >= pool->num) {
return NULL;
}
return (uint8_t *) pool->array + pool->stride * slot;
}
typedef struct {
int (*init)(uvisor_pool_t *, void *, size_t, size_t, int);
int (*queue_init)(uvisor_pool_queue_t *, uvisor_pool_t *, void *, size_t, size_t, int);
uvisor_pool_slot_t (*allocate)(uvisor_pool_t *, uint32_t);
void (*queue_enqueue)(uvisor_pool_queue_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*free)(uvisor_pool_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*queue_dequeue)(uvisor_pool_queue_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*queue_dequeue_first)(uvisor_pool_queue_t *);
uvisor_pool_slot_t (*queue_find_first)(uvisor_pool_queue_t *, TQueryFN_Ptr, void *);
} UvisorPoolTable;
#endif

View File

@ -17,6 +17,9 @@
#ifndef __UVISOR_API_PRIV_SYS_HOOK_EXPORTS_H__
#define __UVISOR_API_PRIV_SYS_HOOK_EXPORTS_H__
/* Predeclaration */
typedef struct uvisor_semaphore UvisorSemaphore;
/*
* Privileged system hooks
*
@ -31,18 +34,20 @@ typedef struct {
void (*priv_pendsv)(void);
void (*priv_systick)(void);
uint32_t (*priv_os_suspend)(void);
int (*priv_uvisor_semaphore_post)(UvisorSemaphore * semaphore);
} UvisorPrivSystemHooks;
/* Use this macro to register privileged system IRQ hooks. If you don't want to
* register a particular privileged system IRQ hook, you can supply NULL for
* that hook parameter. */
#define UVISOR_SET_PRIV_SYS_HOOKS(priv_svc_0_, priv_pendsv_, priv_systick_, priv_os_suspend_) \
#define UVISOR_SET_PRIV_SYS_HOOKS(priv_svc_0_, priv_pendsv_, priv_systick_, priv_os_suspend_, priv_uvisor_semaphore_post_) \
UVISOR_EXTERN_C_BEGIN \
const UvisorPrivSystemHooks __uvisor_priv_sys_hooks = { \
.priv_svc_0 = priv_svc_0_, \
.priv_pendsv = priv_pendsv_, \
.priv_systick = priv_systick_, \
.priv_os_suspend = priv_os_suspend_, \
.priv_uvisor_semaphore_post = priv_uvisor_semaphore_post_, \
}; \
UVISOR_EXTERN_C_END

View File

@ -17,32 +17,26 @@
#ifndef __UVISOR_API_RPC_H__
#define __UVISOR_API_RPC_H__
#include "api/inc/rpc_exports.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);
/** 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
* @param box_id_caller[out] a memory location to store the box ID of the
* calling box (the source box of the RPC). This is
* set before the RPC is dispatched, so that the RPC
* target function can read from this location to
* determine the calling box ID. Optional.
* @param timeout_ms specifies how long to wait (in ms) for an incoming
* RPC message before returning
*/
UVISOR_EXTERN int rpc_fncall_waitfor(const TFN_Ptr fn_ptr_array[], size_t fn_count, uint32_t timeout_ms);
UVISOR_EXTERN int rpc_fncall_waitfor(const TFN_Ptr fn_ptr_array[], size_t fn_count, int * box_id_caller, uint32_t timeout_ms);
/** Wait for an outgoing RPC to finish.
*

View File

@ -0,0 +1,140 @@
/*
* 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_EXPORTS_H__
#define __UVISOR_API_RPC_EXPORTS_H__
#include "api/inc/pool_queue_exports.h"
#include "api/inc/uvisor_semaphore_exports.h"
#include "api/inc/rpc_gateway_exports.h"
typedef uint32_t (*TFN_Ptr)(uint32_t, uint32_t, uint32_t, uint32_t);
#define UVISOR_RESULT_SLOT_BITS 10
#define UVISOR_RESULT_SLOT_MASK ((1 << UVISOR_RESULT_SLOT_BITS) - 1)
#define UVISOR_RESULT_COUNTER_MASK (0xFFFFFFFFUL << UVISOR_RESULT_SLOT_BITS)
/* Increment by 2 because we never want to overflow into the invalid value. */
#define UVISOR_RESULT_COUNTER_INCREMENT (2 << UVISOR_RESULT_SLOT_BITS)
#define UVISOR_RESULT_INVALID_COUNTER (UVISOR_RESULT_COUNTER_MASK)
/* This is the token to wait on for the result of an asynchronous RPC. */
typedef uint32_t uvisor_rpc_result_t;
static inline uvisor_pool_slot_t uvisor_result_slot(uvisor_rpc_result_t result)
{
return result & UVISOR_RESULT_SLOT_MASK;
}
static inline uint32_t uvisor_result_counter(uvisor_rpc_result_t result)
{
return result & UVISOR_RESULT_COUNTER_MASK;
}
static inline uvisor_rpc_result_t uvisor_result_build(uint32_t counter, uvisor_pool_slot_t slot)
{
return (counter & UVISOR_RESULT_COUNTER_MASK) | (slot & UVISOR_RESULT_SLOT_MASK);
}
typedef enum {
/* Who sets this value for caller (outgoing queue), Who sets this value for (incoming queue) callee. */
UVISOR_RPC_MESSAGE_STATE_INVALID, /* nobody, nobody */
UVISOR_RPC_MESSAGE_STATE_IDLE, /* caller receive function before freeing, uvisor when delivers back */
UVISOR_RPC_MESSAGE_STATE_READY_TO_SEND, /* send function, nobody */
UVISOR_RPC_MESSAGE_STATE_SENT, /* uvisor, uvisor */
UVISOR_RPC_MESSAGE_STATE_DONE, /* waitfor_fngroup function, uvisor when delivers back */
} uvisor_rpc_message_state_t;
typedef struct uvisor_rpc_message {
/* NOTE: These are set by the caller, and read by the callee. */
uint32_t p0;
uint32_t p1;
uint32_t p2;
uint32_t p3;
const TRPCGateway * gateway;
/* The box ID of the other box. For callers, this is the destination box
* ID. For callees, this is the source box ID. */
int other_box_id;
/* The semaphore to post to when a result is ready */
UvisorSemaphore semaphore;
/* This cookie keeps track of which result to wait for. It changes
* atomically to an invalid cookie when being waited on, to prevent
* multiple waits for the same result. */
uvisor_rpc_result_t wait_cookie;
/* This is an extra copy of the above cookie, used by uVisor to verify that
* a certain result matches a certain caller. This identifies to uVisor
* which RPC it should complete. uVisor must verify this information of
* course, to see if this box is currently being called into and is allowed
* to complete the RPC. */
uvisor_rpc_result_t match_cookie;
uvisor_rpc_message_state_t state;
uint32_t result;
} uvisor_rpc_message_t;
typedef struct uvisor_rpc_fn_group {
/* A pointer to the function group */
TFN_Ptr const * fn_ptr_array;
size_t fn_count;
/* The semaphore to wait on for this function group */
UvisorSemaphore semaphore;
} uvisor_rpc_fn_group_t;
#define UVISOR_RPC_OUTGOING_MESSAGE_SLOTS (8)
#define UVISOR_RPC_INCOMING_MESSAGE_SLOTS (8)
#define UVISOR_RPC_FN_GROUP_SLOTS (8)
#define UVISOR_RPC_OUTGOING_MESSAGE_TYPE(slots) \
struct { \
uvisor_pool_queue_t queue; \
uvisor_pool_t pool; \
uvisor_pool_queue_entry_t entries[slots]; \
uvisor_rpc_message_t messages[slots]; \
}
#define UVISOR_RPC_INCOMING_MESSAGE_TYPE(slots) \
struct { \
uvisor_pool_queue_t todo_queue; \
uvisor_pool_queue_t done_queue; \
uvisor_pool_t pool; \
uvisor_pool_queue_entry_t entries[slots]; \
uvisor_rpc_message_t messages[slots]; \
}
#define UVISOR_RPC_FN_GROUP_TYPE(slots) \
struct { \
uvisor_pool_queue_t queue; \
uvisor_pool_t pool; \
uvisor_pool_queue_entry_t entries[slots]; \
uvisor_rpc_fn_group_t fn_groups[slots]; \
}
typedef UVISOR_RPC_OUTGOING_MESSAGE_TYPE(UVISOR_RPC_OUTGOING_MESSAGE_SLOTS) uvisor_rpc_outgoing_message_queue_t;
typedef UVISOR_RPC_INCOMING_MESSAGE_TYPE(UVISOR_RPC_INCOMING_MESSAGE_SLOTS) uvisor_rpc_incoming_message_queue_t;
typedef UVISOR_RPC_FN_GROUP_TYPE(UVISOR_RPC_FN_GROUP_SLOTS) uvisor_rpc_fn_group_queue_t;
#endif

View File

@ -22,12 +22,6 @@
#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
@ -40,8 +34,8 @@
*
* @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 gw_name[in] The new, callable function pointer for initiating an RPC from the caller's box
* @param fn_name[in] The function that will run in the callee's box 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
@ -53,15 +47,17 @@
#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__) \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_DECL(fn_name, gw_name ## _rpc_gateway, __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)), \
__UVISOR_OFFSETOF(TRPCGateway, caller)), \
.magic = UVISOR_RPC_GATEWAY_MAGIC_SYNC, \
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
.function = (uint32_t) _sgw_sync_ ## fn_name, \
.target = (uint32_t) fn_name, \
.caller = (uint32_t) _sgw_sync_ ## fn_name, \
}; \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, gw_name ## _rpc_gateway, __VA_ARGS__) \
\
/* Pointer to the gateway we just created. The pointer is located in a
* discoverable linker section. */ \
@ -85,8 +81,8 @@
*
* @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 gw_name[in] The new, callable function pointer for initiating an RPC from the caller's box
* @param fn_name[in] The function that will run in the callee's box 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
@ -98,15 +94,17 @@
#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__) \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_DECL(fn_name, gw_name ## _rpc_gateway, __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)), \
__UVISOR_OFFSETOF(TRPCGateway, caller)), \
.magic = UVISOR_RPC_GATEWAY_MAGIC_ASYNC, \
.box_ptr = (uint32_t) &box_name ## _cfg_ptr, \
.function = (uint32_t) _sgw_async_ ## fn_name, \
.target = (uint32_t) fn_name, \
.caller = (uint32_t) _sgw_async_ ## fn_name, \
}; \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, gw_name ## _rpc_gateway, __VA_ARGS__) \
\
/* Pointer to the gateway we just created. The pointer is located in a
* discoverable linker section. */ \
@ -145,96 +143,130 @@
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, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_DECL(fn_name, gateway, ...) \
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4_DECL, \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3_DECL, \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2_DECL, \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1_DECL, \
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0_DECL)(fn_name, gateway, __VA_ARGS__)
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER(fn_name, gateway, ...) \
__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__)
_UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0)(fn_name, gateway, __VA_ARGS__)
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0_DECL(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(void);
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_0(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(void) \
{ \
TFN_Ptr fp = (TFN_Ptr) fn_name; \
return rpc_fncall_sync(0, 0, 0, 0, fp); \
return rpc_fncall_sync(0, 0, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1_DECL(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0);
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_1(fn_name, gateway, ...) \
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); \
return rpc_fncall_sync(p0, 0, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2_DECL(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1);
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_2(fn_name, gateway, ...) \
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); \
return rpc_fncall_sync(p0, p1, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3_DECL(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2);
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_3(fn_name, gateway, ...) \
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); \
return rpc_fncall_sync(p0, p1, p2, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4_DECL(fn_name, gateway, ...) \
static uint32_t _sgw_sync_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3);
#define _UVISOR_BOX_RPC_GATEWAY_SYNC_CALLER_4(fn_name, gateway, ...) \
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); \
return rpc_fncall_sync(p0, p1, p2, p3, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_DECL(fn_name, gateway, ...) \
__UVISOR_BOX_MACRO(__VA_ARGS__, _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4_DECL, \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3_DECL, \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2_DECL, \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1_DECL, \
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0_DECL)(fn_name, gateway, __VA_ARGS__)
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER(fn_name, gateway, ...) \
__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__)
_UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0)(fn_name, gateway, __VA_ARGS__)
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0_DECL(fn_name, gateway, ...) \
static uvisor_rpc_result_t _sgw_async_ ## fn_name(void);
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_0(fn_name, gateway, ...) \
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); \
return rpc_fncall_async(0, 0, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1_DECL(fn_name, gateway, ...) \
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0);
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_1(fn_name, gateway, ...) \
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); \
return rpc_fncall_async(p0, 0, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2_DECL(fn_name, gateway, ...) \
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1);
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_2(fn_name, gateway, ...) \
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); \
return rpc_fncall_async(p0, p1, 0, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3_DECL(fn_name, gateway, ...) \
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2);
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_3(fn_name, gateway, ...) \
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); \
return rpc_fncall_async(p0, p1, p2, 0, &gateway); \
}
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4(fn_name, ...) \
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4_DECL(fn_name, gateway, ...) \
static uvisor_rpc_result_t _sgw_async_ ## fn_name(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3);
#define _UVISOR_BOX_RPC_GATEWAY_ASYNC_CALLER_4(fn_name, gateway, ...) \
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); \
return rpc_fncall_async(p0, p1, p2, p3, &gateway); \
}
/* 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);
UVISOR_EXTERN uint32_t rpc_fncall_sync(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const TRPCGateway * gateway);
/* 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);
UVISOR_EXTERN uvisor_rpc_result_t rpc_fncall_async(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const TRPCGateway * gateway);
#endif /* __UVISOR_API_RPC_GATEWAY_H__ */

View File

@ -18,42 +18,28 @@
#define __UVISOR_API_RPC_GATEWAY_EXPORTS_H__
#include "api/inc/uvisor_exports.h"
#include "api/inc/magic_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__ */
/* 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)))
/** 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.
* and that the `caller` and `target` field are at a pre-determined offset from
* the `ldr_pc` field.
*/
typedef struct {
typedef struct RPCGateway {
uint32_t ldr_pc;
uint32_t magic;
uint32_t box_ptr;
uint32_t function; /* It's like a pretend literal pool. */
uint32_t target;
uint32_t caller; /* This is not for use by anything other than the ldr_pc. It's like a pretend literal pool. */
} UVISOR_PACKED UVISOR_ALIGN(4) TRPCGateway;
#endif /* __UVISOR_API_RPC_GATEWAY_EXPORTS_H__ */

View File

@ -28,6 +28,13 @@
* priorities available to them */
#define UVISOR_VIRQ_MAX_PRIORITY ((uint32_t) (1 << __NVIC_PRIO_BITS) - 1 - __UVISOR_NVIC_MIN_PRIORITY)
/* Reasons for rebooting */
typedef enum {
RESET_REASON_NO_REASON = 0,
RESET_REASON_HALT,
__TRESETREASON_MAX /* Always keep the last element of the enum. */
} TResetReason;
/* Offset of NVIC interrupts with respect to handler 0 */
#define NVIC_OFFSET 16

View File

@ -27,6 +27,7 @@
/* Library header files */
#include "api/inc/benchmark.h"
#include "api/inc/box_config.h"
#include "api/inc/box_id.h"
#include "api/inc/debug.h"
#include "api/inc/disabled.h"
#include "api/inc/error.h"
@ -35,6 +36,7 @@
#include "api/inc/rpc.h"
#include "api/inc/rpc_gateway.h"
#include "api/inc/secure_access.h"
#include "api/inc/uvisor_semaphore.h"
#else /* defined(UVISOR_PRESENT) && UVISOR_PRESENT == 1 */
@ -64,5 +66,6 @@ UVISOR_EXTERN int uvisor_lib_init(void);
#include "api/inc/uvisor_exports.h"
#include "api/inc/vmpu_exports.h"
#include "api/inc/page_allocator_exports.h"
#include "api/inc/pool_queue_exports.h"
#endif /* __UVISOR_API_UVISOR_LIB_H__ */

View File

@ -22,6 +22,8 @@
/* maximum number of boxes allowed: 1 is the minimum (unprivileged box) */
#define UVISOR_MAX_BOXES 5U
#define UVISOR_WAIT_FOREVER (0xFFFFFFFFUL)
/* extern keyword */
#ifdef __cplusplus
#define UVISOR_EXTERN extern "C"
@ -57,6 +59,7 @@
#define UVISOR_WEAK __weak
#define UVISOR_NORETURN __noreturn
#define UVISOR_RAMFUNC __ramfunc
#define UVISOR_DEPRECATED
#else
#define UVISOR_ALIGN(x) __attribute__((aligned(x)))
#define UVISOR_FORCEINLINE inline __attribute__((always_inline))
@ -64,6 +67,7 @@
#define UVISOR_WEAK __attribute__((weak))
#define UVISOR_NORETURN __attribute__((noreturn))
#define UVISOR_RAMFUNC __attribute__ ((section (".ramfunc"), noinline))
#define UVISOR_DEPRECATED __attribute__((deprecated))
#endif
/* array count macro */

View File

@ -0,0 +1,31 @@
/*
* 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_UVISOR_SEMAPHORE_H__
#define __UVISOR_API_UVISOR_SEMAPHORE_H__
#include "api/inc/uvisor_semaphore_exports.h"
UVISOR_EXTERN int __uvisor_semaphore_init(UvisorSemaphore * semaphore, int32_t count);
/* This function is not safe to call from interrupt context, even if the
* timeout is zero. */
UVISOR_EXTERN int __uvisor_semaphore_pend(UvisorSemaphore * semaphore, uint32_t timeout_ms);
/* This function is safe to call from interrupt context. */
UVISOR_EXTERN int __uvisor_semaphore_post(UvisorSemaphore * semaphore);
#endif

View File

@ -0,0 +1,31 @@
/*
* 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_UVISOR_SEMAPHORE_EXPORTS_H__
#define __UVISOR_API_UVISOR_SEMAPHORE_EXPORTS_H__
#include "api/inc/uvisor_exports.h"
/* This must be big enough for all operating systems uVisor runs on. */
#define UVISOR_SEMAPHORE_INTERNAL_SIZE (16)
/* An opaque structure, that one knows the size of so that they can allocate
* memory. */
typedef struct uvisor_semaphore {
uint8_t internal[UVISOR_SEMAPHORE_INTERNAL_SIZE];
} UVISOR_ALIGN(4) UvisorSemaphore;
#endif

View File

@ -0,0 +1,27 @@
/*
* 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_UVISOR_SPINLOCK_H__
#define __UVISOR_API_UVISOR_SPINLOCK_H__
#include "api/inc/uvisor_exports.h"
#include <stdbool.h>
typedef struct {
bool acquired;
} UvisorSpinlock;
#endif /* __UVISOR_API_UVISOR_SPINLOCK_H__ */

View File

@ -18,6 +18,8 @@
#define __UVISOR_API_VMPU_EXPORTS_H__
#include "api/inc/uvisor_exports.h"
#include "api/inc/pool_queue_exports.h"
#include "api/inc/rpc_exports.h"
#include <stdint.h>
/* The maximum box namespace length is 37 so that it is exactly big enough for
@ -148,19 +150,37 @@ typedef struct {
UvisorBoxAcl acl;
} UVISOR_PACKED UvisorBoxAclItem;
typedef struct {
/* Contains user provided size of box context without guards of buffers. */
uint32_t context_size;
/* Contains total memory used by the RPC queues (incl. management and pool). */
uint32_t rpc_outgoing_message_size;
uint32_t rpc_incoming_message_size;
uint32_t rpc_fn_group_size;
} UVISOR_PACKED uvisor_sizes_t;
/* The number of additional bss sections per box bss.
* The size of each section is stored in the box config, and uVisor core will
* iterate over the box bss, split it into sections as defined by the size table
* and assign a pointer to beginning of that section into the box index pointer table.
*/
#define UVISOR_BOX_INDEX_SIZE_COUNT (sizeof(uvisor_sizes_t) / sizeof(uint32_t))
typedef struct {
uint32_t magic;
uint32_t version;
/* Box stack size includes stack guards and rounding buffer. */
uint32_t stack_size;
/* Contains the size of the index (must be at least sizeof(UvisorBoxIndex)). */
uint32_t index_size;
/* Contains user provided size of box context without guards of buffers. */
uint32_t context_size;
/* Contains user provided size of box heap without guards of buffers. */
uint32_t heap_size;
/* Contains the size of the index (must be at least sizeof(UvisorBoxIndex)). */
uint32_t index_size;
union {
uint32_t bss_size[UVISOR_BOX_INDEX_SIZE_COUNT];
uvisor_sizes_t sizes;
};
/* Opaque-to-uVisor data that potentially contains uvisor-lib-specific or
* OS-specific per-box configuration */
@ -172,8 +192,17 @@ typedef struct {
} UVISOR_PACKED UvisorBoxConfig;
typedef struct {
union {
void * bss_ptr[UVISOR_BOX_INDEX_SIZE_COUNT];
struct {
/* Pointer to the user context */
void * ctx;
/* Pointer to the RPC queues */
uvisor_rpc_outgoing_message_queue_t * rpc_outgoing_message_queue;
uvisor_rpc_incoming_message_queue_t * rpc_incoming_message_queue;
uvisor_rpc_fn_group_queue_t * rpc_fn_group_queue;
};
};
/* Pointer to the box heap */
void * box_heap;
/* Size of the box heap */
@ -182,6 +211,14 @@ typedef struct {
* This is set to `NULL` by uVisor, signalling to the user lib that the
* box heap needs to be initialized before use! */
void * active_heap;
/* Counter that helps to avoid waiting on the same RPC message result twice
* by accident. */
uint32_t rpc_result_counter;
/* Box ID */
int box_id_self;
/* Pointer to the box config */
const UvisorBoxConfig * config;
} UVISOR_PACKED UvisorBoxIndex;

View File

@ -55,6 +55,10 @@ const void * g_page_heap_end;
uint8_t g_page_count_free;
/* Contains the total number of available pages. */
uint8_t g_page_count_total;
/* Contains the shift of the page owner mask. */
uint8_t g_page_map_shift;
/* Contains the rounded up page end address for ARMv7-M MPU region alignment. */
uint32_t g_page_head_end_rounded;
/* Helper function maps pointer to page id, or UVISOR_PAGE_UNUSED. */
uint8_t page_allocator_get_page_from_address(uint32_t address)
@ -132,12 +136,20 @@ void page_allocator_init(void * const heap_start, void * const heap_end, const u
/* Remember the end of the heap. */
g_page_heap_end = g_page_heap_start + g_page_count_total * g_page_size;
DPRINTF("uvisor_page_init:\n.page_heap start 0x%08x\n.page_heap end 0x%08x\n.page_heap available %ukB split into %u pages of %ukB\n\n",
g_page_head_end_rounded = vmpu_round_up_region((uint32_t) g_page_heap_end, g_page_size * 8);
/* Compute the page map shift.
* This initial shift fully left aligns the page map. */
g_page_map_shift = UVISOR_PAGE_MAP_COUNT * 32 - g_page_count_total;
g_page_map_shift -= (g_page_head_end_rounded - (uint32_t) g_page_heap_end) / g_page_size;
DPRINTF(
"page heap: [0x%08x, 0x%08x] %ukB -> %u %ukB pages\r\n",
(unsigned int) g_page_heap_start,
(unsigned int) g_page_heap_end,
(unsigned int) (g_page_count_free * g_page_size / 1024),
(unsigned int) g_page_count_total,
(unsigned int) (g_page_size / 1024));
(unsigned int) (g_page_size / 1024)
);
/* Force a reset of owner and usage page maps. */
memset(g_page_owner_map, 0, sizeof(g_page_owner_map));

View File

@ -37,8 +37,10 @@
#define UVISOR_PAGE_SIZE_MINIMUM (1024UL)
#endif
/* Defines the number of uint32_t page owner masks in the owner map. */
#define UVISOR_PAGE_MAP_COUNT ((UVISOR_PAGE_MAX_COUNT + 31) / 32)
/* Defines the number of uint32_t page owner masks in the owner map.
* +8 is used for ARMv7-M MPUs, where a shift of up to 7-bits may be required
* to align MPU regions. */
#define UVISOR_PAGE_MAP_COUNT ((UVISOR_PAGE_MAX_COUNT + 31 + 8) / 32)
/* The page box_id is the box id which is 8-bit large. */
typedef uint8_t page_owner_t;
@ -46,6 +48,10 @@ typedef uint8_t page_owner_t;
#define UVISOR_PAGE_UNUSED ((page_owner_t) (-1))
/* Contains the total number of available pages. */
extern uint8_t g_page_count_total;
/* Contains the shift of the page owner mask. */
extern uint8_t g_page_map_shift;
/* Contains the ARMv7-MPU rounded page end. */
extern uint32_t g_page_head_end_rounded;
/** Sets the page bit in the page map array.
* @param map an array of `uint32_t` containing the page map
@ -53,7 +59,7 @@ extern uint8_t g_page_count_total;
*/
static inline void page_allocator_map_set(uint32_t * const map, uint8_t page)
{
page += UVISOR_PAGE_MAP_COUNT * 32 - g_page_count_total;
page += g_page_map_shift;
map[page / 32] |= (1UL << (page % 32));
}
@ -63,7 +69,7 @@ static inline void page_allocator_map_set(uint32_t * const map, uint8_t page)
*/
static inline void page_allocator_map_clear(uint32_t * const map, uint8_t page)
{
page += UVISOR_PAGE_MAP_COUNT * 32 - g_page_count_total;
page += g_page_map_shift;
map[page / 32] &= ~(1UL << (page % 32));
}
@ -75,7 +81,7 @@ static inline void page_allocator_map_clear(uint32_t * const map, uint8_t page)
*/
static inline int page_allocator_map_get(const uint32_t * const map, uint8_t page)
{
page += UVISOR_PAGE_MAP_COUNT * 32 - g_page_count_total;
page += g_page_map_shift;
return (map[page / 32] >> (page % 32)) & 0x1;
}

View File

@ -15,6 +15,9 @@
* limitations under the License.
*/
#include "uvisor-lib/uvisor-lib.h"
#include "api/inc/pool_queue_exports.h"
#include "api/inc/rpc_exports.h"
#include "api/inc/uvisor_semaphore.h"
#include "mbed_interface.h"
#include "cmsis_os.h"
#include <stdint.h>
@ -26,7 +29,92 @@ extern void PendSV_Handler(void);
extern void SysTick_Handler(void);
extern uint32_t rt_suspend(void);
UVISOR_SET_PRIV_SYS_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler, rt_suspend);
UVISOR_SET_PRIV_SYS_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler, rt_suspend, __uvisor_semaphore_post);
extern RtxBoxIndex * const __uvisor_ps;
void __uvisor_initialize_rpc_queues(void)
{
UvisorBoxIndex * const index = &__uvisor_ps->index;
uvisor_pool_slot_t i;
uvisor_rpc_outgoing_message_queue_t * rpc_outgoing_msg_queue = index->rpc_outgoing_message_queue;
uvisor_rpc_incoming_message_queue_t * rpc_incoming_msg_queue = index->rpc_incoming_message_queue;
uvisor_rpc_fn_group_queue_t * rpc_fn_group_queue = index->rpc_fn_group_queue;
/* Initialize the outgoing RPC message queue. */
if (uvisor_pool_queue_init(&rpc_outgoing_msg_queue->queue,
&rpc_outgoing_msg_queue->pool,
rpc_outgoing_msg_queue->messages,
sizeof(*rpc_outgoing_msg_queue->messages),
UVISOR_RPC_OUTGOING_MESSAGE_SLOTS,
UVISOR_POOL_QUEUE_BLOCKING)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* Initialize all the result semaphores. */
for (i = 0; i < UVISOR_RPC_OUTGOING_MESSAGE_SLOTS; i++) {
UvisorSemaphore * semaphore = &rpc_outgoing_msg_queue->messages[i].semaphore;
if (__uvisor_semaphore_init(semaphore, 1)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* Semaphores are created with their value initialized to count. We
* want the semaphore to start at zero. Decrement the semaphore, so it
* starts with a value of zero. This will allow the first pend to
* block. */
if (__uvisor_semaphore_pend(semaphore, 0)) {
uvisor_error(USER_NOT_ALLOWED);
}
}
/* Initialize the incoming RPC message queues. */
if (uvisor_pool_queue_init(&rpc_incoming_msg_queue->todo_queue,
&rpc_incoming_msg_queue->pool,
rpc_incoming_msg_queue->messages,
sizeof(*rpc_incoming_msg_queue->messages),
UVISOR_RPC_INCOMING_MESSAGE_SLOTS,
UVISOR_POOL_QUEUE_NON_BLOCKING)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* This is a double init of the pool. We need a function that just inits
* the queue, not the pool, and init everybody separately. */
if (uvisor_pool_queue_init(&rpc_incoming_msg_queue->done_queue,
&rpc_incoming_msg_queue->pool,
rpc_incoming_msg_queue->messages,
sizeof(*rpc_incoming_msg_queue->messages),
UVISOR_RPC_INCOMING_MESSAGE_SLOTS,
UVISOR_POOL_QUEUE_NON_BLOCKING)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* Initialize the function group pool. */
if (uvisor_pool_queue_init(&rpc_fn_group_queue->queue,
&rpc_fn_group_queue->pool,
rpc_fn_group_queue->fn_groups,
sizeof(*rpc_fn_group_queue->fn_groups),
UVISOR_RPC_FN_GROUP_SLOTS,
UVISOR_POOL_QUEUE_BLOCKING)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* Initialize all the function group semaphores. */
for (i = 0; i < UVISOR_RPC_FN_GROUP_SLOTS; i++) {
UvisorSemaphore * semaphore = &rpc_fn_group_queue->fn_groups[i].semaphore;
if (__uvisor_semaphore_init(semaphore, 1)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* Semaphores are created with their value initialized to count. We
* want the semaphore to start at zero. Decrement the semaphore, so it
* starts with a value of zero. This will allow the first pend to
* block. */
if (__uvisor_semaphore_pend(semaphore, 0)) {
uvisor_error(USER_NOT_ALLOWED);
}
}
}
/* This function is called by uVisor in unprivileged mode. On this OS, we
* create box main threads for the box. */
@ -36,6 +124,8 @@ void __uvisor_lib_box_init(void * lib_config)
osThreadDef_t * flash_thread_def = lib_config;
osThreadDef_t thread_def;
__uvisor_initialize_rpc_queues();
/* Copy thread definition from flash to RAM. The thread definition is most
* likely in flash, so we need to copy it to box-local RAM before we can
* modify it. */

View File

@ -0,0 +1,47 @@
#include "api/inc/uvisor_semaphore_exports.h"
#include "api/inc/uvisor_exports.h"
#include "api/inc/halt_exports.h"
#include "cmsis_os.h"
#include <string.h>
typedef struct uvisor_semaphore_internal {
osSemaphoreId id;
osSemaphoreDef_t def;
uint32_t data[2]; /* RTX expects this is 4-byte aligned */
} UVISOR_ALIGN(4) uvisor_semaphore_internal_t;
UVISOR_STATIC_ASSERT(UVISOR_SEMAPHORE_INTERNAL_SIZE >= sizeof(UvisorSemaphore), semaphore_size_too_small);
int __uvisor_semaphore_init(UvisorSemaphore * s, int32_t count)
{
uvisor_semaphore_internal_t * semaphore = (uvisor_semaphore_internal_t *) s;
memset(semaphore->data, 0, sizeof(semaphore->data));
semaphore->def.semaphore = semaphore->data;
semaphore->id = osSemaphoreCreate(&semaphore->def, count);
/* Error when semaphore->id is NULL */
return semaphore->id == NULL ? UVISOR_ERROR_OUT_OF_STRUCTURES : 0;
}
int __uvisor_semaphore_pend(UvisorSemaphore * s, uint32_t timeout_ms)
{
uvisor_semaphore_internal_t * semaphore = (uvisor_semaphore_internal_t *) s;
int32_t num_available_tokens = osSemaphoreWait(semaphore->id, timeout_ms);
if (num_available_tokens == -1) {
return UVISOR_ERROR_INVALID_PARAMETERS;
}
if (num_available_tokens == 0) {
return UVISOR_ERROR_OUT_OF_STRUCTURES;
}
return 0;
}
int __uvisor_semaphore_post(UvisorSemaphore * s) {
uvisor_semaphore_internal_t * semaphore = (uvisor_semaphore_internal_t *) s;
return osSemaphoreRelease(semaphore->id);
}

View File

@ -1353,6 +1353,7 @@ typedef struct
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority __NVIC_SetPriority
#define NVIC_GetPriority __NVIC_GetPriority
#define NVIC_SystemReset __NVIC_SystemReset
#endif /* CMSIS_NVIC_VIRTUAL */
#ifdef CMSIS_VECTAB_VIRTUAL
@ -1581,7 +1582,7 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr
The function initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
__STATIC_INLINE void __NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */

View File

@ -1518,6 +1518,7 @@ typedef struct
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority __NVIC_SetPriority
#define NVIC_GetPriority __NVIC_GetPriority
#define NVIC_SystemReset __NVIC_SystemReset
#endif /* CMSIS_NVIC_VIRTUAL */
#ifdef CMSIS_VECTAB_VIRTUAL
@ -1747,7 +1748,7 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr
The function initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
__STATIC_INLINE void __NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */