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