xref: /optee_os/core/arch/arm/plat-k3/drivers/sec_proxy.c (revision 40baeb58144dd846de2f94e1736df55178c34062)
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 "ti_sci_transport.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 #define SEC_PROXY_MAX_MSG_SIZE 56
46 
47 /**
48  * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread
49  * @id:		Thread ID
50  * @data:	Thread Data path region for target
51  * @scfg:	Secure Config Region for Thread
52  * @rt:		RealTime Region for Thread
53  */
54 struct k3_sec_proxy_thread {
55 	const char *name;
56 	vaddr_t data;
57 	vaddr_t scfg;
58 	vaddr_t rt;
59 } spts[SEC_PROXY_MAX_THREADS];
60 
61 /**
62  * k3_sec_proxy_verify_thread() - Verify thread status before
63  *				  sending/receiving data
64  * @dir: Direction of the thread
65  */
k3_sec_proxy_verify_thread(uint32_t dir)66 static TEE_Result k3_sec_proxy_verify_thread(uint32_t dir)
67 {
68 	struct k3_sec_proxy_thread *spt = &spts[dir];
69 	uint64_t timeout = 0;
70 	uint32_t val = 0;
71 	unsigned int retry = 2;
72 
73 	FMSG("Check for thread corruption");
74 	val = io_read32(spt->rt + RT_THREAD_STATUS_REG);
75 
76 	/* Check for any errors already available */
77 	while ((val & RT_THREAD_STATUS_ERROR_MASK) && retry--) {
78 		if (!retry) {
79 			EMSG("Thread %s is corrupted, cannot send data.",
80 			     spt->name);
81 			return TEE_ERROR_BAD_STATE;
82 		}
83 
84 		/* Write Bit 0 to this location */
85 		IMSG("Resetting proxy thread %s", spt->name);
86 		val ^= RT_THREAD_STATUS_ERROR_MASK;
87 		io_write32(spt->rt + RT_THREAD_STATUS_REG, val);
88 	}
89 
90 	FMSG("Check for thread direction");
91 	/* Make sure thread is configured for right direction */
92 	if ((io_read32(spt->scfg + SCFG_THREAD_CTRL_REG) &
93 	     SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
94 		if (dir == SEC_PROXY_TX_THREAD)
95 			EMSG("Trying to receive data on tx Thread %s",
96 			     spt->name);
97 		else
98 			EMSG("Trying to send data on rx Thread %s", spt->name);
99 		return TEE_ERROR_COMMUNICATION;
100 	}
101 
102 	FMSG("Check for thread queue");
103 	/* Check the message queue before sending/receiving data */
104 	timeout = timeout_init_us(SEC_PROXY_TIMEOUT_US);
105 	while (!(io_read32(spt->rt + RT_THREAD_STATUS_REG) &
106 		 RT_THREAD_STATUS_CUR_CNT_MASK)) {
107 		DMSG("Waiting for thread %s to %s", spt->name,
108 		     (dir == THREAD_DIR_TX) ? "empty" : "fill");
109 		if (timeout_elapsed(timeout)) {
110 			EMSG("Queue is busy");
111 			return TEE_ERROR_BUSY;
112 		}
113 	}
114 
115 	FMSG("Success");
116 	return TEE_SUCCESS;
117 }
118 
119 /**
120  * ti_sci_transport_send() - Send data over a TISCI transport
121  * @msg: Pointer to ti_sci_msg
122  */
ti_sci_transport_send(const struct ti_sci_msg * msg)123 TEE_Result ti_sci_transport_send(const struct ti_sci_msg *msg)
124 {
125 	struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_TX_THREAD];
126 	int num_words = 0;
127 	int trail_bytes = 0;
128 	int i = 0;
129 	uintptr_t data_reg = 0;
130 	uint32_t data_word = 0;
131 	TEE_Result ret = TEE_SUCCESS;
132 
133 	FMSG("Verifying the thread");
134 	ret = k3_sec_proxy_verify_thread(THREAD_DIR_TX);
135 	if (ret) {
136 		EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
137 		return ret;
138 	}
139 
140 	/* Check the message size. */
141 	if (msg->len > SEC_PROXY_MAX_MSG_SIZE) {
142 		EMSG("Thread %s message length %zu > max msg size %d",
143 		     spt->name, msg->len, SEC_PROXY_MAX_MSG_SIZE);
144 		return TEE_ERROR_BAD_STATE;
145 	}
146 
147 	/* Send the message */
148 	data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
149 	num_words = msg->len / sizeof(uint32_t);
150 	for (i = 0; i < num_words; i++) {
151 		memcpy(&data_word, &msg->buf[i * 4], sizeof(uint32_t));
152 		io_write32(data_reg, data_word);
153 		data_reg += sizeof(uint32_t);
154 	}
155 
156 	trail_bytes = msg->len % sizeof(uint32_t);
157 	if (trail_bytes) {
158 		uint32_t data_trail = 0;
159 
160 		i = msg->len - trail_bytes;
161 		while (trail_bytes--) {
162 			data_trail <<= 8;
163 			data_trail |= msg->buf[i++];
164 		}
165 
166 		io_write32(data_reg, data_trail);
167 		data_reg += sizeof(uint32_t);
168 	}
169 
170 	/*
171 	 * 'data_reg' indicates next register to write. If we did not already
172 	 * write on tx complete reg(last reg), we must do so for transmit
173 	 */
174 	if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
175 		io_write32(spt->data + SEC_PROXY_DATA_END_OFFS, 0);
176 
177 	return TEE_SUCCESS;
178 }
179 
180 /**
181  * ti_sci_transport_recv() - Receive data from a TISCI transport
182  * @msg: Pointer to ti_sci_msg
183  */
ti_sci_transport_recv(struct ti_sci_msg * msg)184 TEE_Result ti_sci_transport_recv(struct ti_sci_msg *msg)
185 {
186 	struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_RX_THREAD];
187 	int num_words = 0;
188 	int i = 0;
189 	int trail_bytes = 0;
190 	uint32_t data_trail = 0;
191 	uint32_t data_word = 0;
192 	uintptr_t data_reg = 0;
193 	TEE_Result ret = TEE_SUCCESS;
194 
195 	FMSG("Verifying thread");
196 	ret = k3_sec_proxy_verify_thread(THREAD_DIR_RX);
197 	if (ret) {
198 		EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
199 		return ret;
200 	}
201 
202 	/* Receive the message */
203 	data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
204 	num_words = msg->len / sizeof(uint32_t);
205 	for (i = 0; i < num_words; i++) {
206 		data_word = io_read32(data_reg);
207 		memcpy(&msg->buf[i * 4], &data_word, sizeof(uint32_t));
208 		data_reg += sizeof(uint32_t);
209 	}
210 
211 	trail_bytes = msg->len % sizeof(uint32_t);
212 	if (trail_bytes) {
213 		data_trail = io_read32(data_reg);
214 		data_reg += sizeof(uint32_t);
215 
216 		i = msg->len - trail_bytes;
217 		while (trail_bytes--) {
218 			msg->buf[i++] = data_trail & 0xff;
219 			data_trail >>= 8;
220 		}
221 	}
222 
223 	/*
224 	 * 'data_reg' indicates next register to read. If we did not already
225 	 * read on rx complete reg(last reg), we must do so for receive
226 	 */
227 	if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
228 		io_read32(spt->data + SEC_PROXY_DATA_END_OFFS);
229 
230 	return TEE_SUCCESS;
231 }
232 
233 /**
234  * ti_sci_transport_init() - Initialize the TISCI transport threads
235  */
ti_sci_transport_init(void)236 TEE_Result ti_sci_transport_init(void)
237 {
238 	struct k3_sec_proxy_thread *thread;
239 	int rx_thread = SEC_PROXY_RESPONSE_THREAD;
240 	int tx_thread = SEC_PROXY_REQUEST_THREAD;
241 	uint32_t target_data = 0;
242 	uint32_t cfg_scfg = 0;
243 	uint32_t cfg_rt = 0;
244 
245 	DMSG("tx_thread: %d, rx_thread: %d", tx_thread, rx_thread);
246 
247 	/* TX_THREAD */
248 	target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, tx_thread);
249 	cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, tx_thread);
250 	cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, tx_thread);
251 
252 	thread = &spts[SEC_PROXY_TX_THREAD];
253 	thread->name = "SEC_PROXY_LOW_PRIORITY_THREAD";
254 
255 	thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
256 				       SEC_PROXY_DATA_SIZE);
257 	if (!thread->data)
258 		return TEE_ERROR_OUT_OF_MEMORY;
259 
260 	thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
261 				       SEC_PROXY_SCFG_SIZE);
262 	if (!thread->scfg)
263 		return TEE_ERROR_OUT_OF_MEMORY;
264 
265 	thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
266 				     SEC_PROXY_RT_SIZE);
267 	if (!thread->rt)
268 		return TEE_ERROR_OUT_OF_MEMORY;
269 
270 	/* RX_THREAD */
271 	target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, rx_thread);
272 	cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, rx_thread);
273 	cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, rx_thread);
274 
275 	thread = &spts[SEC_PROXY_RX_THREAD];
276 	thread->name = "SEC_PROXY_RESPONSE_THREAD";
277 
278 	thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
279 				       SEC_PROXY_DATA_SIZE);
280 	if (!thread->data)
281 		return TEE_ERROR_OUT_OF_MEMORY;
282 
283 	thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
284 				       SEC_PROXY_SCFG_SIZE);
285 	if (!thread->scfg)
286 		return TEE_ERROR_OUT_OF_MEMORY;
287 
288 	thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
289 				     SEC_PROXY_RT_SIZE);
290 	if (!thread->rt)
291 		return TEE_ERROR_OUT_OF_MEMORY;
292 
293 	return TEE_SUCCESS;
294 }
295