1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Texas Instruments System Control Interface Driver
4  *   Based on TF-A implementation
5  *
6  * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
7  *	Manorit Chawdhry <m-chawdhry@ti.com>
8  */
9 
10 #include <assert.h>
11 #include <malloc.h>
12 #include <platform_config.h>
13 #include <string.h>
14 #include <string_ext.h>
15 #include <tee_api_defines.h>
16 #include <trace.h>
17 
18 #include "sec_proxy.h"
19 #include "ti_sci.h"
20 #include "ti_sci_protocol.h"
21 
22 static uint8_t message_sequence;
23 
24 /**
25  * struct ti_sci_xfer - Structure representing a message flow
26  * @tx_message:	Transmit message
27  * @rx_message:	Receive message
28  */
29 struct ti_sci_xfer {
30 	struct k3_sec_proxy_msg tx_message;
31 	struct k3_sec_proxy_msg rx_message;
32 };
33 
34 /**
35  * ti_sci_setup_xfer() - Setup message transfer
36  *
37  * @msg_type:	Message type
38  * @msg_flags:	Flag to set for the message
39  * @tx_buf:	Buffer to be sent to mailbox channel
40  * @tx_message_size: transmit message size
41  * @rx_buf:	Buffer to be received from mailbox channel
42  * @rx_message_size: receive message size
43  * @xfer:	Transfer message
44  *
45  * Helper function which is used by various command functions that are
46  * exposed to clients of this driver for allocating a message traffic event.
47  *
48  * Return: 0 if all goes well, else appropriate error message
49  */
ti_sci_setup_xfer(uint16_t msg_type,uint32_t msg_flags,void * tx_buf,size_t tx_message_size,void * rx_buf,size_t rx_message_size,struct ti_sci_xfer * xfer)50 static int ti_sci_setup_xfer(uint16_t msg_type, uint32_t msg_flags,
51 			     void *tx_buf,
52 			     size_t tx_message_size,
53 			     void *rx_buf,
54 			     size_t rx_message_size,
55 			     struct ti_sci_xfer *xfer)
56 {
57 	struct ti_sci_msg_hdr *hdr = NULL;
58 
59 	/* Ensure we have sane transfer sizes */
60 	if (rx_message_size > SEC_PROXY_MAX_MSG_SIZE ||
61 	    tx_message_size > SEC_PROXY_MAX_MSG_SIZE ||
62 	    rx_message_size < sizeof(*hdr) ||
63 	    tx_message_size < sizeof(*hdr)) {
64 		EMSG("Message transfer size not sane");
65 		return TEE_ERROR_SHORT_BUFFER;
66 	}
67 
68 	hdr = (struct ti_sci_msg_hdr *)tx_buf;
69 	hdr->seq = ++message_sequence;
70 	hdr->type = msg_type;
71 	hdr->host = OPTEE_HOST_ID;
72 	hdr->flags = msg_flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
73 
74 	xfer->tx_message.buf = tx_buf;
75 	xfer->tx_message.len = tx_message_size;
76 
77 	xfer->rx_message.buf = rx_buf;
78 	xfer->rx_message.len = rx_message_size;
79 
80 	return 0;
81 }
82 
83 /**
84  * ti_sci_get_response() - Receive response from mailbox channel
85  *
86  * @xfer:	Transfer to initiate and wait for response
87  *
88  * Return: 0 if all goes well, else appropriate error message
89  */
ti_sci_get_response(struct ti_sci_xfer * xfer)90 static inline int ti_sci_get_response(struct ti_sci_xfer *xfer)
91 {
92 	struct k3_sec_proxy_msg *msg = &xfer->rx_message;
93 	struct ti_sci_msg_hdr *hdr = NULL;
94 	unsigned int retry = 5;
95 	int ret = 0;
96 
97 	for (; retry > 0; retry--) {
98 		/* Receive the response */
99 		ret = k3_sec_proxy_recv(msg);
100 		if (ret) {
101 			EMSG("Message receive failed (%d)", ret);
102 			return ret;
103 		}
104 
105 		/* msg is updated by Secure Proxy driver */
106 		hdr = (struct ti_sci_msg_hdr *)msg->buf;
107 
108 		/* Sanity check for message response */
109 		if (hdr->seq == message_sequence)
110 			break;
111 
112 		IMSG("Message with sequence ID %u is not expected", hdr->seq);
113 	}
114 	if (!retry) {
115 		EMSG("Timed out waiting for message");
116 		return TEE_ERROR_BUSY;
117 	}
118 
119 	if (!(hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK)) {
120 		DMSG("Message not acknowledged");
121 		return TEE_ERROR_ACCESS_DENIED;
122 	}
123 
124 	return 0;
125 }
126 
127 /**
128  * ti_sci_do_xfer() - Do one transfer
129  *
130  * @xfer: Transfer to initiate and wait for response
131  *
132  * Return: 0 if all goes well, else appropriate error message
133  */
ti_sci_do_xfer(struct ti_sci_xfer * xfer)134 static inline int ti_sci_do_xfer(struct ti_sci_xfer *xfer)
135 {
136 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
137 	int ret = 0;
138 
139 	/* Send the message */
140 	ret = k3_sec_proxy_send(msg);
141 	if (ret) {
142 		EMSG("Message sending failed (%d)", ret);
143 		return ret;
144 	}
145 
146 	/* Get the response */
147 	ret = ti_sci_get_response(xfer);
148 	if (ret) {
149 		if ((TEE_Result)ret != TEE_ERROR_ACCESS_DENIED)
150 			EMSG("Failed to get response (%d)", ret);
151 		return ret;
152 	}
153 
154 	return 0;
155 }
156 
157 /**
158  * ti_sci_get_revision() - Get the revision of the SCI entity
159  *
160  * Updates the SCI information in the internal data structure.
161  *
162  * Return: 0 if all goes well, else appropriate error message
163  */
ti_sci_get_revision(struct ti_sci_msg_resp_version * rev_info)164 int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
165 {
166 	struct ti_sci_msg_req_version req = { };
167 	struct ti_sci_xfer xfer = { };
168 	int ret = 0;
169 
170 	ret = ti_sci_setup_xfer(TI_SCI_MSG_VERSION, 0x0,
171 				&req, sizeof(req),
172 				rev_info, sizeof(*rev_info),
173 				&xfer);
174 	if (ret)
175 		return ret;
176 
177 	ret = ti_sci_do_xfer(&xfer);
178 	if (ret)
179 		return ret;
180 
181 	return 0;
182 }
183 
ti_sci_device_set_state(uint32_t id,uint32_t flags,uint8_t state)184 static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
185 {
186 	struct ti_sci_msg_req_set_device_state req = { };
187 	struct ti_sci_msg_resp_set_device_state resp = { };
188 	struct ti_sci_xfer xfer = { };
189 	int ret = 0;
190 
191 	ret = ti_sci_setup_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
192 				&req, sizeof(req),
193 				&resp, sizeof(resp),
194 				&xfer);
195 	if (ret)
196 		return ret;
197 
198 	req.id = id;
199 	req.state = state;
200 
201 	ret = ti_sci_do_xfer(&xfer);
202 	if (ret)
203 		return ret;
204 
205 	return 0;
206 }
207 
ti_sci_device_get(uint32_t id)208 int ti_sci_device_get(uint32_t id)
209 {
210 	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
211 }
212 
ti_sci_device_put(uint32_t id)213 int ti_sci_device_put(uint32_t id)
214 {
215 	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
216 }
217 
ti_sci_set_fwl_region(uint16_t fwl_id,uint16_t region,uint32_t n_permission_regs,uint32_t control,const uint32_t permissions[FWL_MAX_PRIVID_SLOTS],uint64_t start_address,uint64_t end_address)218 int ti_sci_set_fwl_region(uint16_t fwl_id, uint16_t region,
219 			  uint32_t n_permission_regs, uint32_t control,
220 			  const uint32_t permissions[FWL_MAX_PRIVID_SLOTS],
221 			  uint64_t start_address, uint64_t end_address)
222 {
223 	struct ti_sci_msg_req_fwl_set_firewall_region req = { };
224 	struct ti_sci_msg_resp_fwl_set_firewall_region resp = { };
225 	struct ti_sci_xfer xfer = { };
226 	unsigned int i = 0;
227 	int ret = 0;
228 
229 	assert(n_permission_regs <= FWL_MAX_PRIVID_SLOTS);
230 
231 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_SET, 0,
232 				&req, sizeof(req),
233 				&resp, sizeof(resp),
234 				&xfer);
235 	if (ret)
236 		return ret;
237 
238 	req.fwl_id = fwl_id;
239 	req.region = region;
240 	req.n_permission_regs = n_permission_regs;
241 	req.control = control;
242 	for (i = 0; i < n_permission_regs; i++)
243 		req.permissions[i] = permissions[i];
244 	req.start_address = start_address;
245 	req.end_address = end_address;
246 
247 	ret = ti_sci_do_xfer(&xfer);
248 	if (ret)
249 		return ret;
250 
251 	return 0;
252 }
253 
ti_sci_get_fwl_region(uint16_t fwl_id,uint16_t region,uint32_t n_permission_regs,uint32_t * control,uint32_t permissions[FWL_MAX_PRIVID_SLOTS],uint64_t * start_address,uint64_t * end_address)254 int ti_sci_get_fwl_region(uint16_t fwl_id, uint16_t region,
255 			  uint32_t n_permission_regs, uint32_t *control,
256 			  uint32_t permissions[FWL_MAX_PRIVID_SLOTS],
257 			  uint64_t *start_address, uint64_t *end_address)
258 {
259 	struct ti_sci_msg_req_fwl_get_firewall_region req = { };
260 	struct ti_sci_msg_resp_fwl_get_firewall_region resp = { };
261 	struct ti_sci_xfer xfer = { };
262 	unsigned int i = 0;
263 	int ret = 0;
264 
265 	assert(n_permission_regs <= FWL_MAX_PRIVID_SLOTS);
266 
267 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_GET, 0,
268 				&req, sizeof(req),
269 				&resp, sizeof(resp),
270 				&xfer);
271 	if (ret)
272 		return ret;
273 
274 	req.fwl_id = fwl_id;
275 	req.region = region;
276 	req.n_permission_regs = n_permission_regs;
277 
278 	ret = ti_sci_do_xfer(&xfer);
279 	if (ret)
280 		return ret;
281 
282 	*control = resp.control;
283 	for (i = 0; i < n_permission_regs; i++)
284 		permissions[i] = resp.permissions[i];
285 	*start_address = resp.start_address;
286 	*end_address = resp.end_address;
287 
288 	return 0;
289 }
290 
ti_sci_change_fwl_owner(uint16_t fwl_id,uint16_t region,uint8_t owner_index,uint8_t * owner_privid,uint16_t * owner_permission_bits)291 int ti_sci_change_fwl_owner(uint16_t fwl_id, uint16_t region,
292 			    uint8_t owner_index, uint8_t *owner_privid,
293 			    uint16_t *owner_permission_bits)
294 {
295 	struct ti_sci_msg_req_fwl_change_owner_info req = { };
296 	struct ti_sci_msg_resp_fwl_change_owner_info resp = { };
297 	struct ti_sci_xfer xfer = { };
298 	int ret = 0;
299 
300 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_CHANGE_OWNER, 0,
301 				&req, sizeof(req),
302 				&resp, sizeof(resp),
303 				&xfer);
304 	if (ret)
305 		return ret;
306 
307 	req.fwl_id = fwl_id;
308 	req.region = region;
309 	req.owner_index = owner_index;
310 
311 	ret = ti_sci_do_xfer(&xfer);
312 	if (ret)
313 		return ret;
314 
315 	*owner_privid = resp.owner_privid;
316 	*owner_permission_bits = resp.owner_permission_bits;
317 
318 	return 0;
319 }
320 
321 /**
322  * ti_sci_get_dkek() - Get the DKEK
323  * @sa2ul_instance:	SA2UL instance to get key
324  * @context:		Context string input to KDF
325  * @label:		Label string input to KDF
326  * @dkek:		Returns with DKEK populated
327  *
328  * Updates the DKEK the internal data structure.
329  *
330  * Return: 0 if all goes well, else appropriate error message
331  */
ti_sci_get_dkek(uint8_t sa2ul_instance,const char * context,const char * label,uint8_t dkek[SA2UL_DKEK_KEY_LEN])332 int ti_sci_get_dkek(uint8_t sa2ul_instance,
333 		    const char *context, const char *label,
334 		    uint8_t dkek[SA2UL_DKEK_KEY_LEN])
335 {
336 	struct ti_sci_msg_req_sa2ul_get_dkek req = { };
337 	struct ti_sci_msg_resp_sa2ul_get_dkek resp = { };
338 	struct ti_sci_xfer xfer = { };
339 	int ret = 0;
340 
341 	ret = ti_sci_setup_xfer(TI_SCI_MSG_SA2UL_GET_DKEK, 0,
342 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
343 	if (ret)
344 		return ret;
345 
346 	req.sa2ul_instance = sa2ul_instance;
347 	req.kdf_label_len = strlen(label);
348 	req.kdf_context_len = strlen(context);
349 	if (req.kdf_label_len + req.kdf_context_len >
350 	    KDF_LABEL_AND_CONTEXT_LEN_MAX) {
351 		EMSG("Context and Label too long");
352 		return TEE_ERROR_BAD_PARAMETERS;
353 	}
354 	memcpy(req.kdf_label_and_context, label, strlen(label));
355 	memcpy(req.kdf_label_and_context + strlen(label), context,
356 	       strlen(context));
357 
358 	ret = ti_sci_do_xfer(&xfer);
359 	if (ret)
360 		return ret;
361 
362 	memcpy(dkek, resp.dkek, sizeof(resp.dkek));
363 	memzero_explicit(&resp, sizeof(resp));
364 	return 0;
365 }
366 
367 /**
368  * ti_sci_init() - Basic initialization
369  *
370  * Return: 0 if all goes well, else appropriate error message
371  */
ti_sci_init(void)372 int ti_sci_init(void)
373 {
374 	struct ti_sci_msg_resp_version rev_info = { };
375 	int ret = 0;
376 
377 	ret = ti_sci_get_revision(&rev_info);
378 	if (ret) {
379 		EMSG("Unable to communicate with control firmware (%d)", ret);
380 		return ret;
381 	}
382 
383 	IMSG("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')",
384 	     rev_info.abi_major, rev_info.abi_minor,
385 	     rev_info.firmware_revision,
386 	     rev_info.firmware_description);
387 
388 	return 0;
389 }
390