1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
4  * Provides access to UEFI variables on platforms where they are secured by the
5  * aforementioned Secure Execution Environment (SEE) application.
6  *
7  * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
8  */
9 
10 #include <linux/efi.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/sizes.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19 #include <linux/ucs2_string.h>
20 
21 #include <linux/firmware/qcom/qcom_qseecom.h>
22 #include <linux/firmware/qcom/qcom_scm.h>
23 #include <linux/firmware/qcom/qcom_tzmem.h>
24 
25 /* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
26 
27 /* Maximum length of name string with null-terminator */
28 #define QSEE_MAX_NAME_LEN			1024
29 
30 #define QSEE_CMD_UEFI(x)			(0x8000 | (x))
31 #define QSEE_CMD_UEFI_GET_VARIABLE		QSEE_CMD_UEFI(0)
32 #define QSEE_CMD_UEFI_SET_VARIABLE		QSEE_CMD_UEFI(1)
33 #define QSEE_CMD_UEFI_GET_NEXT_VARIABLE		QSEE_CMD_UEFI(2)
34 #define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO	QSEE_CMD_UEFI(3)
35 
36 /**
37  * struct qsee_req_uefi_get_variable - Request for GetVariable command.
38  * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
39  * @length:      Length of the request in bytes, including this struct and any
40  *               parameters (name, GUID) stored after it as well as any padding
41  *               thereof for alignment.
42  * @name_offset: Offset from the start of this struct to where the variable
43  *               name is stored (as utf-16 string), in bytes.
44  * @name_size:   Size of the name parameter in bytes, including null-terminator.
45  * @guid_offset: Offset from the start of this struct to where the GUID
46  *               parameter is stored, in bytes.
47  * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
48  * @data_size:   Size of the output buffer, in bytes.
49  */
50 struct qsee_req_uefi_get_variable {
51 	u32 command_id;
52 	u32 length;
53 	u32 name_offset;
54 	u32 name_size;
55 	u32 guid_offset;
56 	u32 guid_size;
57 	u32 data_size;
58 } __packed;
59 
60 /**
61  * struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
62  * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
63  * @length:      Length of the response in bytes, including this struct and the
64  *               returned data.
65  * @status:      Status of this command.
66  * @attributes:  EFI variable attributes.
67  * @data_offset: Offset from the start of this struct to where the data is
68  *               stored, in bytes.
69  * @data_size:   Size of the returned data, in bytes. In case status indicates
70  *               that the buffer is too small, this will be the size required
71  *               to store the EFI variable data.
72  */
73 struct qsee_rsp_uefi_get_variable {
74 	u32 command_id;
75 	u32 length;
76 	u32 status;
77 	u32 attributes;
78 	u32 data_offset;
79 	u32 data_size;
80 } __packed;
81 
82 /**
83  * struct qsee_req_uefi_set_variable - Request for the SetVariable command.
84  * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
85  * @length:      Length of the request in bytes, including this struct and any
86  *               parameters (name, GUID, data) stored after it as well as any
87  *               padding thereof required for alignment.
88  * @name_offset: Offset from the start of this struct to where the variable
89  *               name is stored (as utf-16 string), in bytes.
90  * @name_size:   Size of the name parameter in bytes, including null-terminator.
91  * @guid_offset: Offset from the start of this struct to where the GUID
92  *               parameter is stored, in bytes.
93  * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
94  * @attributes:  The EFI variable attributes to set for this variable.
95  * @data_offset: Offset from the start of this struct to where the EFI variable
96  *               data is stored, in bytes.
97  * @data_size:   Size of EFI variable data, in bytes.
98  *
99  */
100 struct qsee_req_uefi_set_variable {
101 	u32 command_id;
102 	u32 length;
103 	u32 name_offset;
104 	u32 name_size;
105 	u32 guid_offset;
106 	u32 guid_size;
107 	u32 attributes;
108 	u32 data_offset;
109 	u32 data_size;
110 } __packed;
111 
112 /**
113  * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
114  * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
115  * @length:      The length of this response, i.e. the size of this struct in
116  *               bytes.
117  * @status:      Status of this command.
118  * @_unknown1:   Unknown response field.
119  * @_unknown2:   Unknown response field.
120  */
121 struct qsee_rsp_uefi_set_variable {
122 	u32 command_id;
123 	u32 length;
124 	u32 status;
125 	u32 _unknown1;
126 	u32 _unknown2;
127 } __packed;
128 
129 /**
130  * struct qsee_req_uefi_get_next_variable - Request for the
131  * GetNextVariableName command.
132  * @command_id:  The ID of the command. Must be
133  *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
134  * @length:      Length of the request in bytes, including this struct and any
135  *               parameters (name, GUID) stored after it as well as any padding
136  *               thereof for alignment.
137  * @guid_offset: Offset from the start of this struct to where the GUID
138  *               parameter is stored, in bytes.
139  * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
140  * @name_offset: Offset from the start of this struct to where the variable
141  *               name is stored (as utf-16 string), in bytes.
142  * @name_size:   Size of the name parameter in bytes, including null-terminator.
143  */
144 struct qsee_req_uefi_get_next_variable {
145 	u32 command_id;
146 	u32 length;
147 	u32 guid_offset;
148 	u32 guid_size;
149 	u32 name_offset;
150 	u32 name_size;
151 } __packed;
152 
153 /**
154  * struct qsee_rsp_uefi_get_next_variable - Response for the
155  * GetNextVariableName command.
156  * @command_id:  The ID of the command. Should be
157  *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
158  * @length:      Length of the response in bytes, including this struct and any
159  *               parameters (name, GUID) stored after it as well as any padding
160  *               thereof for alignment.
161  * @status:      Status of this command.
162  * @guid_offset: Offset from the start of this struct to where the GUID
163  *               parameter is stored, in bytes.
164  * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
165  * @name_offset: Offset from the start of this struct to where the variable
166  *               name is stored (as utf-16 string), in bytes.
167  * @name_size:   Size of the name parameter in bytes, including null-terminator.
168  */
169 struct qsee_rsp_uefi_get_next_variable {
170 	u32 command_id;
171 	u32 length;
172 	u32 status;
173 	u32 guid_offset;
174 	u32 guid_size;
175 	u32 name_offset;
176 	u32 name_size;
177 } __packed;
178 
179 /**
180  * struct qsee_req_uefi_query_variable_info - Response for the
181  * GetNextVariableName command.
182  * @command_id: The ID of the command. Must be
183  *              %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
184  * @length:     The length of this request, i.e. the size of this struct in
185  *              bytes.
186  * @attributes: The storage attributes to query the info for.
187  */
188 struct qsee_req_uefi_query_variable_info {
189 	u32 command_id;
190 	u32 length;
191 	u32 attributes;
192 } __packed;
193 
194 /**
195  * struct qsee_rsp_uefi_query_variable_info - Response for the
196  * GetNextVariableName command.
197  * @command_id:        The ID of the command. Must be
198  *                     %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
199  * @length:            The length of this response, i.e. the size of this
200  *                     struct in bytes.
201  * @status:            Status of this command.
202  * @_pad:              Padding.
203  * @storage_space:     Full storage space size, in bytes.
204  * @remaining_space:   Free storage space available, in bytes.
205  * @max_variable_size: Maximum variable data size, in bytes.
206  */
207 struct qsee_rsp_uefi_query_variable_info {
208 	u32 command_id;
209 	u32 length;
210 	u32 status;
211 	u32 _pad;
212 	u64 storage_space;
213 	u64 remaining_space;
214 	u64 max_variable_size;
215 } __packed;
216 
217 /* -- Alignment helpers ----------------------------------------------------- */
218 
219 /*
220  * Helper macro to ensure proper alignment of types (fields and arrays) when
221  * stored in some (contiguous) buffer.
222  *
223  * Note: The driver from which this one has been reverse-engineered expects an
224  * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
225  * however, has an alignment of 4 byte (32 bits). So far, this seems to work
226  * fine here. See also the comment on the typedef of efi_guid_t.
227  *
228  * Note: It looks like uefisecapp is quite picky about how the memory passed to
229  * it is structured and aligned. In particular the request/response setup used
230  * for QSEE_CMD_UEFI_GET_VARIABLE. While qcom_qseecom_app_send(), in theory,
231  * accepts separate buffers/addresses for the request and response parts, in
232  * practice, however, it seems to expect them to be both part of a larger
233  * contiguous block. We initially allocated separate buffers for the request
234  * and response but this caused the QSEE_CMD_UEFI_GET_VARIABLE command to
235  * either not write any response to the response buffer or outright crash the
236  * device. Therefore, we now allocate a single contiguous block of DMA memory
237  * for both and properly align the data using the macros below. In particular,
238  * request and response structs are aligned at 8 byte (via __reqdata_offs()),
239  * following the driver that this has been reverse-engineered from.
240  */
241 #define qcuefi_buf_align_fields(fields...)					\
242 	({									\
243 		size_t __len = 0;						\
244 		fields								\
245 		__len;								\
246 	})
247 
248 #define __field_impl(size, align, offset)					\
249 	({									\
250 		size_t *__offset = (offset);					\
251 		size_t __aligned;						\
252 										\
253 		__aligned = ALIGN(__len, align);				\
254 		__len = __aligned + (size);					\
255 										\
256 		if (__offset)							\
257 			*__offset = __aligned;					\
258 	});
259 
260 #define __array_offs(type, count, offset)					\
261 	__field_impl(sizeof(type) * (count), __alignof__(type), offset)
262 
263 #define __array_offs_aligned(type, count, align, offset)			\
264 	__field_impl(sizeof(type) * (count), align, offset)
265 
266 #define __reqdata_offs(size, offset)						\
267 	__array_offs_aligned(u8, size, 8, offset)
268 
269 #define __array(type, count)		__array_offs(type, count, NULL)
270 #define __field_offs(type, offset)	__array_offs(type, 1, offset)
271 #define __field(type)			__array_offs(type, 1, NULL)
272 
273 /* -- UEFI app interface. --------------------------------------------------- */
274 
275 struct qcuefi_client {
276 	struct qseecom_client *client;
277 	struct efivars efivars;
278 	struct qcom_tzmem_pool *mempool;
279 };
280 
qcuefi_dev(struct qcuefi_client * qcuefi)281 static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
282 {
283 	return &qcuefi->client->aux_dev.dev;
284 }
285 
qsee_uefi_status_to_efi(u32 status)286 static efi_status_t qsee_uefi_status_to_efi(u32 status)
287 {
288 	u64 category = status & 0xf0000000;
289 	u64 code = status & 0x0fffffff;
290 
291 	return category << (BITS_PER_LONG - 32) | code;
292 }
293 
qsee_uefi_get_variable(struct qcuefi_client * qcuefi,const efi_char16_t * name,const efi_guid_t * guid,u32 * attributes,unsigned long * data_size,void * data)294 static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
295 					   const efi_guid_t *guid, u32 *attributes,
296 					   unsigned long *data_size, void *data)
297 {
298 	struct qsee_req_uefi_get_variable *req_data;
299 	struct qsee_rsp_uefi_get_variable *rsp_data;
300 	void *cmd_buf __free(qcom_tzmem) = NULL;
301 	unsigned long buffer_size = *data_size;
302 	unsigned long name_length;
303 	efi_status_t efi_status;
304 	size_t cmd_buf_size;
305 	size_t guid_offs;
306 	size_t name_offs;
307 	size_t req_size;
308 	size_t rsp_size;
309 	size_t req_offs;
310 	size_t rsp_offs;
311 	ssize_t status;
312 
313 	if (!name || !guid)
314 		return EFI_INVALID_PARAMETER;
315 
316 	name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
317 	if (name_length > QSEE_MAX_NAME_LEN)
318 		return EFI_INVALID_PARAMETER;
319 
320 	if (buffer_size && !data)
321 		return EFI_INVALID_PARAMETER;
322 
323 	req_size = qcuefi_buf_align_fields(
324 		__field(*req_data)
325 		__array_offs(*name, name_length, &name_offs)
326 		__field_offs(*guid, &guid_offs)
327 	);
328 
329 	rsp_size = qcuefi_buf_align_fields(
330 		__field(*rsp_data)
331 		__array(u8, buffer_size)
332 	);
333 
334 	cmd_buf_size = qcuefi_buf_align_fields(
335 		__reqdata_offs(req_size, &req_offs)
336 		__reqdata_offs(rsp_size, &rsp_offs)
337 	);
338 
339 	cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
340 	if (!cmd_buf)
341 		return EFI_OUT_OF_RESOURCES;
342 
343 	req_data = cmd_buf + req_offs;
344 	rsp_data = cmd_buf + rsp_offs;
345 
346 	req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
347 	req_data->data_size = buffer_size;
348 	req_data->name_offset = name_offs;
349 	req_data->name_size = name_length * sizeof(*name);
350 	req_data->guid_offset = guid_offs;
351 	req_data->guid_size = sizeof(*guid);
352 	req_data->length = req_size;
353 
354 	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
355 	if (status < 0)
356 		return EFI_INVALID_PARAMETER;
357 
358 	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
359 
360 	status = qcom_qseecom_app_send(qcuefi->client,
361 				       cmd_buf + req_offs, req_size,
362 				       cmd_buf + rsp_offs, rsp_size);
363 	if (status)
364 		return EFI_DEVICE_ERROR;
365 
366 	if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE)
367 		return EFI_DEVICE_ERROR;
368 
369 	if (rsp_data->length < sizeof(*rsp_data))
370 		return EFI_DEVICE_ERROR;
371 
372 	if (rsp_data->status) {
373 		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
374 			__func__, rsp_data->status);
375 		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
376 
377 		/* Update size and attributes in case buffer is too small. */
378 		if (efi_status == EFI_BUFFER_TOO_SMALL) {
379 			*data_size = rsp_data->data_size;
380 			if (attributes)
381 				*attributes = rsp_data->attributes;
382 		}
383 
384 		return qsee_uefi_status_to_efi(rsp_data->status);
385 	}
386 
387 	if (rsp_data->length > rsp_size)
388 		return EFI_DEVICE_ERROR;
389 
390 	if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length)
391 		return EFI_DEVICE_ERROR;
392 
393 	/*
394 	 * Note: We need to set attributes and data size even if the buffer is
395 	 * too small and we won't copy any data. This is described in spec, so
396 	 * that callers can either allocate a buffer properly (with two calls
397 	 * to this function) or just read back attributes withouth having to
398 	 * deal with that.
399 	 *
400 	 * Specifically:
401 	 * - If we have a buffer size of zero and no buffer, just return the
402 	 *   attributes, required size, and indicate success.
403 	 * - If the buffer size is nonzero but too small, indicate that as an
404 	 *   error.
405 	 * - Otherwise, we are good to copy the data.
406 	 *
407 	 * Note that we have already ensured above that the buffer pointer is
408 	 * non-NULL if its size is nonzero.
409 	 */
410 	*data_size = rsp_data->data_size;
411 	if (attributes)
412 		*attributes = rsp_data->attributes;
413 
414 	if (buffer_size == 0 && !data)
415 		return EFI_SUCCESS;
416 
417 	if (buffer_size < rsp_data->data_size)
418 		return EFI_BUFFER_TOO_SMALL;
419 
420 	memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
421 
422 	return EFI_SUCCESS;
423 }
424 
qsee_uefi_set_variable(struct qcuefi_client * qcuefi,const efi_char16_t * name,const efi_guid_t * guid,u32 attributes,unsigned long data_size,const void * data)425 static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
426 					   const efi_guid_t *guid, u32 attributes,
427 					   unsigned long data_size, const void *data)
428 {
429 	struct qsee_req_uefi_set_variable *req_data;
430 	struct qsee_rsp_uefi_set_variable *rsp_data;
431 	void *cmd_buf __free(qcom_tzmem) = NULL;
432 	unsigned long name_length;
433 	size_t cmd_buf_size;
434 	size_t name_offs;
435 	size_t guid_offs;
436 	size_t data_offs;
437 	size_t req_size;
438 	size_t req_offs;
439 	size_t rsp_offs;
440 	ssize_t status;
441 
442 	if (!name || !guid)
443 		return EFI_INVALID_PARAMETER;
444 
445 	name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
446 	if (name_length > QSEE_MAX_NAME_LEN)
447 		return EFI_INVALID_PARAMETER;
448 
449 	/*
450 	 * Make sure we have some data if data_size is nonzero. Note that using
451 	 * a size of zero is a valid use-case described in spec and deletes the
452 	 * variable.
453 	 */
454 	if (data_size && !data)
455 		return EFI_INVALID_PARAMETER;
456 
457 	req_size = qcuefi_buf_align_fields(
458 		__field(*req_data)
459 		__array_offs(*name, name_length, &name_offs)
460 		__field_offs(*guid, &guid_offs)
461 		__array_offs(u8, data_size, &data_offs)
462 	);
463 
464 	cmd_buf_size = qcuefi_buf_align_fields(
465 		__reqdata_offs(req_size, &req_offs)
466 		__reqdata_offs(sizeof(*rsp_data), &rsp_offs)
467 	);
468 
469 	cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
470 	if (!cmd_buf)
471 		return EFI_OUT_OF_RESOURCES;
472 
473 	req_data = cmd_buf + req_offs;
474 	rsp_data = cmd_buf + rsp_offs;
475 
476 	req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
477 	req_data->attributes = attributes;
478 	req_data->name_offset = name_offs;
479 	req_data->name_size = name_length * sizeof(*name);
480 	req_data->guid_offset = guid_offs;
481 	req_data->guid_size = sizeof(*guid);
482 	req_data->data_offset = data_offs;
483 	req_data->data_size = data_size;
484 	req_data->length = req_size;
485 
486 	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
487 	if (status < 0)
488 		return EFI_INVALID_PARAMETER;
489 
490 	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
491 
492 	if (data_size)
493 		memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
494 
495 	status = qcom_qseecom_app_send(qcuefi->client,
496 				       cmd_buf + req_offs, req_size,
497 				       cmd_buf + rsp_offs, sizeof(*rsp_data));
498 	if (status)
499 		return EFI_DEVICE_ERROR;
500 
501 	if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE)
502 		return EFI_DEVICE_ERROR;
503 
504 	if (rsp_data->length != sizeof(*rsp_data))
505 		return EFI_DEVICE_ERROR;
506 
507 	if (rsp_data->status) {
508 		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
509 			__func__, rsp_data->status);
510 		return qsee_uefi_status_to_efi(rsp_data->status);
511 	}
512 
513 	return EFI_SUCCESS;
514 }
515 
qsee_uefi_get_next_variable(struct qcuefi_client * qcuefi,unsigned long * name_size,efi_char16_t * name,efi_guid_t * guid)516 static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
517 						unsigned long *name_size, efi_char16_t *name,
518 						efi_guid_t *guid)
519 {
520 	struct qsee_req_uefi_get_next_variable *req_data;
521 	struct qsee_rsp_uefi_get_next_variable *rsp_data;
522 	void *cmd_buf __free(qcom_tzmem) = NULL;
523 	efi_status_t efi_status;
524 	size_t cmd_buf_size;
525 	size_t guid_offs;
526 	size_t name_offs;
527 	size_t req_size;
528 	size_t rsp_size;
529 	size_t req_offs;
530 	size_t rsp_offs;
531 	ssize_t status;
532 
533 	if (!name_size || !name || !guid)
534 		return EFI_INVALID_PARAMETER;
535 
536 	if (*name_size == 0)
537 		return EFI_INVALID_PARAMETER;
538 
539 	req_size = qcuefi_buf_align_fields(
540 		__field(*req_data)
541 		__field_offs(*guid, &guid_offs)
542 		__array_offs(*name, *name_size / sizeof(*name), &name_offs)
543 	);
544 
545 	rsp_size = qcuefi_buf_align_fields(
546 		__field(*rsp_data)
547 		__field(*guid)
548 		__array(*name, *name_size / sizeof(*name))
549 	);
550 
551 	cmd_buf_size = qcuefi_buf_align_fields(
552 		__reqdata_offs(req_size, &req_offs)
553 		__reqdata_offs(rsp_size, &rsp_offs)
554 	);
555 
556 	cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
557 	if (!cmd_buf)
558 		return EFI_OUT_OF_RESOURCES;
559 
560 	req_data = cmd_buf + req_offs;
561 	rsp_data = cmd_buf + rsp_offs;
562 
563 	req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
564 	req_data->guid_offset = guid_offs;
565 	req_data->guid_size = sizeof(*guid);
566 	req_data->name_offset = name_offs;
567 	req_data->name_size = *name_size;
568 	req_data->length = req_size;
569 
570 	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
571 	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
572 			      *name_size / sizeof(*name));
573 	if (status < 0)
574 		return EFI_INVALID_PARAMETER;
575 
576 	status = qcom_qseecom_app_send(qcuefi->client,
577 				       cmd_buf + req_offs, req_size,
578 				       cmd_buf + rsp_offs, rsp_size);
579 	if (status)
580 		return EFI_DEVICE_ERROR;
581 
582 	if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE)
583 		return EFI_DEVICE_ERROR;
584 
585 	if (rsp_data->length < sizeof(*rsp_data))
586 		return EFI_DEVICE_ERROR;
587 
588 	if (rsp_data->status) {
589 		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
590 			__func__, rsp_data->status);
591 		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
592 
593 		/*
594 		 * If the buffer to hold the name is too small, update the
595 		 * name_size with the required size, so that callers can
596 		 * reallocate it accordingly.
597 		 */
598 		if (efi_status == EFI_BUFFER_TOO_SMALL)
599 			*name_size = rsp_data->name_size;
600 
601 		return efi_status;
602 	}
603 
604 	if (rsp_data->length > rsp_size)
605 		return EFI_DEVICE_ERROR;
606 
607 	if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length)
608 		return EFI_DEVICE_ERROR;
609 
610 	if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length)
611 		return EFI_DEVICE_ERROR;
612 
613 	if (rsp_data->name_size > *name_size) {
614 		*name_size = rsp_data->name_size;
615 		return EFI_BUFFER_TOO_SMALL;
616 	}
617 
618 	if (rsp_data->guid_size != sizeof(*guid))
619 		return EFI_DEVICE_ERROR;
620 
621 	memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
622 	status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
623 			      rsp_data->name_size / sizeof(*name));
624 	*name_size = rsp_data->name_size;
625 
626 	if (status < 0)
627 		/*
628 		 * Return EFI_DEVICE_ERROR here because the buffer size should
629 		 * have already been validated above, causing this function to
630 		 * bail with EFI_BUFFER_TOO_SMALL.
631 		 */
632 		return EFI_DEVICE_ERROR;
633 
634 	return EFI_SUCCESS;
635 }
636 
qsee_uefi_query_variable_info(struct qcuefi_client * qcuefi,u32 attr,u64 * storage_space,u64 * remaining_space,u64 * max_variable_size)637 static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
638 						  u64 *storage_space, u64 *remaining_space,
639 						  u64 *max_variable_size)
640 {
641 	struct qsee_req_uefi_query_variable_info *req_data;
642 	struct qsee_rsp_uefi_query_variable_info *rsp_data;
643 	void *cmd_buf __free(qcom_tzmem) = NULL;
644 	size_t cmd_buf_size;
645 	size_t req_offs;
646 	size_t rsp_offs;
647 	int status;
648 
649 	cmd_buf_size = qcuefi_buf_align_fields(
650 		__reqdata_offs(sizeof(*req_data), &req_offs)
651 		__reqdata_offs(sizeof(*rsp_data), &rsp_offs)
652 	);
653 
654 	cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
655 	if (!cmd_buf)
656 		return EFI_OUT_OF_RESOURCES;
657 
658 	req_data = cmd_buf + req_offs;
659 	rsp_data = cmd_buf + rsp_offs;
660 
661 	req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
662 	req_data->attributes = attr;
663 	req_data->length = sizeof(*req_data);
664 
665 	status = qcom_qseecom_app_send(qcuefi->client,
666 				       cmd_buf + req_offs, sizeof(*req_data),
667 				       cmd_buf + rsp_offs, sizeof(*rsp_data));
668 	if (status)
669 		return EFI_DEVICE_ERROR;
670 
671 	if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO)
672 		return EFI_DEVICE_ERROR;
673 
674 	if (rsp_data->length != sizeof(*rsp_data))
675 		return EFI_DEVICE_ERROR;
676 
677 	if (rsp_data->status) {
678 		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
679 			__func__, rsp_data->status);
680 		return qsee_uefi_status_to_efi(rsp_data->status);
681 	}
682 
683 	if (storage_space)
684 		*storage_space = rsp_data->storage_space;
685 
686 	if (remaining_space)
687 		*remaining_space = rsp_data->remaining_space;
688 
689 	if (max_variable_size)
690 		*max_variable_size = rsp_data->max_variable_size;
691 
692 	return EFI_SUCCESS;
693 }
694 
695 /* -- Global efivar interface. ---------------------------------------------- */
696 
697 static struct qcuefi_client *__qcuefi;
698 static DEFINE_MUTEX(__qcuefi_lock);
699 
qcuefi_set_reference(struct qcuefi_client * qcuefi)700 static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
701 {
702 	mutex_lock(&__qcuefi_lock);
703 
704 	if (qcuefi && __qcuefi) {
705 		mutex_unlock(&__qcuefi_lock);
706 		return -EEXIST;
707 	}
708 
709 	__qcuefi = qcuefi;
710 
711 	mutex_unlock(&__qcuefi_lock);
712 	return 0;
713 }
714 
qcuefi_acquire(void)715 static struct qcuefi_client *qcuefi_acquire(void)
716 {
717 	mutex_lock(&__qcuefi_lock);
718 	if (!__qcuefi) {
719 		mutex_unlock(&__qcuefi_lock);
720 		return NULL;
721 	}
722 	return __qcuefi;
723 }
724 
qcuefi_release(void)725 static void qcuefi_release(void)
726 {
727 	mutex_unlock(&__qcuefi_lock);
728 }
729 
qcuefi_get_variable(efi_char16_t * name,efi_guid_t * vendor,u32 * attr,unsigned long * data_size,void * data)730 static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
731 					unsigned long *data_size, void *data)
732 {
733 	struct qcuefi_client *qcuefi;
734 	efi_status_t status;
735 
736 	qcuefi = qcuefi_acquire();
737 	if (!qcuefi)
738 		return EFI_NOT_READY;
739 
740 	status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
741 
742 	qcuefi_release();
743 	return status;
744 }
745 
qcuefi_set_variable(efi_char16_t * name,efi_guid_t * vendor,u32 attr,unsigned long data_size,void * data)746 static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
747 					u32 attr, unsigned long data_size, void *data)
748 {
749 	struct qcuefi_client *qcuefi;
750 	efi_status_t status;
751 
752 	qcuefi = qcuefi_acquire();
753 	if (!qcuefi)
754 		return EFI_NOT_READY;
755 
756 	status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
757 
758 	qcuefi_release();
759 	return status;
760 }
761 
qcuefi_get_next_variable(unsigned long * name_size,efi_char16_t * name,efi_guid_t * vendor)762 static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
763 					     efi_guid_t *vendor)
764 {
765 	struct qcuefi_client *qcuefi;
766 	efi_status_t status;
767 
768 	qcuefi = qcuefi_acquire();
769 	if (!qcuefi)
770 		return EFI_NOT_READY;
771 
772 	status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
773 
774 	qcuefi_release();
775 	return status;
776 }
777 
qcuefi_query_variable_info(u32 attr,u64 * storage_space,u64 * remaining_space,u64 * max_variable_size)778 static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
779 					       u64 *max_variable_size)
780 {
781 	struct qcuefi_client *qcuefi;
782 	efi_status_t status;
783 
784 	qcuefi = qcuefi_acquire();
785 	if (!qcuefi)
786 		return EFI_NOT_READY;
787 
788 	status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
789 					       max_variable_size);
790 
791 	qcuefi_release();
792 	return status;
793 }
794 
795 static const struct efivar_operations qcom_efivar_ops = {
796 	.get_variable = qcuefi_get_variable,
797 	.set_variable = qcuefi_set_variable,
798 	.get_next_variable = qcuefi_get_next_variable,
799 	.query_variable_info = qcuefi_query_variable_info,
800 };
801 
802 /* -- Driver setup. --------------------------------------------------------- */
803 
qcom_uefisecapp_probe(struct auxiliary_device * aux_dev,const struct auxiliary_device_id * aux_dev_id)804 static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
805 				 const struct auxiliary_device_id *aux_dev_id)
806 {
807 	struct qcom_tzmem_pool_config pool_config;
808 	struct qcuefi_client *qcuefi;
809 	int status;
810 
811 	qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
812 	if (!qcuefi)
813 		return -ENOMEM;
814 
815 	qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
816 
817 	auxiliary_set_drvdata(aux_dev, qcuefi);
818 	status = qcuefi_set_reference(qcuefi);
819 	if (status)
820 		return status;
821 
822 	status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
823 	if (status)
824 		qcuefi_set_reference(NULL);
825 
826 	memset(&pool_config, 0, sizeof(pool_config));
827 	pool_config.initial_size = SZ_4K;
828 	pool_config.policy = QCOM_TZMEM_POLICY_MULTIPLIER;
829 	pool_config.increment = 2;
830 	pool_config.max_size = SZ_256K;
831 
832 	qcuefi->mempool = devm_qcom_tzmem_pool_new(&aux_dev->dev, &pool_config);
833 	if (IS_ERR(qcuefi->mempool))
834 		return PTR_ERR(qcuefi->mempool);
835 
836 	return status;
837 }
838 
qcom_uefisecapp_remove(struct auxiliary_device * aux_dev)839 static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
840 {
841 	struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
842 
843 	efivars_unregister(&qcuefi->efivars);
844 	qcuefi_set_reference(NULL);
845 }
846 
847 static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
848 	{ .name = "qcom_qseecom.uefisecapp" },
849 	{}
850 };
851 MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
852 
853 static struct auxiliary_driver qcom_uefisecapp_driver = {
854 	.probe = qcom_uefisecapp_probe,
855 	.remove = qcom_uefisecapp_remove,
856 	.id_table = qcom_uefisecapp_id_table,
857 	.driver = {
858 		.name = "qcom_qseecom_uefisecapp",
859 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
860 	},
861 };
862 module_auxiliary_driver(qcom_uefisecapp_driver);
863 
864 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
865 MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
866 MODULE_LICENSE("GPL");
867