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