1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Texas Instruments K3 Secure Proxy Driver
4 *
5 * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
6 * Manorit Chawdhry <m-chawdhry@ti.com>
7 */
8
9 #include <io.h>
10 #include <kernel/delay.h>
11 #include <mm/core_memprot.h>
12 #include <mm/core_mmu.h>
13 #include <platform_config.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <trace.h>
18
19 #include "sec_proxy.h"
20
21 /* SEC PROXY RT THREAD STATUS */
22 #define RT_THREAD_STATUS_REG 0x0
23 #define RT_THREAD_STATUS_ERROR_MASK BIT(31)
24 #define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK_32(7, 0)
25
26 /* SEC PROXY SCFG THREAD CTRL */
27 #define SCFG_THREAD_CTRL_REG 0x1000
28 #define SCFG_THREAD_CTRL_DIR_SHIFT 31
29 #define SCFG_THREAD_CTRL_DIR_MASK BIT(31)
30
31 /* SECURE PROXY GENERIC HELPERS */
32 enum threads {
33 SEC_PROXY_TX_THREAD,
34 SEC_PROXY_RX_THREAD,
35 SEC_PROXY_MAX_THREADS
36 };
37
38 #define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
39 #define SEC_PROXY_DATA_START_OFFS 0x4
40 #define SEC_PROXY_DATA_END_OFFS 0x3c
41
42 #define THREAD_DIR_TX (0)
43 #define THREAD_DIR_RX (1)
44
45 /**
46 * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread
47 * @id: Thread ID
48 * @data: Thread Data path region for target
49 * @scfg: Secure Config Region for Thread
50 * @rt: RealTime Region for Thread
51 */
52 struct k3_sec_proxy_thread {
53 const char *name;
54 vaddr_t data;
55 vaddr_t scfg;
56 vaddr_t rt;
57 } spts[SEC_PROXY_MAX_THREADS];
58
59 /**
60 * k3_sec_proxy_verify_thread() - Verify thread status before
61 * sending/receiving data
62 * @dir: Direction of the thread
63 */
k3_sec_proxy_verify_thread(uint32_t dir)64 static TEE_Result k3_sec_proxy_verify_thread(uint32_t dir)
65 {
66 struct k3_sec_proxy_thread *spt = &spts[dir];
67 uint64_t timeout = 0;
68 uint32_t val = 0;
69 unsigned int retry = 2;
70
71 FMSG("Check for thread corruption");
72 val = io_read32(spt->rt + RT_THREAD_STATUS_REG);
73
74 /* Check for any errors already available */
75 while ((val & RT_THREAD_STATUS_ERROR_MASK) && retry--) {
76 if (!retry) {
77 EMSG("Thread %s is corrupted, cannot send data.",
78 spt->name);
79 return TEE_ERROR_BAD_STATE;
80 }
81
82 /* Write Bit 0 to this location */
83 IMSG("Resetting proxy thread %s", spt->name);
84 val ^= RT_THREAD_STATUS_ERROR_MASK;
85 io_write32(spt->rt + RT_THREAD_STATUS_REG, val);
86 }
87
88 FMSG("Check for thread direction");
89 /* Make sure thread is configured for right direction */
90 if ((io_read32(spt->scfg + SCFG_THREAD_CTRL_REG) &
91 SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
92 if (dir == SEC_PROXY_TX_THREAD)
93 EMSG("Trying to receive data on tx Thread %s",
94 spt->name);
95 else
96 EMSG("Trying to send data on rx Thread %s", spt->name);
97 return TEE_ERROR_COMMUNICATION;
98 }
99
100 FMSG("Check for thread queue");
101 /* Check the message queue before sending/receiving data */
102 timeout = timeout_init_us(SEC_PROXY_TIMEOUT_US);
103 while (!(io_read32(spt->rt + RT_THREAD_STATUS_REG) &
104 RT_THREAD_STATUS_CUR_CNT_MASK)) {
105 DMSG("Waiting for thread %s to %s", spt->name,
106 (dir == THREAD_DIR_TX) ? "empty" : "fill");
107 if (timeout_elapsed(timeout)) {
108 EMSG("Queue is busy");
109 return TEE_ERROR_BUSY;
110 }
111 }
112
113 FMSG("Success");
114 return TEE_SUCCESS;
115 }
116
117 /**
118 * k3_sec_proxy_send() - Send data over a Secure Proxy thread
119 * @msg: Pointer to k3_sec_proxy_msg
120 */
k3_sec_proxy_send(const struct k3_sec_proxy_msg * msg)121 TEE_Result k3_sec_proxy_send(const struct k3_sec_proxy_msg *msg)
122 {
123 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_TX_THREAD];
124 int num_words = 0;
125 int trail_bytes = 0;
126 int i = 0;
127 uintptr_t data_reg = 0;
128 uint32_t data_word = 0;
129 TEE_Result ret = TEE_SUCCESS;
130
131 FMSG("Verifying the thread");
132 ret = k3_sec_proxy_verify_thread(THREAD_DIR_TX);
133 if (ret) {
134 EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
135 return ret;
136 }
137
138 /* Check the message size. */
139 if (msg->len > SEC_PROXY_MAX_MSG_SIZE) {
140 EMSG("Thread %s message length %zu > max msg size %d",
141 spt->name, msg->len, SEC_PROXY_MAX_MSG_SIZE);
142 return TEE_ERROR_BAD_STATE;
143 }
144
145 /* Send the message */
146 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
147 num_words = msg->len / sizeof(uint32_t);
148 for (i = 0; i < num_words; i++) {
149 memcpy(&data_word, &msg->buf[i * 4], sizeof(uint32_t));
150 io_write32(data_reg, data_word);
151 data_reg += sizeof(uint32_t);
152 }
153
154 trail_bytes = msg->len % sizeof(uint32_t);
155 if (trail_bytes) {
156 uint32_t data_trail = 0;
157
158 i = msg->len - trail_bytes;
159 while (trail_bytes--) {
160 data_trail <<= 8;
161 data_trail |= msg->buf[i++];
162 }
163
164 io_write32(data_reg, data_trail);
165 data_reg += sizeof(uint32_t);
166 }
167
168 /*
169 * 'data_reg' indicates next register to write. If we did not already
170 * write on tx complete reg(last reg), we must do so for transmit
171 */
172 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
173 io_write32(spt->data + SEC_PROXY_DATA_END_OFFS, 0);
174
175 return TEE_SUCCESS;
176 }
177
178 /**
179 * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
180 * @msg: Pointer to k3_sec_proxy_msg
181 */
k3_sec_proxy_recv(struct k3_sec_proxy_msg * msg)182 TEE_Result k3_sec_proxy_recv(struct k3_sec_proxy_msg *msg)
183 {
184 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_RX_THREAD];
185 int num_words = 0;
186 int i = 0;
187 int trail_bytes = 0;
188 uint32_t data_trail = 0;
189 uint32_t data_word = 0;
190 uintptr_t data_reg = 0;
191 TEE_Result ret = TEE_SUCCESS;
192
193 FMSG("Verifying thread");
194 ret = k3_sec_proxy_verify_thread(THREAD_DIR_RX);
195 if (ret) {
196 EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
197 return ret;
198 }
199
200 /* Receive the message */
201 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
202 num_words = msg->len / sizeof(uint32_t);
203 for (i = 0; i < num_words; i++) {
204 data_word = io_read32(data_reg);
205 memcpy(&msg->buf[i * 4], &data_word, sizeof(uint32_t));
206 data_reg += sizeof(uint32_t);
207 }
208
209 trail_bytes = msg->len % sizeof(uint32_t);
210 if (trail_bytes) {
211 data_trail = io_read32(data_reg);
212 data_reg += sizeof(uint32_t);
213
214 i = msg->len - trail_bytes;
215 while (trail_bytes--) {
216 msg->buf[i] = data_trail & 0xff;
217 data_trail >>= 8;
218 }
219 }
220
221 /*
222 * 'data_reg' indicates next register to read. If we did not already
223 * read on rx complete reg(last reg), we must do so for receive
224 */
225 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
226 io_read32(spt->data + SEC_PROXY_DATA_END_OFFS);
227
228 return TEE_SUCCESS;
229 }
230
231 /**
232 * k3_sec_proxy_init() - Initialize the secure proxy threads
233 */
k3_sec_proxy_init(void)234 TEE_Result k3_sec_proxy_init(void)
235 {
236 struct k3_sec_proxy_thread *thread;
237 int rx_thread = SEC_PROXY_RESPONSE_THREAD;
238 int tx_thread = SEC_PROXY_REQUEST_THREAD;
239 uint32_t target_data = 0;
240 uint32_t cfg_scfg = 0;
241 uint32_t cfg_rt = 0;
242
243 DMSG("tx_thread: %d, rx_thread: %d", tx_thread, rx_thread);
244
245 /* TX_THREAD */
246 target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, tx_thread);
247 cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, tx_thread);
248 cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, tx_thread);
249
250 thread = &spts[SEC_PROXY_TX_THREAD];
251 thread->name = "SEC_PROXY_LOW_PRIORITY_THREAD";
252
253 thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
254 SEC_PROXY_DATA_SIZE);
255 if (!thread->data)
256 return TEE_ERROR_OUT_OF_MEMORY;
257
258 thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
259 SEC_PROXY_SCFG_SIZE);
260 if (!thread->scfg)
261 return TEE_ERROR_OUT_OF_MEMORY;
262
263 thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
264 SEC_PROXY_RT_SIZE);
265 if (!thread->rt)
266 return TEE_ERROR_OUT_OF_MEMORY;
267
268 /* RX_THREAD */
269 target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, rx_thread);
270 cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, rx_thread);
271 cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, rx_thread);
272
273 thread = &spts[SEC_PROXY_RX_THREAD];
274 thread->name = "SEC_PROXY_RESPONSE_THREAD";
275
276 thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
277 SEC_PROXY_DATA_SIZE);
278 if (!thread->data)
279 return TEE_ERROR_OUT_OF_MEMORY;
280
281 thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
282 SEC_PROXY_SCFG_SIZE);
283 if (!thread->scfg)
284 return TEE_ERROR_OUT_OF_MEMORY;
285
286 thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
287 SEC_PROXY_RT_SIZE);
288 if (!thread->rt)
289 return TEE_ERROR_OUT_OF_MEMORY;
290
291 return TEE_SUCCESS;
292 }
293