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