Merge pull request #4295 from Patater/armv8m

Update uVisor to v0.28.1
pull/2224/merge
Sam Grove 2017-06-04 11:13:58 -05:00 committed by GitHub
commit 40042f0b00
44 changed files with 588 additions and 173 deletions

View File

@ -1,7 +1,7 @@
597 Alessandro Angelino
592 Milosch Meriac
554 Alessandro Angelino
105 Jaeden Amero
65 Niklas Hauser
144 Jaeden Amero
80 Niklas Hauser
5 Irit Arkin
3 JaredCJR
3 AnotherButler

View File

@ -1 +1 @@
v0.27.0-23-g8231ae897dadbb1c3eeb79ae2103d308d28c7e14
v0.28.1

View File

@ -1,37 +0,0 @@
/*
* 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 __RTX_PROCESS_MALLOC_H__
#define __RTX_PROCESS_MALLOC_H__
#include "secure_allocator.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Allocate memory on the process heap. */
void * malloc_p(size_t size);
/* Reallocate memory on the process heap. */
void * realloc_p(void * ptr, size_t size);
/* Free memory on the process heap. */
void free_p(void * ptr);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __RTX_PROCESS_MALLOC_H__ */

View File

@ -70,6 +70,18 @@ void * secure_malloc(
SecureAllocator allocator,
size_t size);
/** Drop-in for `aligned_alloc`. */
void * secure_aligned_alloc(
SecureAllocator allocator,
size_t alignment,
size_t size);
/** Drop-in for `calloc`. */
void * secure_calloc(
SecureAllocator allocator,
size_t nmemb,
size_t size);
/** Drop-in for `realloc`. */
void * secure_realloc(
SecureAllocator allocator,

View File

@ -40,7 +40,6 @@
/* The uVisor API main header file will use the above definitions. */
#include "uvisor/api/inc/uvisor-lib.h"
#include "uvisor-lib/rtx/process_malloc.h"
#include "uvisor-lib/rtx/rtx_box_index.h"
#include "uvisor-lib/rtx/secure_allocator.h"

View File

@ -19,11 +19,12 @@
#include "rt_OsEventObserver.h"
#include "api/inc/uvisor_exports.h"
#include "api/inc/unvic_exports.h"
#include "api/inc/virq_exports.h"
#include "api/inc/debug_exports.h"
#include "api/inc/halt_exports.h"
#include "api/inc/pool_queue_exports.h"
#include "api/inc/page_allocator_exports.h"
#include "api/inc/uvisor_spinlock_exports.h"
#include <stdint.h>
#define UVISOR_API_MAGIC 0x5C9411B4
@ -37,7 +38,7 @@ typedef struct {
uint32_t magic;
uint32_t (*get_version)(uint32_t);
void (*init)(void);
void (*init)(uint32_t caller);
void (*irq_enable)(uint32_t irqn);
void (*irq_disable)(uint32_t irqn);
@ -60,17 +61,23 @@ typedef struct {
void (*debug_init)(const TUvisorDebugDriver * const driver);
void (*error)(THaltUserError reason);
void (*start)(void);
void (*vmpu_mem_invalidate)(void);
int (*pool_init)(uvisor_pool_t *, void *, size_t, size_t, int);
int (*pool_queue_init)(uvisor_pool_queue_t *, uvisor_pool_t *, void *, size_t, size_t, int);
uvisor_pool_slot_t (*pool_allocate)(uvisor_pool_t *, uint32_t);
int (*pool_init)(uvisor_pool_t *, void *, size_t, size_t);
int (*pool_queue_init)(uvisor_pool_queue_t *, uvisor_pool_t *, void *, size_t, size_t);
uvisor_pool_slot_t (*pool_allocate)(uvisor_pool_t *);
void (*pool_queue_enqueue)(uvisor_pool_queue_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*pool_free)(uvisor_pool_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*pool_queue_dequeue)(uvisor_pool_queue_t *, uvisor_pool_slot_t);
uvisor_pool_slot_t (*pool_queue_dequeue_first)(uvisor_pool_queue_t *);
uvisor_pool_slot_t (*pool_queue_find_first)(uvisor_pool_queue_t *, TQueryFN_Ptr, void *);
void (*spin_init)(UvisorSpinlock * spinlock);
bool (*spin_trylock)(UvisorSpinlock * spinlock);
void (*spin_lock)(UvisorSpinlock * spinlock);
void (*spin_unlock)(UvisorSpinlock * spinlock);
OsEventObserver os_event_observer;
} UVISOR_PACKED UvisorApi;

View File

@ -22,15 +22,16 @@
#include "api/inc/rpc_exports.h"
#include <stddef.h>
#include <stdint.h>
#include <sys/reent.h>
UVISOR_EXTERN const uint32_t __uvisor_mode;
UVISOR_EXTERN void const * const public_box_cfg_ptr;
typedef struct {
void (*function)(const void *);
size_t priority;
size_t stack_size;
} uvisor_box_main_t;
/* All pointers in the box index need to be 4-byte aligned.
* We therefore also need to round up all sizes to 4-byte multiples to
* provide the space to be able to align the pointers to 4-bytes. */
#define __UVISOR_BOX_ROUND_4(size) \
(((size) + 3UL) & ~3UL)
#define UVISOR_DISABLED 0
#define UVISOR_PERMISSIVE 1
@ -53,7 +54,9 @@ typedef struct {
{ \
sizeof(RtxBoxIndex), \
0, \
0, \
sizeof(uvisor_rpc_t), \
sizeof(uvisor_ipc_t), \
0, \
}, \
0, \
@ -83,12 +86,13 @@ typedef struct {
UVISOR_STACK_SIZE_ROUND( \
( \
(UVISOR_MIN_STACK(stack_size) + \
(context_size) + \
(__uvisor_box_heapsize) + \
sizeof(RtxBoxIndex) + \
sizeof(uvisor_rpc_outgoing_message_queue_t) + \
sizeof(uvisor_rpc_incoming_message_queue_t) + \
sizeof(uvisor_rpc_fn_group_queue_t) \
__UVISOR_BOX_ROUND_4(context_size) + \
__UVISOR_BOX_ROUND_4(__uvisor_box_heapsize) + \
__UVISOR_BOX_ROUND_4(sizeof(RtxBoxIndex)) + \
__UVISOR_BOX_ROUND_4(sizeof(uvisor_rpc_outgoing_message_queue_t)) + \
__UVISOR_BOX_ROUND_4(sizeof(uvisor_rpc_incoming_message_queue_t)) + \
__UVISOR_BOX_ROUND_4(sizeof(uvisor_rpc_fn_group_queue_t)) + \
__UVISOR_BOX_ROUND_4(sizeof(struct _reent)) \
) \
* 8) \
/ 6)]; \
@ -99,7 +103,9 @@ typedef struct {
{ \
sizeof(RtxBoxIndex), \
context_size, \
sizeof(struct _reent), \
sizeof(uvisor_rpc_t), \
sizeof(uvisor_ipc_t), \
__uvisor_box_heapsize, \
}, \
UVISOR_MIN_STACK(stack_size), \

View File

@ -18,18 +18,37 @@
#define __UVISOR_API_NVIC_VIRTUAL_H__
#include "api/inc/interrupts.h"
#include "api/inc/unvic_exports.h"
#include "api/inc/virq_exports.h"
#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping
#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping
#define NVIC_EnableIRQ vIRQ_EnableIRQ
#define NVIC_DisableIRQ vIRQ_DisableIRQ
#define NVIC_GetPendingIRQ vIRQ_GetPendingIRQ
#define NVIC_SetPendingIRQ vIRQ_SetPendingIRQ
#define NVIC_ClearPendingIRQ vIRQ_ClearPendingIRQ
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority vIRQ_SetPriority
#define NVIC_GetPriority vIRQ_GetPriority
#define NVIC_SystemReset() vIRQ_SystemReset(RESET_REASON_NO_REASON)
/* The NVIC APIs are only wrapped on ARMv7-M. */
#if !defined(ARCH_CORE_ARMv8M) && !defined(TARGET_M33)
#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping
#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping
#define NVIC_EnableIRQ vIRQ_EnableIRQ
#define NVIC_DisableIRQ vIRQ_DisableIRQ
#define NVIC_GetPendingIRQ vIRQ_GetPendingIRQ
#define NVIC_SetPendingIRQ vIRQ_SetPendingIRQ
#define NVIC_ClearPendingIRQ vIRQ_ClearPendingIRQ
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority vIRQ_SetPriority
#define NVIC_GetPriority vIRQ_GetPriority
#define NVIC_SystemReset() vIRQ_SystemReset(RESET_REASON_NO_REASON)
#else
#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping
#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping
#define NVIC_EnableIRQ __NVIC_EnableIRQ
#define NVIC_DisableIRQ __NVIC_DisableIRQ
#define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ
#define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ
#define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ
#define NVIC_GetActive __NVIC_GetActive
#define NVIC_SetPriority __NVIC_SetPriority
#define NVIC_GetPriority __NVIC_GetPriority
#define NVIC_SystemReset() __NVIC_SystemReset()
#endif
#endif /* __UVISOR_API_NVIC_VIRTUAL_H__ */

View File

@ -19,7 +19,17 @@
#include "api/inc/interrupts.h"
#define NVIC_SetVector vIRQ_SetVector
#define NVIC_GetVector vIRQ_GetVector
/* The NVIC APIs are only wrapped on ARMv7-M. */
#if !defined(ARCH_CORE_ARMv8M) && !defined(TARGET_M33)
#define NVIC_SetVector vIRQ_SetVector
#define NVIC_GetVector vIRQ_GetVector
#else
#define NVIC_SetVector __NVIC_SetVector
#define NVIC_GetVector __NVIC_GetVector
#endif
#endif /* __UVISOR_API_VECTAB_VIRTUAL_H__ */

View File

@ -49,6 +49,7 @@ typedef enum {
FAULT_USAGE,
FAULT_HARD,
FAULT_DEBUG,
FAULT_SECURE,
__THALTERROR_MAX /* always keep as the last element of the enum */
} THaltError;

View File

@ -17,7 +17,7 @@
#ifndef __UVISOR_API_INTERRUPTS_H__
#define __UVISOR_API_INTERRUPTS_H__
#include "api/inc/unvic_exports.h"
#include "api/inc/virq_exports.h"
#include "api/inc/uvisor_exports.h"
#include "api/inc/api.h"
#include <stdint.h>

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2017, 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_IPC_H__
#define __UVISOR_API_IPC_H__
#include "api/inc/ipc_exports.h"
#include "api/inc/uvisor_exports.h"
#include <stdint.h>
#include <stddef.h>
/** Wait for any of the specified IPC operations to complete.
*
* @note This function currently spins, burning through power.
*
* @param[in] wait_tokens a bitfield of tokens to wait on
* @param[out] done_tokens a bitfield which tokens completed
* @param[in] timeout_ms how long to wait (in ms) for an IPC operation
* before returning. 0 means don't wait at all. Any
* other value means wait forever.
* @return 0 on success, non-zero error code otherwise
*/
UVISOR_EXTERN int ipc_waitforany(uint32_t wait_tokens, uint32_t * done_tokens, uint32_t timeout_ms);
/** Wait for all of the specified IPC operations to complete.
*
* @note This function currently spins, burning through power.
*
* @param[in] wait_tokens a bitfield of tokens to wait on
* @param[out] done_tokens a bitfield which tokens completed
* @param[in] timeout_ms how long to wait (in ms) for an IPC operation
* before returning. 0 means don't wait at all.
* Any other value means wait forever.
* @return 0 on success, non-zero error code otherwise
*/
UVISOR_EXTERN int ipc_waitforall(uint32_t wait_tokens, uint32_t * done_tokens, uint32_t timeout_ms);
/** Asynchronously send an IPC message
*
* @note The memory used for sending the message (pointed to by msg) must be
* valid until after the send is complete.
*
* @param[in] desc an IPC descriptor for the message
* @param[in] msg the message to send
*
* @return 0 on success, non-zero error code otherwise
* */
UVISOR_EXTERN int ipc_send(uvisor_ipc_desc_t * desc, const void * msg);
/** Asynchronously receive an IPC message
*
* @note The memory used for receiving the message (pointed to by msg) must be
* valid until after the receive is complete.
*
* @param[inout] desc an IPC descriptor for the message
* @param[out] msg the memory to copy the message to
*
* @return 0 on success, non-zero error code otherwise
*/
UVISOR_EXTERN int ipc_recv(uvisor_ipc_desc_t * desc, void * msg);
#endif /* __UVISOR_API_IPC_H__ */

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2017, 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_IPC_EXPORTS_H__
#define __UVISOR_API_IPC_EXPORTS_H__
#include "api/inc/pool_queue_exports.h"
#include "api/inc/uvisor_spinlock_exports.h"
#include "api/inc/vmpu_exports.h"
#include <stddef.h>
/* Use the invalid box ID to mean "receive from any" box. */
#define UVISOR_BOX_ID_ANY UVISOR_BOX_ID_INVALID
#define UVISOR_IPC_SEND_SLOTS 16
#define UVISOR_IPC_RECV_SLOTS 16
/* The value UVISOR_IPC_INVALID_TOKEN is defined to should be useful as a null
* token, and preferably not having any other legitimate use. Due to the
* internal bitfield representation of tokens, it makes a lot of sense to use 0
* as the null token. ipc_allocate_token() returns 0 if no tokens are
* available. Freeing 0 bits means nothing ('&= ~0' is a no-op). No other value
* makes as much sense to use as 0. If tokens become represented internally as
* something other than a bitfield, it would make sense to reconsider the value
* used here. */
#define UVISOR_IPC_INVALID_TOKEN 0
typedef enum uvisor_ipc_io_state {
UVISOR_IPC_IO_STATE_INVALID,
UVISOR_IPC_IO_STATE_IDLE,
UVISOR_IPC_IO_STATE_READY_TO_SEND, /* Enqueued and waiting for delivery */
UVISOR_IPC_IO_STATE_READY_TO_RECV, /* Enqueued and waiting for delivery */
UVISOR_IPC_IO_STATE_VALID, /* uVisor has copied the message */
} uvisor_ipc_io_state_t;
/* IPC Descriptor Structure */
/* When sending:
* @param[in] box_id the ID of the destination box
* @param[in] port the port to send the message to
* @param[in] len the length of the message
* @param[out] token a token that can be used to wait at a later time for
* the send to complete
*/
/* When receiving before a message has been received:
* @param[in] box_id an ID of a box that is allowed to send to this box, or
* UVISOR_BOX_ID_ANY to allow messages from any box
* @param[in] port the port to listen for messages on
* @param[in] len the maximum length of message to receive
* @param[out] token a token that can be used to wait at a later time for
* the recv to complete
*
* When receiving after a message has been received:
* @param[out] box_id the box ID of the sender
* @param[out] port the port the message arrived on
* @param[out] len the length of the message
* @param[out] token not modified
*/
typedef struct uvisor_ipc_desc {
int box_id;
size_t port;
size_t len;
uint32_t token;
} uvisor_ipc_desc_t;
/* IPC IO Request Structure */
typedef struct uvisor_ipc_io {
uvisor_ipc_desc_t * desc;
void * msg;
uvisor_ipc_io_state_t state;
} uvisor_ipc_io_t;
#define UVISOR_IPC_SEND_TYPE(slots) \
struct { \
uvisor_pool_queue_t queue; \
uvisor_pool_t pool; \
uvisor_pool_queue_entry_t entries[slots]; \
uvisor_ipc_io_t io[slots]; \
}
#define UVISOR_IPC_RECV_TYPE(slots) \
struct { \
uvisor_pool_queue_t queue; \
uvisor_pool_t pool; \
uvisor_pool_queue_entry_t entries[slots]; \
uvisor_ipc_io_t io[slots]; \
}
typedef UVISOR_IPC_SEND_TYPE(UVISOR_IPC_SEND_SLOTS) uvisor_ipc_send_queue_t;
typedef UVISOR_IPC_RECV_TYPE(UVISOR_IPC_RECV_SLOTS) uvisor_ipc_recv_queue_t;
typedef struct uvisor_ipc {
uvisor_ipc_send_queue_t send_queue;
uvisor_ipc_recv_queue_t recv_queue;
UvisorSpinlock tokens_lock; /* Protect access to tokens. */
uint32_t allocated_tokens; /* Endpoints read and write. */
uint32_t completed_tokens; /* uVisor and endpoints read and write. */
} uvisor_ipc_t;
static inline uvisor_ipc_t * uvisor_ipc(UvisorBoxIndex * const index)
{
return (uvisor_ipc_t *) index->bss.address_of.ipc;
}
#endif

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017, 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_LINKER_EXPORTS_H__
#define __UVISOR_API_LINKER_EXPORTS_H__
/* FIXME Consider supporting other aliasing schemes. This is dependent on the
* IDAU implementation. Not all aliasing is guaranteed to work the same way. We
* currently only support a 1-bit MSB IDAU. */
#if defined (ARCH_CORE_ARMv8M) || defined (TARGET_M33)
# define SECURE_ALIAS_OFFSET 0x10000000
#else
# define SECURE_ALIAS_OFFSET 0
#endif
/** @returns the non-secure alias of the input address. */
#define UVISOR_GET_NS_ALIAS(addr) ((typeof(addr)) ((uint32_t) (addr) & ~SECURE_ALIAS_OFFSET))
/** @returns the secure alias of the input address. */
#define UVISOR_GET_S_ALIAS(addr) ((typeof(addr)) ((uint32_t) (addr) | SECURE_ALIAS_OFFSET))
/** @returns `true` if address is a secure alias. */
#define UVISOR_IS_S_ALIAS(addr) ((uint32_t) (addr) & SECURE_ALIAS_OFFSET)
/** @returns an address targeting the non-secure state. */
#define UVISOR_GET_NS_ADDRESS(addr) ((addr) & ~1UL)
/** @returns the secure alias of the input address for uVisor core builds, and
* the non-secure alias for non-uVisor core builds.
* This is useful for code shared across secure and non-secure aliases. */
#if UVISOR_CORE_BUILD
#define UVISOR_AUTO_ALIAS(addr) UVISOR_GET_S_ALIAS(addr)
#else
#define UVISOR_AUTO_ALIAS(addr) UVISOR_GET_NS_ALIAS(addr)
#endif
/** @returns the secure alias of the input address for uVisor core builds, and
* assumes the addr supplied is already a non-secure alias for non-uVisor core builds.
* This is useful for code shared across secure and non-secure aliases. */
#if UVISOR_CORE_BUILD
#define UVISOR_AUTO_NS_ALIAS(addr) UVISOR_GET_S_ALIAS(addr)
#else
#define UVISOR_AUTO_NS_ALIAS(addr) addr
#endif
#endif

View File

@ -68,12 +68,6 @@ typedef struct uvisor_pool {
/* 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;
@ -81,9 +75,6 @@ typedef struct uvisor_pool {
/* 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;
@ -108,20 +99,17 @@ typedef struct uvisor_pool_queue {
/* 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);
UVISOR_EXTERN int uvisor_pool_init(uvisor_pool_t * pool, void * array, size_t stride, size_t num);
/* 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);
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);
/* 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);
/* Allocate a slot from the pool. 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 there is no 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);
/* 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);
@ -142,6 +130,7 @@ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_try_free(uvisor_pool_t * pool, uvis
* 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_try_dequeue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot);
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
@ -156,15 +145,17 @@ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_dequeue_first(uvisor_pool
* 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_try_find_first(uvisor_pool_queue_t * pool_queue,
TQueryFN_Ptr query_fn, 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)
static inline uvisor_pool_slot_t uvisor_pool_queue_allocate(uvisor_pool_queue_t * pool_queue)
{
return uvisor_pool_allocate(pool_queue->pool, timeout_ms);
return uvisor_pool_allocate(pool_queue->pool);
}
static inline uvisor_pool_slot_t uvisor_pool_queue_try_allocate(uvisor_pool_queue_t * pool_queue)

View File

@ -34,6 +34,7 @@
#include "api/inc/interrupts.h"
#include "api/inc/register_gateway.h"
#include "api/inc/rpc.h"
#include "api/inc/ipc.h"
#include "api/inc/rpc_gateway.h"
#include "api/inc/secure_access.h"
#include "api/inc/uvisor_semaphore.h"
@ -45,10 +46,14 @@
#endif /* defined(UVISOR_PRESENT) && UVISOR_PRESENT == 1 */
/* The host startup needs to call this after osKernelInitialize to initialize
* uvisor-lib. The function can fail. It's up the the host startup to decide
* what to do with any failures. */
UVISOR_EXTERN int uvisor_lib_init(void);
/* On ARMv7-M, the host startup needs to call this after osKernelInitialize to
* initialize uvisor-lib. The function can fail. It's up the the host startup
* to decide what to do with any failures. */
UVISOR_EXTERN int uvisor_lib_init(void); /* FIXME: Remove this when we move ARMv7-M to the hypervisor model. */
/* The host startup needs to call this after osKernelInitialize to start
* uVisor. The function will halt if errors are encountered. */
UVISOR_EXTERN void uvisor_start(void);
#include "api/inc/page_allocator.h"
@ -60,8 +65,8 @@ UVISOR_EXTERN int uvisor_lib_init(void);
#include "api/inc/halt_exports.h"
#include "api/inc/register_gateway_exports.h"
#include "api/inc/rpc_gateway_exports.h"
#include "api/inc/priv_sys_hook_exports.h"
#include "api/inc/unvic_exports.h"
#include "api/inc/priv_sys_hooks_exports.h"
#include "api/inc/virq_exports.h"
#include "api/inc/uvisor_exports.h"
#include "api/inc/vmpu_exports.h"
#include "api/inc/page_allocator_exports.h"

View File

@ -18,6 +18,7 @@
#define __UVISOR_API_UVISOR_EXPORTS_H__
#include <stdint.h>
#include <stddef.h>
/* maximum number of boxes allowed: 1 is the minimum (unprivileged box) */
#define UVISOR_MAX_BOXES 5U
@ -190,4 +191,10 @@
#endif /* defined(__CC_ARM) || defined(__GNUC__) */
typedef struct {
void (*function)(const void *);
size_t priority;
size_t stack_size;
} uvisor_box_main_t;
#endif /* __UVISOR_API_UVISOR_EXPORTS_H__ */

View File

@ -24,4 +24,19 @@ typedef struct {
bool acquired;
} UvisorSpinlock;
/* This function is safe to call from interrupt context. */
UVISOR_EXTERN void uvisor_spin_init(UvisorSpinlock * spinlock);
/* Attempt to spin lock once. Return true if the lock was obtained, false if
* otherwise. This function is safe to call from interrupt context. */
UVISOR_EXTERN bool uvisor_spin_trylock(UvisorSpinlock * spinlock);
/* Spin in a tight loop until the lock is obtained. This function is safe to
* call from interrupt context, but probably not wise. */
UVISOR_EXTERN void uvisor_spin_lock(UvisorSpinlock * spinlock);
/* Unlock the spin lock. This function is safe to call from interrupt context.
* */
UVISOR_EXTERN void uvisor_spin_unlock(UvisorSpinlock * spinlock);
#endif /* __UVISOR_API_UVISOR_SPINLOCK_H__ */

View File

@ -116,7 +116,7 @@
#define UVISOR_REGION_ROUND_DOWN(x) ((x) & ~((1UL << UVISOR_REGION_BITS(x)) - 1))
#define UVISOR_REGION_ROUND_UP(x) (1UL << UVISOR_REGION_BITS(x))
#define UVISOR_STACK_SIZE_ROUND(x) UVISOR_REGION_ROUND_UP(x)
#elif defined(ARCH_MPU_KINETIS)
#elif defined(ARCH_MPU_ARMv8M) || defined(ARCH_MPU_KINETIS)
#define UVISOR_REGION_ROUND_DOWN(x) UVISOR_ROUND32_DOWN(x)
#define UVISOR_REGION_ROUND_UP(x) UVISOR_ROUND32_UP(x)
#define UVISOR_STACK_SIZE_ROUND(x) UVISOR_REGION_ROUND_UP((x) + (UVISOR_STACK_BAND_SIZE * 2))
@ -157,7 +157,9 @@ typedef struct {
typedef struct uvisor_bss_sections_t {
uint32_t index;
uint32_t context;
uint32_t newlib_reent;
uint32_t rpc;
uint32_t ipc;
uint32_t heap;
} UVISOR_PACKED UvisorBssSections;

View File

@ -22,6 +22,7 @@
#include "mbed_interface.h"
#include "cmsis_os2.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* Register the OS with uVisor */
@ -36,6 +37,11 @@ extern RtxBoxIndex * const __uvisor_ps;
void __uvisor_initialize_rpc_queues(void)
{
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
// TODO Initialize RPC queues on ARMv8-M (via uvisor_start).
return;
#endif
UvisorBoxIndex * const index = &__uvisor_ps->index;
uvisor_pool_slot_t i;
@ -49,8 +55,7 @@ void __uvisor_initialize_rpc_queues(void)
&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_RPC_OUTGOING_MESSAGE_SLOTS)) {
uvisor_error(USER_NOT_ALLOWED);
}
@ -67,8 +72,7 @@ void __uvisor_initialize_rpc_queues(void)
&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_RPC_INCOMING_MESSAGE_SLOTS)) {
uvisor_error(USER_NOT_ALLOWED);
}
/* This is a double init of the pool. We need a function that just inits
@ -77,8 +81,7 @@ void __uvisor_initialize_rpc_queues(void)
&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_RPC_INCOMING_MESSAGE_SLOTS)) {
uvisor_error(USER_NOT_ALLOWED);
}
@ -87,8 +90,7 @@ void __uvisor_initialize_rpc_queues(void)
&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_RPC_FN_GROUP_SLOTS)) {
uvisor_error(USER_NOT_ALLOWED);
}
@ -119,20 +121,18 @@ void __uvisor_lib_box_init(void * lib_config)
* is because the thread must be created to use a different stack than the
* stack osCreateThread() is called from, as context information is saved
* to the thread stack by the call to osCreateThread(). */
/* Allocate memory for the main thread from the process heap (which is
* private to the process). This memory is never freed, even if the box's
* main thread exits. */
thread_attr.stack_mem = malloc_p(thread_attr.stack_size);
/* Allocate memory for the main thread from the box heap. This memory is
* never freed, even if the box's main thread exits. */
thread_attr.stack_mem = malloc(thread_attr.stack_size);
if (thread_attr.stack_mem == NULL) {
/* No process heap memory available for thread stack */
uvisor_error(USER_NOT_ALLOWED);
}
/* Allocate memory for the main thread control block from the process heap
* (which is private to the process). This memory is never freed, even if
* the box's main thread exits. */
/* Allocate memory for the main thread control block from the box heap.
* This memory is never freed, even if the box's main thread exits. */
thread_attr.cb_size = sizeof(osRtxThread_t);
thread_attr.cb_mem = malloc_p(thread_attr.cb_size);
thread_attr.cb_mem = malloc(thread_attr.cb_size);
if (thread_attr.cb_mem == NULL) {
/* No process heap memory available for thread control block. */
uvisor_error(USER_NOT_ALLOWED);

View File

@ -23,12 +23,13 @@
#include <stdio.h>
#include <reent.h>
#define OP_MALLOC 0
#define OP_REALLOC 1
#define OP_FREE 2
#define HEAP_ACTIVE 0
#define HEAP_PROCESS 1
/*
* These are the C standard memory functions:
* - void *calloc(size_t nmemb, size_t size);
* - void free(void *ptr);
* - void *malloc(size_t size);
* - void *realloc(void *ptr, size_t size);
*/
/* Use printf with caution inside malloc: printf may allocate memory itself,
so using printf in malloc may lead to recursive calls! */
@ -40,6 +41,14 @@ extern RtxBoxIndex * const __uvisor_ps;
* @retval 1 The kernel is initialized.. */
static int is_kernel_initialized()
{
/* TODO: Bare-bone boxes must not call any RTX2 functions for now.
* Each box should instead provide `heap_lock` and `heap_unlock` functions
* as part of the box context. These would just be empty for boxes without
* the need for heap locking. */
if (__uvisor_ps->index.box_id_self != 0) {
return 0;
}
static uint8_t kernel_running = 0;
if (kernel_running) {
return 1;
@ -106,7 +115,16 @@ static int init_allocator()
return ret;
}
static void * memory(void * ptr, size_t size, int heap, int operation)
typedef enum {
MEMOP_MALLOC,
MEMOP_MEMALIGN,
MEMOP_CALLOC,
MEMOP_REALLOC,
MEMOP_FREE
} MemoryOperation;
static void * memory(MemoryOperation operation, uint32_t * args)
{
/* Buffer the return value. */
void * ret = NULL;
@ -115,12 +133,8 @@ static void * memory(void * ptr, size_t size, int heap, int operation)
return NULL;
}
/* Check if we need to aquire the mutex. */
int mutexed = is_kernel_initialized() &&
((heap == HEAP_PROCESS) ||
(void *) __uvisor_ps->index.bss.address_of.heap == __uvisor_ps->index.active_heap);
void * allocator = (heap == HEAP_PROCESS) ?
((void *) __uvisor_ps->index.bss.address_of.heap) :
(__uvisor_ps->index.active_heap);
int mutexed = is_kernel_initialized();
void * allocator = __uvisor_ps->index.active_heap;
/* Aquire the mutex if required.
* TODO: Mutex use is very coarse here. It may be sufficient to guard
@ -132,14 +146,20 @@ static void * memory(void * ptr, size_t size, int heap, int operation)
/* Perform the required operation. */
switch(operation)
{
case OP_MALLOC:
ret = secure_malloc(allocator, size);
case MEMOP_MALLOC:
ret = secure_malloc(allocator, (size_t) args[0]);
break;
case OP_REALLOC:
ret = secure_realloc(allocator, ptr, size);
case MEMOP_MEMALIGN:
ret = secure_aligned_alloc(allocator, (size_t) args[0], (size_t) args[1]);
break;
case OP_FREE:
secure_free(allocator, ptr);
case MEMOP_CALLOC:
ret = secure_calloc(allocator, (size_t) args[0], (size_t) args[1]);
break;
case MEMOP_REALLOC:
ret = secure_realloc(allocator, (void *) args[0], (size_t) args[1]);
break;
case MEMOP_FREE:
secure_free(allocator, (void *) args[0]);
break;
default:
break;
@ -152,42 +172,36 @@ static void * memory(void * ptr, size_t size, int heap, int operation)
}
/* Wrapped memory management functions. */
#if defined (__CC_ARM)
void * $Sub$$_malloc_r(struct _reent * r, size_t size) {
return memory(r, size, HEAP_ACTIVE, OP_MALLOC);
}
void * $Sub$$_realloc_r(struct _reent * r, void * ptr, size_t size) {
(void)r;
return memory(ptr, size, HEAP_ACTIVE, OP_REALLOC);
}
void $Sub$$_free_r(struct _reent * r, void * ptr) {
(void)r;
memory(ptr, 0, HEAP_ACTIVE, OP_FREE);
}
#elif defined (__GNUC__)
#if defined (__GNUC__)
void * __wrap__malloc_r(struct _reent * r, size_t size) {
return memory(r, size, HEAP_ACTIVE, OP_MALLOC);
(void) r;
return memory(MEMOP_MALLOC, (uint32_t *) &size);
}
void * __wrap__memalign_r(struct _reent * r, size_t alignment, size_t bytes) {
(void) r;
uint32_t args[2] = {(uint32_t) alignment, (uint32_t) bytes};
return memory(MEMOP_MEMALIGN, args);
}
void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size) {
(void) r;
uint32_t args[2] = {(uint32_t) nmemb, (uint32_t) size};
return memory(MEMOP_CALLOC, args);
}
void * __wrap__realloc_r(struct _reent * r, void * ptr, size_t size) {
(void)r;
return memory(ptr, size, HEAP_ACTIVE, OP_REALLOC);
(void) r;
uint32_t args[2] = {(uint32_t) ptr, (uint32_t) size};
return memory(MEMOP_REALLOC, args);
}
void __wrap__free_r(struct _reent * r, void * ptr) {
(void)r;
memory(ptr, 0, HEAP_ACTIVE, OP_FREE);
(void) r;
memory(MEMOP_FREE, (uint32_t *) &ptr);
}
#elif defined (__CC_ARM)
/* TODO: Find out how to do function wrapping for ARMCC. See microlib libc. */
# warning "Using uVisor allocator is not available for ARMCC. Falling back to default allocator."
#elif defined (__ICCARM__)
/* TODO: Find out how to do function wrapping for IARCC. */
/* TODO: newlib allocator is not thread-safe! */
# warning "Using uVisor allocator is not available for IARCC. Falling back to newlib allocator."
# warning "Using uVisor allocator is not available for IARCC. Falling back to default allocator."
#endif
void * malloc_p(size_t size) {
return memory(NULL, size, HEAP_PROCESS, OP_MALLOC);
}
void * realloc_p(void * ptr, size_t size) {
return memory(ptr, size, HEAP_PROCESS, OP_REALLOC);
}
void free_p(void * ptr) {
memory(ptr, 0, HEAP_PROCESS, OP_FREE);
}

View File

@ -205,6 +205,40 @@ void * secure_malloc(
return NULL;
}
void * secure_aligned_alloc(
SecureAllocator allocator,
size_t alignment,
size_t size)
{
/* Alignment must be a power of two! */
if (alignment & ((1UL << ((31UL - __builtin_clz(alignment)) - 1)))) {
return NULL;
}
/* TODO: THIS IS A NAIVE IMPLEMENTATION, which wastes much memory. */
void * ptr = secure_malloc(allocator, size + alignment - 1);
if (ptr == NULL) {
return NULL;
}
return (void *) (((uint32_t) ptr + alignment - 1) & ~(alignment - 1));
}
void * secure_calloc(
SecureAllocator allocator,
size_t nmemb,
size_t size)
{
if ((uint64_t) nmemb * size > SIZE_MAX) {
/* (size * nmemb) has overflowed. */
return NULL;
}
void * ptr = secure_malloc(allocator, size * nmemb);
if (ptr == NULL) {
return NULL;
}
memset(ptr, 0, size * nmemb);
return ptr;
}
void * secure_realloc(
SecureAllocator allocator,
void * ptr,

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2017, 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.
*/
#include "tz_context.h"
#include <stdint.h>
/* Provide do-nothing stubs for RTX's trustzone context saving hooks. uVisor
* doesn't use these on ARMv8-M. */
uint32_t TZ_InitContextSystem_S(void) {
return 1; /* Success */
}
TZ_MemoryId_t TZ_AllocModuleContext_S(TZ_ModuleId_t module) {
return 1; /* Always hand out slot 1. */
}
uint32_t TZ_FreeModuleContext_S(TZ_MemoryId_t id) {
return 1; /* Success */
}
uint32_t TZ_LoadContext_S(TZ_MemoryId_t id) {
return 1; /* Success */
}
uint32_t TZ_StoreContext_S(TZ_MemoryId_t id) {
return 1; /* Success */
}

View File

@ -54,7 +54,7 @@ int uvisor_page_free(const UvisorPageTable *const table)
static osMutexId_t g_page_allocator_mutex_id = NULL;
static osRtxMutex_t g_page_allocator_mutex_data;
static osMutexDef_t g_page_allocator_mutex_attr = {
.name = "uvisor_page_alloc_mutex",
.name = "uvisor_malloc_mutex",
.attr_bits = 0, /* Non-recursive */
.cb_mem = &g_page_allocator_mutex_data,
.cb_size = sizeof(g_page_allocator_mutex_data)

View File

@ -19,6 +19,7 @@ int __uvisor_semaphore_init(UvisorSemaphore * s, uint32_t max_count, uint32_t in
memset(&semaphore->data, 0, sizeof(semaphore->data));
memset(&semaphore->attr, 0, sizeof(semaphore->attr));
semaphore->attr.name = "uvisor_semaphore";
semaphore->attr.cb_size = sizeof(semaphore->data);
semaphore->attr.cb_mem = &semaphore->data;
semaphore->id = osSemaphoreNew(max_count, initial_count, &semaphore->attr);

View File

@ -80,6 +80,7 @@ void mbed_stats_heap_get(mbed_stats_heap_t *stats)
extern "C" {
void * __real__malloc_r(struct _reent * r, size_t size);
void * __real__memalign_r(struct _reent * r, size_t alignment, size_t bytes);
void * __real__realloc_r(struct _reent * r, void * ptr, size_t size);
void __real__free_r(struct _reent * r, void * ptr);
void* __real__calloc_r(struct _reent * r, size_t nmemb, size_t size);
@ -178,8 +179,6 @@ extern "C" void __wrap__free_r(struct _reent * r, void * ptr) {
#endif // #ifdef MBED_MEM_TRACING_ENABLED
}
#endif // if !defined(FEATURE_UVISOR)
extern "C" void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size) {
void *ptr = NULL;
#ifdef MBED_HEAP_STATS_ENABLED
@ -200,6 +199,12 @@ extern "C" void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size)
return ptr;
}
extern "C" void * __wrap__memalign_r(struct _reent * r, size_t alignment, size_t bytes) {
return __real__memalign_r(r, alignment, bytes);
}
#endif // if !defined(FEATURE_UVISOR)
/******************************************************************************/
/* ARMCC memory allocation wrappers */

View File

@ -73,12 +73,27 @@ SVC_ContextSave:
STR R12,[R1,#TCB_SP_OFS] // Store SP
SVC_ContextSwitch:
#ifdef FEATURE_UVISOR
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
#endif
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
* the stack we save them onto is likely to be inaccessible after the
* call to thread_switch_helper). So, we just re-obtain the values from
* osRtxInfo again. */
BL thread_switch_helper
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
STR R2,[R3] // osRtxInfo.thread.run: curr = next
SVC_ContextRestore:
LDR R0,[R2,#TCB_SP_OFS] // Load SP
LDMIA R0!,{R4-R11} // Restore R4..R11
MSR PSP,R0 // Set PSP
#ifdef FEATURE_UVISOR
CPSIE I // The PSP has been set. Re-enable interrupts.
#endif
MVN LR,#~0xFFFFFFFD // Set EXC_RETURN value
SVC_Exit:

View File

@ -91,6 +91,18 @@ SVC_ContextSave:
STRB LR, [R1,#TCB_SF_OFS] // Store stack frame information
SVC_ContextSwitch:
#ifdef FEATURE_UVISOR
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
#endif
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
* the stack we save them onto is likely to be inaccessible after the
* call to thread_switch_helper). So, we just re-obtain the values from
* osRtxInfo again. */
BL thread_switch_helper
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
STR R2,[R3] // osRtxInfo.thread.run: curr = next
SVC_ContextRestore:
@ -105,6 +117,9 @@ SVC_ContextRestore:
#endif
LDMIA R0!,{R4-R11} // Restore R4..R11
MSR PSP,R0 // Set PSP
#ifdef FEATURE_UVISOR
CPSIE I // The PSP has been set. Re-enable interrupts.
#endif
SVC_Exit:
BX LR // Exit from handler

View File

@ -426,9 +426,12 @@ void osRtxThreadSwitch (os_thread_t *thread) {
osRtxInfo.thread.run.next = thread;
osRtxThreadStackCheck();
EvrRtxThreadSwitch(thread);
}
/// Notify the OS event observer of an imminent thread switch.
void thread_switch_helper(void) {
if (osEventObs && osEventObs->thread_switch) {
osEventObs->thread_switch(thread->context);
osEventObs->thread_switch(osRtxInfo.thread.run.next->context);
}
}

View File

@ -11,7 +11,7 @@
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r", "-Wl,--wrap,_memalign_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit",
"-Wl,-n"]
},

View File

@ -10,7 +10,7 @@
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r", "-Wl,--wrap,_memalign_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit",
"-Wl,-n"]
},

View File

@ -10,7 +10,7 @@
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r", "-Wl,--wrap,_memalign_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit",
"-Wl,-n"]
},