1 /*
2 * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include "tfm_hal_device_header.h"
10 #include "tfm_ns_ctx.h"
11 #include "tfm_nspm.h"
12
13 /*
14 * NS context. Initialized to 0.
15 * All contexts are not used as the reference counter is 0 in initialization.
16 */
17 static struct tfm_ns_ctx_t ns_ctx_data[TFM_NS_CONTEXT_MAX] = {0};
18
19 /* Current active NS context index. Default is invalid index */
20 static uint8_t active_ns_ctx_index = TFM_NS_CONTEXT_MAX;
21
init_ns_ctx(void)22 bool init_ns_ctx(void)
23 {
24 uint32_t i;
25
26 for (i = 0; i < TFM_NS_CONTEXT_MAX; i++) {
27 /* Only need to ensure the reference counter is 0 */
28 ns_ctx_data[i].ref_cnt = 0;
29 }
30
31 active_ns_ctx_index = TFM_NS_CONTEXT_MAX;
32 return true;
33 }
34
acquire_ns_ctx(uint8_t gid,uint8_t * idx)35 bool acquire_ns_ctx(uint8_t gid, uint8_t *idx)
36 {
37 /* Only support one context slot for now */
38 uint32_t i;
39 uint32_t empty_ctx_idx = TFM_NS_CONTEXT_MAX; /* default is invalid */
40
41 __disable_irq();
42 /*
43 * Go through all context slots to get the context for the given group ID.
44 * It will not take a long time as the context number should be limited.
45 */
46 for (i = 0; i < TFM_NS_CONTEXT_MAX; i++) {
47 if (ns_ctx_data[i].ref_cnt > 0) { /* This context has been taken */
48 if (ns_ctx_data[i].gid == gid) {
49 /*
50 * Found the context associated with the input group ID.
51 * Check if the thread number reached the limit.
52 */
53 if (ns_ctx_data[i].ref_cnt < TFM_NS_CONTEXT_MAX_TID) {
54 /* Reuse this context and increase the reference number */
55 ns_ctx_data[i].ref_cnt++;
56 *idx = i;
57 __enable_irq();
58 return true;
59 } else {
60 /* No more thread for this group */
61 __enable_irq();
62 return false;
63 }
64 }
65 } else { /* Found an empty context slot */
66 /* Save the first unused context index and continue */
67 if (empty_ctx_idx == TFM_NS_CONTEXT_MAX) {
68 empty_ctx_idx = i;
69 }
70 /*
71 * Still need to go through the remaining slots to check if there
72 * is an existing context assigned to the given group ID.
73 */
74 }
75 }
76
77 /* No existing context for the group ID, use the first free context */
78 if (empty_ctx_idx < TFM_NS_CONTEXT_MAX) {
79 ns_ctx_data[empty_ctx_idx].ref_cnt++;
80 ns_ctx_data[empty_ctx_idx].gid = gid;
81 *idx = empty_ctx_idx;
82 __enable_irq();
83 return true;
84 } else {
85 __enable_irq();
86 return false; /* No available context */
87 }
88 }
89
release_ns_ctx(uint8_t gid,uint8_t tid,uint8_t idx)90 bool release_ns_ctx(uint8_t gid, uint8_t tid, uint8_t idx)
91 {
92 /* Check if the index is in range */
93 if (idx >= TFM_NS_CONTEXT_MAX) {
94 return false;
95 }
96
97 __disable_irq();
98
99 /* Check if the context belongs to that group */
100 if (ns_ctx_data[idx].gid != gid) {
101 __enable_irq();
102 return false;
103 }
104
105 /*
106 * If it is to release the current active context, then set active context
107 * to invalid.
108 * Otherwise, just de-reference the context
109 */
110 if (idx == active_ns_ctx_index) {
111 if (ns_ctx_data[idx].tid == tid) {
112 /* Release the currrent active thread */
113 if (ns_ctx_data[idx].ref_cnt > 0) {
114 ns_ctx_data[idx].ref_cnt--;
115 }
116 active_ns_ctx_index = TFM_NS_CONTEXT_MAX;
117 } else {
118 /*
119 * Release for another thread in the active context
120 * As there's an active thread ongoing, so the ref_counter should
121 * be at least 1 after the release.
122 */
123 if (ns_ctx_data[idx].ref_cnt > 1) {
124 ns_ctx_data[idx].ref_cnt--;
125 }
126 }
127 } else {
128 /* Release in the non-active context */
129 if (ns_ctx_data[idx].ref_cnt > 0) {
130 ns_ctx_data[idx].ref_cnt--;
131 }
132 }
133
134 __enable_irq();
135 return true;
136 }
137
load_ns_ctx(uint8_t gid,uint8_t tid,int32_t nsid,uint8_t idx)138 bool load_ns_ctx(uint8_t gid, uint8_t tid, int32_t nsid, uint8_t idx)
139 {
140 /* Check if the index is in range */
141 if (idx >= TFM_NS_CONTEXT_MAX) {
142 return false;
143 }
144
145 __disable_irq();
146
147 /* Check group ID and reference counter */
148 if ((ns_ctx_data[idx].gid != gid) || (ns_ctx_data[idx].ref_cnt == 0)) {
149 __enable_irq();
150 return false;
151 }
152
153 ns_ctx_data[idx].tid = tid;
154 ns_ctx_data[idx].nsid = nsid;
155 active_ns_ctx_index = idx;
156 __enable_irq();
157 return true;
158 }
159
save_ns_ctx(uint8_t gid,uint8_t tid,uint8_t idx)160 bool save_ns_ctx(uint8_t gid, uint8_t tid, uint8_t idx)
161 {
162 __disable_irq();
163 /* Check if the given index is valid */
164 if ((idx != active_ns_ctx_index) || (idx >= TFM_NS_CONTEXT_MAX)) {
165 __enable_irq();
166 return false;
167 }
168
169 /* Check group, thread ID and reference counter */
170 if ((ns_ctx_data[idx].gid != gid)
171 || (ns_ctx_data[idx].tid != tid)
172 || (ns_ctx_data[idx].ref_cnt == 0)) {
173 __enable_irq();
174 return false;
175 }
176
177 /* Set active context index to invalid */
178 active_ns_ctx_index = TFM_NS_CONTEXT_MAX;
179 __enable_irq();
180 return true;
181 }
182
get_nsid_from_active_ns_ctx(void)183 int32_t get_nsid_from_active_ns_ctx(void)
184 {
185 int32_t ret = TFM_NS_CLIENT_INVALID_ID;
186
187 __disable_irq();
188
189 if (active_ns_ctx_index < TFM_NS_CONTEXT_MAX) {
190 ret = ns_ctx_data[active_ns_ctx_index].nsid;
191 }
192
193 __enable_irq();
194 return ret;
195 }
196