2021-03-20 00:22:17 +08:00
|
|
|
/*
|
2021-01-11 22:38:00 +08:00
|
|
|
* Copyright (c) 2019,2020 Linaro Limited
|
2021-03-20 00:22:17 +08:00
|
|
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <device.h>
|
|
|
|
#include <init.h>
|
|
|
|
#include <kernel.h>
|
2021-05-04 21:31:04 +08:00
|
|
|
#include <arch/arm/aarch32/cortex_m/cmsis.h>
|
2021-03-20 00:22:17 +08:00
|
|
|
|
|
|
|
#include <tfm_ns_interface.h>
|
|
|
|
|
2021-01-11 22:38:00 +08:00
|
|
|
/**
|
|
|
|
* @file @brief Zephyr's TF-M NS interface implementation
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* Global mutex to be used by the TF-M NS dispatcher, preventing
|
|
|
|
* the Non-Secure application from initiating multiple parallel
|
|
|
|
* TF-M secure calls.
|
|
|
|
*/
|
|
|
|
K_MUTEX_DEFINE(tfm_mutex);
|
|
|
|
|
|
|
|
int32_t tfm_ns_interface_dispatch(veneer_fn fn,
|
|
|
|
uint32_t arg0, uint32_t arg1,
|
|
|
|
uint32_t arg2, uint32_t arg3)
|
|
|
|
{
|
|
|
|
int32_t result;
|
|
|
|
|
|
|
|
/* TF-M request protected by NS lock */
|
|
|
|
if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) {
|
|
|
|
return (int32_t)TFM_ERROR_GENERIC;
|
|
|
|
}
|
|
|
|
|
2021-05-04 21:31:04 +08:00
|
|
|
#if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
|
2021-03-24 20:14:19 +08:00
|
|
|
/*
|
|
|
|
* Prevent the thread from being preempted, while executing a Secure
|
|
|
|
* function. This is required to prevent system crashes that could
|
|
|
|
* occur, if a thead context switch is triggered in the middle of a
|
|
|
|
* Secure call.
|
|
|
|
*/
|
|
|
|
k_sched_lock();
|
2021-05-04 21:31:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING)
|
|
|
|
uint32_t fp_ctx_caller_saved[16];
|
|
|
|
uint32_t fp_ctx_callee_saved[16];
|
|
|
|
uint32_t fp_ctx_FPSCR;
|
|
|
|
bool context_saved = false;
|
|
|
|
uint32_t CONTROL = __get_CONTROL();
|
|
|
|
|
|
|
|
if (CONTROL & CONTROL_FPCA_Msk) {
|
|
|
|
/* Store caller-saved and callee-saved FP registers. */
|
|
|
|
__asm__ volatile(
|
|
|
|
"vstmia %0, {s0-s15}\n"
|
|
|
|
"vstmia %1, {s16-s31}\n"
|
|
|
|
:: "r" (fp_ctx_caller_saved), "r" (fp_ctx_callee_saved) :
|
|
|
|
);
|
|
|
|
|
|
|
|
fp_ctx_FPSCR = __get_FPSCR();
|
|
|
|
context_saved = true;
|
|
|
|
|
|
|
|
/* Disable FPCA so no stacking of FP registers happens in TFM. */
|
|
|
|
__set_CONTROL(CONTROL & ~CONTROL_FPCA_Msk);
|
|
|
|
|
|
|
|
/* ISB is recommended after setting CONTROL. It's not needed
|
|
|
|
* here though, since FPCA should have no impact on instruction
|
|
|
|
* fetching.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING) */
|
2021-03-24 20:14:19 +08:00
|
|
|
|
2021-01-11 22:38:00 +08:00
|
|
|
result = fn(arg0, arg1, arg2, arg3);
|
|
|
|
|
2021-05-04 21:31:04 +08:00
|
|
|
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING)
|
|
|
|
if (context_saved) {
|
|
|
|
/* Set FPCA first so it is set even if an interrupt happens
|
|
|
|
* during restoration.
|
|
|
|
*/
|
|
|
|
__set_CONTROL(__get_CONTROL() | CONTROL_FPCA_Msk);
|
|
|
|
|
|
|
|
/* Restore FP state. */
|
|
|
|
__set_FPSCR(fp_ctx_FPSCR);
|
|
|
|
|
|
|
|
__asm__ volatile(
|
|
|
|
"vldmia %0, {s0-s15}\n"
|
|
|
|
"vldmia %0, {s16-s31}\n"
|
|
|
|
:: "r" (fp_ctx_caller_saved), "r" (fp_ctx_callee_saved) :
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING) */
|
|
|
|
|
|
|
|
#if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
|
2021-03-24 20:14:19 +08:00
|
|
|
/* Unlock the scheduler, to allow the thread to be preempted. */
|
|
|
|
k_sched_unlock();
|
2021-05-04 21:31:04 +08:00
|
|
|
#endif
|
2021-03-24 20:14:19 +08:00
|
|
|
|
2021-01-11 22:38:00 +08:00
|
|
|
k_mutex_unlock(&tfm_mutex);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum tfm_status_e tfm_ns_interface_init(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The static K_MUTEX_DEFINE handles mutex initialization,
|
|
|
|
* so this function may be implemented as no-op.
|
|
|
|
*/
|
|
|
|
return TFM_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-20 00:22:17 +08:00
|
|
|
#if defined(TFM_PSA_API)
|
|
|
|
#include "psa_manifest/sid.h"
|
|
|
|
#endif /* TFM_PSA_API */
|
|
|
|
|
|
|
|
static int ns_interface_init(const struct device *arg)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(arg);
|
|
|
|
|
2021-01-11 22:38:00 +08:00
|
|
|
__ASSERT(tfm_ns_interface_init() == TFM_SUCCESS,
|
|
|
|
"TF-M NS interface init failed");
|
2021-03-20 00:22:17 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the TFM NS interface */
|
|
|
|
SYS_INIT(ns_interface_init, POST_KERNEL,
|
|
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|