|  | /* | 
|  | * Copyright (c) 2019,2020 Linaro Limited | 
|  | * Copyright (c) 2021 Nordic Semiconductor ASA | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/init.h> | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/arch/arm/cortex_m/fpu.h> | 
|  |  | 
|  | #include <tfm_ns_interface.h> | 
|  |  | 
|  | /** | 
|  | * @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) | 
|  | { | 
|  | bool isr_mode = k_is_in_isr() || k_is_pre_kernel(); | 
|  | int tfm_ns_saved_prio; | 
|  | int32_t result; | 
|  |  | 
|  | if (!isr_mode) { | 
|  | /* TF-M request protected by NS lock */ | 
|  | if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) { | 
|  | return (int32_t)PSA_ERROR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) | 
|  | /* Prevent the thread from being preempted, while executing a | 
|  | * Secure function. This is required to prevent system crashes | 
|  | * that could occur, if a thread context switch is triggered in | 
|  | * the middle of a Secure call. Note that the code below takes | 
|  | * into account MetaIRQ, which can preempt cooperative threads | 
|  | * of any priority. | 
|  | */ | 
|  | tfm_ns_saved_prio = k_thread_priority_get(k_current_get()); | 
|  | k_thread_priority_set(k_current_get(), K_HIGHEST_THREAD_PRIO); | 
|  | #else | 
|  | ARG_UNUSED(tfm_ns_saved_prio); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_FPU_SHARING) | 
|  | struct fpu_ctx_full context_buffer; | 
|  |  | 
|  | z_arm_save_fp_context(&context_buffer); | 
|  | #endif | 
|  |  | 
|  | result = fn(arg0, arg1, arg2, arg3); | 
|  |  | 
|  | #if defined(CONFIG_FPU_SHARING) | 
|  | z_arm_restore_fp_context(&context_buffer); | 
|  | #endif | 
|  |  | 
|  | if (!isr_mode) { | 
|  | #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) | 
|  | /* Restore thread priority, to allow the thread to be preempted. */ | 
|  | k_thread_priority_set(k_current_get(), tfm_ns_saved_prio); | 
|  | #endif | 
|  |  | 
|  | k_mutex_unlock(&tfm_mutex); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | uint32_t tfm_ns_interface_init(void) | 
|  | { | 
|  | /* | 
|  | * The static K_MUTEX_DEFINE handles mutex initialization, | 
|  | * so this function may be implemented as no-op. | 
|  | */ | 
|  | return PSA_SUCCESS; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if defined(TFM_PSA_API) | 
|  | #include "psa_manifest/sid.h" | 
|  | #endif /* TFM_PSA_API */ | 
|  |  | 
|  | static int ns_interface_init(void) | 
|  | { | 
|  |  | 
|  | __ASSERT(tfm_ns_interface_init() == PSA_SUCCESS, | 
|  | "TF-M NS interface init failed"); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Initialize the TFM NS interface */ | 
|  | SYS_INIT(ns_interface_init, POST_KERNEL, | 
|  | CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |