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 <device.h>
9 #include <init.h>
10 #include <kernel.h>
11 #include <arch/arm/aarch32/cortex_m/cmsis.h>
12 #include <arch/arm/aarch32/cortex_m/fpu.h>
13 
14 #include <tfm_ns_interface.h>
15 
16 /**
17  * @file @brief Zephyr's TF-M NS interface implementation
18  *
19  */
20 
21 
22 /* Global mutex to be used by the TF-M NS dispatcher, preventing
23  * the Non-Secure application from initiating multiple parallel
24  * TF-M secure calls.
25  */
26 K_MUTEX_DEFINE(tfm_mutex);
27 
tfm_ns_interface_dispatch(veneer_fn fn,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)28 int32_t tfm_ns_interface_dispatch(veneer_fn fn,
29 				  uint32_t arg0, uint32_t arg1,
30 				  uint32_t arg2, uint32_t arg3)
31 {
32 	int32_t result;
33 
34 	/* TF-M request protected by NS lock */
35 	if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) {
36 		return (int32_t)TFM_ERROR_GENERIC;
37 	}
38 
39 #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
40 	/*
41 	 * Prevent the thread from being preempted, while executing a Secure
42 	 * function. This is required to prevent system crashes that could
43 	 * occur, if a thead context switch is triggered in the middle of a
44 	 * Secure call.
45 	 */
46 	k_sched_lock();
47 #endif
48 
49 #if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
50 	struct fpu_ctx_full context_buffer;
51 
52 	z_arm_save_fp_context(&context_buffer);
53 #endif
54 
55 	result = fn(arg0, arg1, arg2, arg3);
56 
57 #if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
58 	z_arm_restore_fp_context(&context_buffer);
59 #endif
60 
61 #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
62 	/* Unlock the scheduler, to allow the thread to be preempted. */
63 	k_sched_unlock();
64 #endif
65 
66 	k_mutex_unlock(&tfm_mutex);
67 
68 	return result;
69 }
70 
tfm_ns_interface_init(void)71 enum tfm_status_e tfm_ns_interface_init(void)
72 {
73 	/*
74 	 * The static K_MUTEX_DEFINE handles mutex initialization,
75 	 * so this function may be implemented as no-op.
76 	 */
77 	return TFM_SUCCESS;
78 }
79 
80 
81 #if defined(TFM_PSA_API)
82 #include "psa_manifest/sid.h"
83 #endif /* TFM_PSA_API */
84 
ns_interface_init(const struct device * arg)85 static int ns_interface_init(const struct device *arg)
86 {
87 	ARG_UNUSED(arg);
88 
89 	__ASSERT(tfm_ns_interface_init() == TFM_SUCCESS,
90 		"TF-M NS interface init failed");
91 
92 	return 0;
93 }
94 
95 /* Initialize the TFM NS interface */
96 SYS_INIT(ns_interface_init, POST_KERNEL,
97 	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
98