1 /*
2 * Copyright (c) 2019,2020 Linaro Limited
3 * Copyright (c) 2021 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/device.h>
9 #include <zephyr/init.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/arch/arm/cortex_m/fpu.h>
12
13 #include <tfm_ns_interface.h>
14
15 /**
16 * @file @brief Zephyr's TF-M NS interface implementation
17 *
18 */
19
20
21 /* Global mutex to be used by the TF-M NS dispatcher, preventing
22 * the Non-Secure application from initiating multiple parallel
23 * TF-M secure calls.
24 */
25 K_MUTEX_DEFINE(tfm_mutex);
26
tfm_ns_interface_dispatch(veneer_fn fn,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)27 int32_t tfm_ns_interface_dispatch(veneer_fn fn,
28 uint32_t arg0, uint32_t arg1,
29 uint32_t arg2, uint32_t arg3)
30 {
31 int32_t result;
32 bool is_pre_kernel = k_is_pre_kernel();
33 int tfm_ns_saved_prio;
34
35 if (!is_pre_kernel) {
36 /* TF-M request protected by NS lock */
37 if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) {
38 return (int32_t)PSA_ERROR_GENERIC_ERROR;
39 }
40
41 #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
42 /* Prevent the thread from being preempted, while executing a
43 * Secure function. This is required to prevent system crashes
44 * that could occur, if a thread context switch is triggered in
45 * the middle of a Secure call. Note that the code below takes
46 * into account MetaIRQ, which can preempt cooperative threads
47 * of any priority.
48 */
49 tfm_ns_saved_prio = k_thread_priority_get(k_current_get());
50 k_thread_priority_set(k_current_get(), K_HIGHEST_THREAD_PRIO);
51 #else
52 ARG_UNUSED(tfm_ns_saved_prio);
53 #endif
54 }
55
56 struct fpu_ctx_full context_buffer;
57
58 z_arm_save_fp_context(&context_buffer);
59
60 result = fn(arg0, arg1, arg2, arg3);
61
62 z_arm_restore_fp_context(&context_buffer);
63
64 if (!is_pre_kernel) {
65 #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
66 /* Restore thread priority, to allow the thread to be preempted. */
67 k_thread_priority_set(k_current_get(), tfm_ns_saved_prio);
68 #endif
69
70 k_mutex_unlock(&tfm_mutex);
71 }
72
73 return result;
74 }
75
tfm_ns_interface_init(void)76 uint32_t tfm_ns_interface_init(void)
77 {
78 /*
79 * The static K_MUTEX_DEFINE handles mutex initialization,
80 * so this function may be implemented as no-op.
81 */
82 return PSA_SUCCESS;
83 }
84
85
86 #if defined(TFM_PSA_API)
87 #include "psa_manifest/sid.h"
88 #endif /* TFM_PSA_API */
89
ns_interface_init(void)90 static int ns_interface_init(void)
91 {
92
93 __ASSERT(tfm_ns_interface_init() == PSA_SUCCESS,
94 "TF-M NS interface init failed");
95
96 return 0;
97 }
98
99 /* Initialize the TFM NS interface */
100 SYS_INIT(ns_interface_init, POST_KERNEL,
101 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
102