diff options
author | Ken Liu <ken.liu@arm.com> | 2018-09-20 22:42:31 +0800 |
---|---|---|
committer | Edison Ai <edison.ai@arm.com> | 2019-01-22 10:39:24 +0800 |
commit | 91d44da94e906430c72d6907d77a86d10e1a77c0 (patch) | |
tree | 3d41679a730ca1ae35a483d5f066f53c8be01142 | |
parent | f09acd4ac3593bf7dbaba846e44ebc02b6525813 (diff) | |
download | trusted-firmware-m-91d44da94e906430c72d6907d77a86d10e1a77c0.tar.gz |
Core: Fundamental components for secure IPC
This patch provides Thread, Wait and ARCH related APIs
for PSA secure IPC implementation.
Change-Id: I338cd82563d20d75db4fd60441896f76dc85c6e2
Signed-off-by: Ken Liu <ken.liu@arm.com>
-rw-r--r-- | secure_fw/core/ipc/CMakeLists.inc | 4 | ||||
-rw-r--r-- | secure_fw/core/ipc/include/tfm_arch_v8m.h | 66 | ||||
-rw-r--r-- | secure_fw/core/ipc/include/tfm_thread.h | 223 | ||||
-rw-r--r-- | secure_fw/core/ipc/include/tfm_utils.h | 23 | ||||
-rw-r--r-- | secure_fw/core/ipc/include/tfm_wait.h | 86 | ||||
-rw-r--r-- | secure_fw/core/ipc/tfm_arch_v8m.c | 124 | ||||
-rw-r--r-- | secure_fw/core/ipc/tfm_thread.c | 195 | ||||
-rw-r--r-- | secure_fw/core/ipc/tfm_utils.c | 15 | ||||
-rw-r--r-- | secure_fw/core/ipc/tfm_wait.c | 62 |
9 files changed, 798 insertions, 0 deletions
diff --git a/secure_fw/core/ipc/CMakeLists.inc b/secure_fw/core/ipc/CMakeLists.inc index 87437ae63c..ff8e633b58 100644 --- a/secure_fw/core/ipc/CMakeLists.inc +++ b/secure_fw/core/ipc/CMakeLists.inc @@ -36,6 +36,10 @@ elseif (TFM_PSA_API) set (SS_IPC_C_SRC "${SS_IPC_DIR}/tfm_svcalls.c" "${SS_IPC_DIR}/psa_service.c" "${SS_IPC_DIR}/psa_client.c" + "${SS_IPC_DIR}/tfm_arch_v8m.c" + "${SS_IPC_DIR}/tfm_thread.c" + "${SS_IPC_DIR}/tfm_wait.c" + "${SS_IPC_DIR}/tfm_utils.c" "${SS_IPC_DIR}/../tfm_core.c" "${SS_IPC_DIR}/../tfm_secure_api.c" "${SS_IPC_DIR}/../tfm_spm_services.c" diff --git a/secure_fw/core/ipc/include/tfm_arch_v8m.h b/secure_fw/core/ipc/include/tfm_arch_v8m.h new file mode 100644 index 0000000000..96914c0746 --- /dev/null +++ b/secure_fw/core/ipc/include/tfm_arch_v8m.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_ARCH_V8M_H__ +#define __TFM_ARCH_V8M_H__ + +#include "cmsis.h" + +#define XPSR_T32 0x01000000 +#define LR_UNPRIVILEGED 0xfffffffd + +/* This header file collects the ARCH related operations. */ +struct tfm_state_context_base { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t ra_lr; + uint32_t ra; + uint32_t xpsr; +}; + +struct tfm_state_context_ext { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t sp; + uint32_t sp_limit; + uint32_t dummy; + uint32_t lr; +}; + +struct tfm_state_context { + struct tfm_state_context_ext ctxb; +}; + +#define TFM_STATE_1ST_ARG(ctx) \ + (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0) +#define TFM_STATE_2ND_ARG(ctx) \ + (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r1) +#define TFM_STATE_3RD_ARG(ctx) \ + (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r2) +#define TFM_STATE_4TH_ARG(ctx) \ + (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r3) +#define TFM_STATE_RET_VAL(ctx) \ + (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0) + +__STATIC_INLINE void tfm_trigger_pendsv(void) +{ + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void tfm_initialize_context(struct tfm_state_context *ctx, + uint32_t r0, uint32_t ra, + uint32_t sp, uint32_t sp_limit); + +#endif diff --git a/secure_fw/core/ipc/include/tfm_thread.h b/secure_fw/core/ipc/include/tfm_thread.h new file mode 100644 index 0000000000..8a6d86364d --- /dev/null +++ b/secure_fw/core/ipc/include/tfm_thread.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_THREAD_H__ +#define __TFM_THREAD_H__ + +#include "tfm_arch_v8m.h" +#include "cmsis_compiler.h" + +/* Status code */ +#define THRD_STAT_CREATING 0 +#define THRD_STAT_RUNNING 1 +#define THRD_STAT_BLOCK 2 +#define THRD_STAT_DETACH 3 +#define THRD_STAT_INVALID 4 + +/* Security attribute - default as security */ +#define THRD_ATTR_SECURE_OFFSET 16 +#define THRD_ATTR_SECURE (0) +#define THRD_ATTR_NON_SECURE (1 << THRD_ATTR_SECURE_OFFSET) + +/* Lower value has higher priority */ +#define THRD_PRIOR_MASK 0xFF +#define THRD_PRIOR_HIGHEST 0x0 +#define THRD_PRIOR_MEDIUM 0x7F +#define THRD_PRIOR_LOWEST 0xFF + +/* Error code */ +#define THRD_SUCCESS 0 +#define THRD_ERR_INVALID_PARAM 1 + +/* Thread entry function type */ +typedef void *(*tfm_thrd_func_t)(void *); + +/* Thread context */ +struct tfm_thrd_ctx { + tfm_thrd_func_t pfn; /* entry function */ + void *param; /* entry parameter */ + uint8_t *sp_base; /* stack bottom */ + uint8_t *sp_top; /* stack top */ + uint32_t prior; /* priority */ + uint32_t status; /* status */ + + struct tfm_state_context state_ctx; /* State context */ + struct tfm_thrd_ctx *next; /* next thread in list */ +}; + +/* + * Initialize a thread context with the necessary info. + * + * Parameters : + * pth - pointer of caller provided thread context + * pfn - thread entry function + * param - thread entry function parameter + * sp_base - stack pointer base (higher address) + * sp_top - stack pointer top (lower address) + * + * Notes : + * Thread contex rely on caller allocated memory; initialize members in + * context. This function does not insert thread into schedulable list. + */ +void tfm_thrd_init(struct tfm_thrd_ctx *pth, + tfm_thrd_func_t pfn, void *param, + uint8_t *sp_base, uint8_t *sp_top); + +/* Set thread priority. + * + * Parameters : + * pth - pointer of thread context + * prior - priority value (0~255) + * + * Notes : + * Set thread priority. Priority is set to THRD_PRIOR_MEDIUM in + * tfm_thrd_init(). + */ +void __STATIC_INLINE tfm_thrd_priority(struct tfm_thrd_ctx *pth, + uint32_t prior) +{ + pth->prior &= ~THRD_PRIOR_MASK; + pth->prior |= prior & THRD_PRIOR_MASK; +} + +/* + * Set thread security attribute. + * + * Parameters : + * pth - pointer of thread context + * attr_secure - THRD_ATTR_SECURE or THRD_ATTR_NON_SECURE + * + * Notes + * Reuse prior of thread context to shift down non-secure thread priority. + */ +void __STATIC_INLINE tfm_thrd_secure(struct tfm_thrd_ctx *pth, + uint32_t attr_secure) +{ + pth->prior &= ~THRD_ATTR_NON_SECURE; + pth->prior |= attr_secure; +} + +/* + * Set thread status. + * + * Parameters : + * pth - pointer of thread context + * new_status - new status of thread + * + * Return : + * None + * + * Notes : + * Thread status is not changed if invalid status value inputed. + */ +void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status); + +/* + * Get thread status. + * + * Parameters : + * pth - pointer of thread context + * + * Return : + * Status of thread + */ +uint32_t __STATIC_INLINE tfm_thrd_get_status(struct tfm_thrd_ctx *pth) +{ + return pth->status; +} + +/* + * Set thread state return value. + * + * Parameters : + * pth - pointer of thread context + * retval - return value to be set for thread state + * + * Notes : + * This API is useful for blocked syscall blocking thread. Syscall + * could set its return value to the caller before caller goes. + */ +void __STATIC_INLINE tfm_thrd_set_retval(struct tfm_thrd_ctx *pth, + uint32_t retval) +{ + TFM_STATE_RET_VAL(&pth->state_ctx) = retval; +} + +/* + * Validate thread context and insert it into schedulable list. + * + * Parameters : + * pth - pointer of thread context + * + * Return : + * THRD_SUCCESS for success. Or an error is returned. + * + * Notes : + * This function validates thread info. It returns error if thread info + * is not correct. Thread is avaliable after successful tfm_thrd_start(). + */ +uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth); + +/* + * Get current running thread. + * + * Return : + * Current running thread context pointer. + */ +struct tfm_thrd_ctx *tfm_thrd_curr_thread(void); + +/* + * Get next running thread in list. + * + * Return : + * Pointer of next thread to be run. + */ +struct tfm_thrd_ctx *tfm_thrd_next_thread(void); + +/* + * Activate a scheduling action after exception. + * + * Notes : + * This function could be called multiple times before scheduling. + */ +void tfm_thrd_activate_schedule(void); + +/* + * Save current context into 'prev' thread and switch to 'next'. + * + * Parameters : + * ctxb - latest caller context + * prev - previous thread to be switched out + * next - thread to be run + * + * Notes : + * This function could be called multiple times before scheduling. + */ +void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb, + struct tfm_thrd_ctx *prev, + struct tfm_thrd_ctx *next); + +/* + * Exit current running thread. + * + * Notes : + * Remove current thread out of schedulable list. + */ +void tfm_thrd_do_exit(void); + +/* + * PendSV specified function. + * + * Parameters : + * ctxb - State context storage pointer + * + * Notes: + * This is a staging API. Scheduler should be called in SPM finally and + * this function will be obsoleted later. + */ +void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb); + +#endif diff --git a/secure_fw/core/ipc/include/tfm_utils.h b/secure_fw/core/ipc/include/tfm_utils.h new file mode 100644 index 0000000000..70707b887d --- /dev/null +++ b/secure_fw/core/ipc/include/tfm_utils.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_UTILS_H__ +#define __TFM_UTILS_H__ + +/* CPU spin here */ +void tfm_panic(void); + +/* Assert and spin */ +#define TFM_ASSERT(cond) \ + do { \ + if (!(cond)) { \ + printf("Assert:%s:%d", __FUNCTION__, __LINE__); \ + while (1) \ + ; \ + } \ + } while (0) + +#endif diff --git a/secure_fw/core/ipc/include/tfm_wait.h b/secure_fw/core/ipc/include/tfm_wait.h new file mode 100644 index 0000000000..2bed0aec3d --- /dev/null +++ b/secure_fw/core/ipc/include/tfm_wait.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_WAIT_H__ +#define __TFM_WAIT_H__ + +#include "cmsis_compiler.h" + +#define EVENT_MAGIC 0x65766e74 +#define EVENT_STAT_WAITED 0x0 +#define EVENT_STAT_SIGNALED 0x1 + +struct tfm_event_ctx { + uint32_t magic; /* 'evnt' */ + struct tfm_thrd_ctx *owner; /* waiting thread */ + uint32_t status; /* status */ + uint32_t retval; /* return value */ +}; + +/* + * Initialize an event context. + * + * Parameters : + * pevt - pointer of event context caller provided + * stat - initial status (EVENT_STAT_WAITED or EVENT_STAT_SIGNALED) + */ +void __STATIC_INLINE tfm_event_init(struct tfm_event_ctx *pevt, uint32_t stat) +{ + pevt->magic = EVENT_MAGIC; + pevt->status = stat; + pevt->owner = NULL; + pevt->retval = 0; +} + +/* + * Wait on an event. + * + * Parameters : + * pevt - pointer of event context + * + * Notes : + * Thread is blocked if event is not signaled. + */ +void tfm_event_wait(struct tfm_event_ctx *pevt); + +/* + * Signal an event. + * + * Parameters : + * pevt - pointer of event context + * + * Notes : + * Waiting thread on this event will be running. + */ +void tfm_event_signal(struct tfm_event_ctx *pevt); + +/* + * Peek an event status. + * + * Parameters : + * pevt - pointer of event context + * + * Return : + * Status of event. + * + * Notes : + * This function is used for getting event status without blocking thread. + */ +uint32_t tfm_event_peek(struct tfm_event_ctx *pevt); + +/* + * Set event owner return value. + * + * Parameters : + * pevt - pointer of event context + * retval - return value of blocked owner thread + * + * Notes : + * Thread return value is set while thread is to be running. + */ +void tfm_event_owner_retval(struct tfm_event_ctx *pevt, uint32_t retval); + +#endif diff --git a/secure_fw/core/ipc/tfm_arch_v8m.c b/secure_fw/core/ipc/tfm_arch_v8m.c new file mode 100644 index 0000000000..5c50636896 --- /dev/null +++ b/secure_fw/core/ipc/tfm_arch_v8m.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include <inttypes.h> +#include <stdio.h> + +#include "tfm_arch_v8m.h" +#include "cmsis.h" +#include "psa_client.h" +#include "psa_service.h" +#include "secure_utilities.h" +#include "tfm_utils.h" +#include "tfm_thread.h" + +/* This file contains the ARCH code for ARM V8M */ + +/* + * Thread exit zone. + * This function is set as the return address of thread entry and only + * privileged thread could return here. Un-privileged thread triggers + * fault if it tries to jump here and it gets exit by fault handler. + * + * The reason of putting this function here is for fault handler checking. + * Function address could be checked in fault handler to know it is a REAL + * thread exit or just an exception. + */ +static void exit_zone(void) +{ + tfm_thrd_do_exit(); +} + +void tfm_initialize_context(struct tfm_state_context *ctx, + uint32_t r0, uint32_t ra, + uint32_t sp, uint32_t sp_limit) +{ + /* + * For security consideration, set unused registers into ZERO; + * and only necessary registers are set here. + */ + struct tfm_state_context_base *p_ctxa = + (struct tfm_state_context_base *)sp; + + /* + * Shift back SP to leave space for holding base context + * since thread is kicked off through exception return. + */ + p_ctxa--; + + /* Basic context is considerate at thread start.*/ + tfm_memset(p_ctxa, 0, sizeof(*p_ctxa)); + p_ctxa->r0 = r0; + p_ctxa->ra = ra; + p_ctxa->ra_lr = (uint32_t)exit_zone; + p_ctxa->xpsr = XPSR_T32; + + tfm_memset(ctx, 0, sizeof(*ctx)); + ctx->ctxb.sp = (uint32_t)p_ctxa; + ctx->ctxb.sp_limit = sp_limit; + ctx->ctxb.lr = LR_UNPRIVILEGED; +} + +/* + * Stack status at PendSV entry: + * + * [ R0 - R3 ]<- PSP + * [ R12 ] + * [ LR_of_RA ] + * MSP->[ ........ ] [ RA ] + * [ ........ ] [ XPSR ] + * [ ........ ] + * [ ........ ] + * + * Stack status before calling pendsv_do_schedule(): + * + * MSP->[ R4 - R11 ] + * [ PSP ]--->[ R0 - R3 ] + * [ PSP Limit] [ R12 ] + * [ R2(dummy)] [ LR_of_RA ] + * [ LR ] [ RA ] + * [ ........ ] [ XPSR ] + * [ ........ ] [ ........ ] + * [ ........ ] + * + * pendsv_do_schedule() updates stacked context into current thread and + * replace stacked context with context of next thread. + * + * Scheduler does not support handler mode thread so take PSP/PSP_LIMIT as + * thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes + * aligned. + */ +__attribute__((naked)) void PendSV_Handler(void) +{ + __ASM( + "mrs r0, psp \n" + "mrs r1, psplim \n" + "push {r0, r1, r2, lr} \n" + "push {r4-r11} \n" + "mov r0, sp \n" + "bl tfm_pendsv_do_schedule \n" + "pop {r4-r11} \n" + "pop {r0, r1, r2, lr} \n" + "msr psp, r0 \n" + "msr psplim, r1 \n" + "bx lr \n" + ); +} + +/* Reserved for future usage */ +__attribute__((naked)) void MemManage_Handler(void) +{ + __ASM("b ."); +} + +__attribute__((naked)) void BusFault_Handler(void) +{ + __ASM("b ."); +} +__attribute__((naked)) void UsageFault_Handler(void) +{ + __ASM("b ."); +} diff --git a/secure_fw/core/ipc/tfm_thread.c b/secure_fw/core/ipc/tfm_thread.c new file mode 100644 index 0000000000..39f42ee234 --- /dev/null +++ b/secure_fw/core/ipc/tfm_thread.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include <inttypes.h> +#include <stdio.h> +#include "tfm_arch_v8m.h" +#include "tfm_thread.h" +#include "tfm_utils.h" +#include "secure_utilities.h" + +/* Force ZERO in case ZI(bss) clear is missing */ +static struct tfm_thrd_ctx *p_thrd_head = NULL; +static struct tfm_thrd_ctx *p_runn_head = NULL; +static struct tfm_thrd_ctx *p_curr_thrd = NULL; + +/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */ +#define LIST_HEAD p_thrd_head +#define RUNN_HEAD p_runn_head +#define CURR_THRD p_curr_thrd + +/* To get next running thread for scheduler */ +struct tfm_thrd_ctx *tfm_thrd_next_thread(void) +{ + struct tfm_thrd_ctx *pth = RUNN_HEAD; + + /* + * First RUNNING thread has highest priority since threads are sorted with + * priority. + */ + while (pth && pth->status != THRD_STAT_RUNNING) { + pth = pth->next; + } + + return pth; +} + +/* To get current thread for caller */ +struct tfm_thrd_ctx *tfm_thrd_curr_thread() +{ + return CURR_THRD; +} + +/* Insert a new thread into list by descending priority (Highest at head) */ +static void insert_by_prior(struct tfm_thrd_ctx **head, + struct tfm_thrd_ctx *node) +{ + if (*head == NULL || (node->prior <= (*head)->prior)) { + node->next = *head; + *head = node; + } else { + struct tfm_thrd_ctx *iter = *head; + + while (iter->next && (node->prior > iter->next->prior)) { + iter = iter->next; + } + node->next = iter->next; + iter->next = node; + } +} + +/* + * Set first running thread as head to reduce enumerate + * depth while searching for a first running thread. + */ +static void update_running_head(struct tfm_thrd_ctx **runn, + struct tfm_thrd_ctx *node) +{ + if ((node->status == THRD_STAT_RUNNING) && + (*runn == NULL || (node->prior <= (*runn)->prior))) { + *runn = node; + } else { + *runn = tfm_thrd_next_thread(); + } +} + +/* Set context members only. No validation here */ +void tfm_thrd_init(struct tfm_thrd_ctx *pth, + tfm_thrd_func_t pfn, void *param, + uint8_t *sp_base, uint8_t *sp_top) +{ + pth->prior = THRD_PRIOR_MEDIUM; + pth->status = THRD_STAT_CREATING; + pth->pfn = pfn; + pth->param = param; + pth->sp_base = sp_base; + pth->sp_top = sp_top; +} + +uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth) +{ + /* Validate parameters before really start */ + if ((pth->status != THRD_STAT_CREATING) || + (pth->pfn == NULL) || + (pth->sp_base == NULL) || + (pth->sp_top == NULL)) { + return THRD_ERR_INVALID_PARAM; + } + + /* Thread management runs in handler mode; set context for thread mode. */ + tfm_initialize_context(&pth->state_ctx, + (uint32_t)pth->param, (uint32_t)pth->pfn, + (uint32_t)pth->sp_base, (uint32_t)pth->sp_top); + + /* Insert a new thread with priority */ + insert_by_prior(&LIST_HEAD, pth); + + /* Mark it as RUNNING after insertion */ + tfm_thrd_set_status(pth, THRD_STAT_RUNNING); + + return THRD_SUCCESS; +} + +void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status) +{ + TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID); + + pth->status = new_status; + update_running_head(&RUNN_HEAD, pth); +} + +/* + * TEMP WORKAROUND: The caller function who called thread module init needs to + * be returned. The caller is not a thread. Create a dummy IDLE thread to + * collect caller context; and schedule back to the caller with this context + * after all other real threads blocked. + * + * This WORKAROUND needs to be removed after IPC NSPM takes place. + */ +#define DUMMY_IDLE_TAG 0xDEEDDEED +static uint8_t idle_stack[32] __attribute__((aligned(8))); +static struct tfm_thrd_ctx idle_thread; +static struct tfm_thrd_ctx *init_idle_thread(struct tfm_thrd_ctx *pth) +{ + /* + * IDLE thread is a thread with the lowest priority. + * It gets scheduled after all other higher priority threads get blocked. + * The entry of IDLE thread is a dummy and has no mean. + */ + tfm_thrd_init(pth, (tfm_thrd_func_t)DUMMY_IDLE_TAG, NULL, + (uint8_t *)&idle_stack[32], (uint8_t *)idle_stack); + tfm_thrd_priority(pth, THRD_PRIOR_LOWEST); + tfm_thrd_start(pth); + return pth; +} + +/* Scheduling won't happen immediately but after the exception returns */ +void tfm_thrd_activate_schedule(void) +{ + /* + * The current thread can be NULL only when initializing. Create the IDLE + * thread and set it as the current thread to collect caller context. + */ + if (CURR_THRD == NULL) { + CURR_THRD = init_idle_thread(&idle_thread); + } + + tfm_trigger_pendsv(); +} + +/* Remove current thread out of the schedulable list */ +void tfm_thrd_do_exit(void) +{ + CURR_THRD->status = THRD_STAT_DETACH; + tfm_trigger_pendsv(); +} + +void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb, + struct tfm_thrd_ctx *prev, + struct tfm_thrd_ctx *next) +{ + /* Update latest context into the current thread context */ + tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb)); + /* Update background context with next thread's context */ + tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb)); + /* Set current thread indicator with next thread */ + CURR_THRD = next; +} + +/* + * This function is a reference implementation for PendSV handler in + * isolation level 1. More jobs (sandboxing e.g.) need to be done while + * scheduling in other isolation levels. + */ +void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb) +{ + struct tfm_thrd_ctx *pth = tfm_thrd_next_thread(); + + /* Swith context if another thread ready to run */ + if (pth && pth != CURR_THRD) { + tfm_thrd_context_switch(ctxb, CURR_THRD, pth); + } +} diff --git a/secure_fw/core/ipc/tfm_utils.c b/secure_fw/core/ipc/tfm_utils.c new file mode 100644 index 0000000000..089f5b3810 --- /dev/null +++ b/secure_fw/core/ipc/tfm_utils.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include <inttypes.h> +#include <stdio.h> +#include "tfm_utils.h" + +void tfm_panic(void) +{ + while (1) + ; +} diff --git a/secure_fw/core/ipc/tfm_wait.c b/secure_fw/core/ipc/tfm_wait.c new file mode 100644 index 0000000000..814ec89469 --- /dev/null +++ b/secure_fw/core/ipc/tfm_wait.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include <inttypes.h> +#include <stdio.h> +#include "tfm_arch_v8m.h" +#include "tfm_thread.h" +#include "tfm_utils.h" +#include "tfm_wait.h" + +void tfm_event_wait(struct tfm_event_ctx *pevt) +{ + struct tfm_thrd_ctx *curr_thrd = tfm_thrd_curr_thread(); + + TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC); + + if (pevt->status == EVENT_STAT_WAITED) { + pevt->owner = curr_thrd; + pevt->retval = TFM_STATE_1ST_ARG(&pevt->owner->state_ctx); + tfm_thrd_set_status(pevt->owner, THRD_STAT_BLOCK); + tfm_thrd_activate_schedule(); + } + + pevt->status = EVENT_STAT_WAITED; +} + +/* Peek the status to see if caller would block. */ +uint32_t tfm_event_peek(struct tfm_event_ctx *pevt) +{ + TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC); + + return pevt->status; +} + +void tfm_event_signal(struct tfm_event_ctx *pevt) +{ + TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC); + + pevt->status = EVENT_STAT_SIGNALED; + + /* + * Wake the blocked owner up and keep the status as EVENT_STAT_WAITED + * if there is an owner. Or the second event wait caller will return + * without block since status is EVENT_STAT_SIGNALED. + */ + if (pevt->owner && pevt->owner->status == THRD_STAT_BLOCK) { + tfm_thrd_set_status(pevt->owner, THRD_STAT_RUNNING); + tfm_thrd_set_retval(pevt->owner, pevt->retval); + pevt->status = EVENT_STAT_WAITED; + tfm_thrd_activate_schedule(); + } +} + +void tfm_event_owner_retval(struct tfm_event_ctx *pmtx, uint32_t retval) +{ + TFM_ASSERT(pmtx && pmtx->magic == EVENT_MAGIC); + + pmtx->retval = retval; +} |