Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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 */
 47struct 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 */
 70struct 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 */
 97struct 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 */
118struct 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 */
141struct 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 */
166struct 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 */
185struct 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 */
204struct 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#define qcuefi_buf_align_fields(fields...)					\
226	({									\
227		size_t __len = 0;						\
228		fields								\
229		__len;								\
230	})
231
232#define __field_impl(size, align, offset)					\
233	({									\
234		size_t *__offset = (offset);					\
235		size_t __aligned;						\
236										\
237		__aligned = ALIGN(__len, align);				\
238		__len = __aligned + (size);					\
239										\
240		if (__offset)							\
241			*__offset = __aligned;					\
242	});
243
244#define __array_offs(type, count, offset)					\
245	__field_impl(sizeof(type) * (count), __alignof__(type), offset)
246
247#define __array(type, count)		__array_offs(type, count, NULL)
248#define __field_offs(type, offset)	__array_offs(type, 1, offset)
249#define __field(type)			__array_offs(type, 1, NULL)
250
251/* -- UEFI app interface. --------------------------------------------------- */
252
253struct qcuefi_client {
254	struct qseecom_client *client;
255	struct efivars efivars;
256};
257
258static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
259{
260	return &qcuefi->client->aux_dev.dev;
261}
262
263static efi_status_t qsee_uefi_status_to_efi(u32 status)
264{
265	u64 category = status & 0xf0000000;
266	u64 code = status & 0x0fffffff;
267
268	return category << (BITS_PER_LONG - 32) | code;
269}
270
271static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
272					   const efi_guid_t *guid, u32 *attributes,
273					   unsigned long *data_size, void *data)
274{
275	struct qsee_req_uefi_get_variable *req_data;
276	struct qsee_rsp_uefi_get_variable *rsp_data;
277	unsigned long buffer_size = *data_size;
278	efi_status_t efi_status = EFI_SUCCESS;
279	unsigned long name_length;
280	size_t guid_offs;
281	size_t name_offs;
282	size_t req_size;
283	size_t rsp_size;
284	ssize_t status;
285
286	if (!name || !guid)
287		return EFI_INVALID_PARAMETER;
288
289	name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
290	if (name_length > QSEE_MAX_NAME_LEN)
291		return EFI_INVALID_PARAMETER;
292
293	if (buffer_size && !data)
294		return EFI_INVALID_PARAMETER;
295
296	req_size = qcuefi_buf_align_fields(
297		__field(*req_data)
298		__array_offs(*name, name_length, &name_offs)
299		__field_offs(*guid, &guid_offs)
300	);
301
302	rsp_size = qcuefi_buf_align_fields(
303		__field(*rsp_data)
304		__array(u8, buffer_size)
305	);
306
307	req_data = kzalloc(req_size, GFP_KERNEL);
308	if (!req_data) {
309		efi_status = EFI_OUT_OF_RESOURCES;
310		goto out;
311	}
312
313	rsp_data = kzalloc(rsp_size, GFP_KERNEL);
314	if (!rsp_data) {
315		efi_status = EFI_OUT_OF_RESOURCES;
316		goto out_free_req;
317	}
318
319	req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
320	req_data->data_size = buffer_size;
321	req_data->name_offset = name_offs;
322	req_data->name_size = name_length * sizeof(*name);
323	req_data->guid_offset = guid_offs;
324	req_data->guid_size = sizeof(*guid);
325	req_data->length = req_size;
326
327	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
328	if (status < 0) {
329		efi_status = EFI_INVALID_PARAMETER;
330		goto out_free;
331	}
332
333	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
334
335	status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
336	if (status) {
337		efi_status = EFI_DEVICE_ERROR;
338		goto out_free;
339	}
340
341	if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE) {
342		efi_status = EFI_DEVICE_ERROR;
343		goto out_free;
344	}
345
346	if (rsp_data->length < sizeof(*rsp_data)) {
347		efi_status = EFI_DEVICE_ERROR;
348		goto out_free;
349	}
350
351	if (rsp_data->status) {
352		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
353			__func__, rsp_data->status);
354		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
355
356		/* Update size and attributes in case buffer is too small. */
357		if (efi_status == EFI_BUFFER_TOO_SMALL) {
358			*data_size = rsp_data->data_size;
359			if (attributes)
360				*attributes = rsp_data->attributes;
361		}
362
363		goto out_free;
364	}
365
366	if (rsp_data->length > rsp_size) {
367		efi_status = EFI_DEVICE_ERROR;
368		goto out_free;
369	}
370
371	if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length) {
372		efi_status = EFI_DEVICE_ERROR;
373		goto out_free;
374	}
375
376	/*
377	 * Note: We need to set attributes and data size even if the buffer is
378	 * too small and we won't copy any data. This is described in spec, so
379	 * that callers can either allocate a buffer properly (with two calls
380	 * to this function) or just read back attributes withouth having to
381	 * deal with that.
382	 *
383	 * Specifically:
384	 * - If we have a buffer size of zero and no buffer, just return the
385	 *   attributes, required size, and indicate success.
386	 * - If the buffer size is nonzero but too small, indicate that as an
387	 *   error.
388	 * - Otherwise, we are good to copy the data.
389	 *
390	 * Note that we have already ensured above that the buffer pointer is
391	 * non-NULL if its size is nonzero.
392	 */
393	*data_size = rsp_data->data_size;
394	if (attributes)
395		*attributes = rsp_data->attributes;
396
397	if (buffer_size == 0 && !data) {
398		efi_status = EFI_SUCCESS;
399		goto out_free;
400	}
401
402	if (buffer_size < rsp_data->data_size) {
403		efi_status = EFI_BUFFER_TOO_SMALL;
404		goto out_free;
405	}
406
407	memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
408
409out_free:
410	kfree(rsp_data);
411out_free_req:
412	kfree(req_data);
413out:
414	return efi_status;
415}
416
417static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
418					   const efi_guid_t *guid, u32 attributes,
419					   unsigned long data_size, const void *data)
420{
421	struct qsee_req_uefi_set_variable *req_data;
422	struct qsee_rsp_uefi_set_variable *rsp_data;
423	efi_status_t efi_status = EFI_SUCCESS;
424	unsigned long name_length;
425	size_t name_offs;
426	size_t guid_offs;
427	size_t data_offs;
428	size_t req_size;
429	ssize_t status;
430
431	if (!name || !guid)
432		return EFI_INVALID_PARAMETER;
433
434	name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
435	if (name_length > QSEE_MAX_NAME_LEN)
436		return EFI_INVALID_PARAMETER;
437
438	/*
439	 * Make sure we have some data if data_size is nonzero. Note that using
440	 * a size of zero is a valid use-case described in spec and deletes the
441	 * variable.
442	 */
443	if (data_size && !data)
444		return EFI_INVALID_PARAMETER;
445
446	req_size = qcuefi_buf_align_fields(
447		__field(*req_data)
448		__array_offs(*name, name_length, &name_offs)
449		__field_offs(*guid, &guid_offs)
450		__array_offs(u8, data_size, &data_offs)
451	);
452
453	req_data = kzalloc(req_size, GFP_KERNEL);
454	if (!req_data) {
455		efi_status = EFI_OUT_OF_RESOURCES;
456		goto out;
457	}
458
459	rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
460	if (!rsp_data) {
461		efi_status = EFI_OUT_OF_RESOURCES;
462		goto out_free_req;
463	}
464
465	req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
466	req_data->attributes = attributes;
467	req_data->name_offset = name_offs;
468	req_data->name_size = name_length * sizeof(*name);
469	req_data->guid_offset = guid_offs;
470	req_data->guid_size = sizeof(*guid);
471	req_data->data_offset = data_offs;
472	req_data->data_size = data_size;
473	req_data->length = req_size;
474
475	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
476	if (status < 0) {
477		efi_status = EFI_INVALID_PARAMETER;
478		goto out_free;
479	}
480
481	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
482
483	if (data_size)
484		memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
485
486	status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data,
487				       sizeof(*rsp_data));
488	if (status) {
489		efi_status = EFI_DEVICE_ERROR;
490		goto out_free;
491	}
492
493	if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE) {
494		efi_status = EFI_DEVICE_ERROR;
495		goto out_free;
496	}
497
498	if (rsp_data->length != sizeof(*rsp_data)) {
499		efi_status = EFI_DEVICE_ERROR;
500		goto out_free;
501	}
502
503	if (rsp_data->status) {
504		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
505			__func__, rsp_data->status);
506		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
507	}
508
509out_free:
510	kfree(rsp_data);
511out_free_req:
512	kfree(req_data);
513out:
514	return efi_status;
515}
516
517static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
518						unsigned long *name_size, efi_char16_t *name,
519						efi_guid_t *guid)
520{
521	struct qsee_req_uefi_get_next_variable *req_data;
522	struct qsee_rsp_uefi_get_next_variable *rsp_data;
523	efi_status_t efi_status = EFI_SUCCESS;
524	size_t guid_offs;
525	size_t name_offs;
526	size_t req_size;
527	size_t rsp_size;
528	ssize_t status;
529
530	if (!name_size || !name || !guid)
531		return EFI_INVALID_PARAMETER;
532
533	if (*name_size == 0)
534		return EFI_INVALID_PARAMETER;
535
536	req_size = qcuefi_buf_align_fields(
537		__field(*req_data)
538		__field_offs(*guid, &guid_offs)
539		__array_offs(*name, *name_size / sizeof(*name), &name_offs)
540	);
541
542	rsp_size = qcuefi_buf_align_fields(
543		__field(*rsp_data)
544		__field(*guid)
545		__array(*name, *name_size / sizeof(*name))
546	);
547
548	req_data = kzalloc(req_size, GFP_KERNEL);
549	if (!req_data) {
550		efi_status = EFI_OUT_OF_RESOURCES;
551		goto out;
552	}
553
554	rsp_data = kzalloc(rsp_size, GFP_KERNEL);
555	if (!rsp_data) {
556		efi_status = EFI_OUT_OF_RESOURCES;
557		goto out_free_req;
558	}
559
560	req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
561	req_data->guid_offset = guid_offs;
562	req_data->guid_size = sizeof(*guid);
563	req_data->name_offset = name_offs;
564	req_data->name_size = *name_size;
565	req_data->length = req_size;
566
567	memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
568	status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
569			      *name_size / sizeof(*name));
570	if (status < 0) {
571		efi_status = EFI_INVALID_PARAMETER;
572		goto out_free;
573	}
574
575	status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
576	if (status) {
577		efi_status = EFI_DEVICE_ERROR;
578		goto out_free;
579	}
580
581	if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE) {
582		efi_status = EFI_DEVICE_ERROR;
583		goto out_free;
584	}
585
586	if (rsp_data->length < sizeof(*rsp_data)) {
587		efi_status = EFI_DEVICE_ERROR;
588		goto out_free;
589	}
590
591	if (rsp_data->status) {
592		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
593			__func__, rsp_data->status);
594		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
595
596		/*
597		 * If the buffer to hold the name is too small, update the
598		 * name_size with the required size, so that callers can
599		 * reallocate it accordingly.
600		 */
601		if (efi_status == EFI_BUFFER_TOO_SMALL)
602			*name_size = rsp_data->name_size;
603
604		goto out_free;
605	}
606
607	if (rsp_data->length > rsp_size) {
608		efi_status = EFI_DEVICE_ERROR;
609		goto out_free;
610	}
611
612	if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length) {
613		efi_status = EFI_DEVICE_ERROR;
614		goto out_free;
615	}
616
617	if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length) {
618		efi_status = EFI_DEVICE_ERROR;
619		goto out_free;
620	}
621
622	if (rsp_data->name_size > *name_size) {
623		*name_size = rsp_data->name_size;
624		efi_status = EFI_BUFFER_TOO_SMALL;
625		goto out_free;
626	}
627
628	if (rsp_data->guid_size != sizeof(*guid)) {
629		efi_status = EFI_DEVICE_ERROR;
630		goto out_free;
631	}
632
633	memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
634	status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
635			      rsp_data->name_size / sizeof(*name));
636	*name_size = rsp_data->name_size;
637
638	if (status < 0) {
639		/*
640		 * Return EFI_DEVICE_ERROR here because the buffer size should
641		 * have already been validated above, causing this function to
642		 * bail with EFI_BUFFER_TOO_SMALL.
643		 */
644		efi_status = EFI_DEVICE_ERROR;
645	}
646
647out_free:
648	kfree(rsp_data);
649out_free_req:
650	kfree(req_data);
651out:
652	return efi_status;
653}
654
655static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
656						  u64 *storage_space, u64 *remaining_space,
657						  u64 *max_variable_size)
658{
659	struct qsee_req_uefi_query_variable_info *req_data;
660	struct qsee_rsp_uefi_query_variable_info *rsp_data;
661	efi_status_t efi_status = EFI_SUCCESS;
662	int status;
663
664	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
665	if (!req_data) {
666		efi_status = EFI_OUT_OF_RESOURCES;
667		goto out;
668	}
669
670	rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
671	if (!rsp_data) {
672		efi_status = EFI_OUT_OF_RESOURCES;
673		goto out_free_req;
674	}
675
676	req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
677	req_data->attributes = attr;
678	req_data->length = sizeof(*req_data);
679
680	status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data,
681				       sizeof(*rsp_data));
682	if (status) {
683		efi_status = EFI_DEVICE_ERROR;
684		goto out_free;
685	}
686
687	if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO) {
688		efi_status = EFI_DEVICE_ERROR;
689		goto out_free;
690	}
691
692	if (rsp_data->length != sizeof(*rsp_data)) {
693		efi_status = EFI_DEVICE_ERROR;
694		goto out_free;
695	}
696
697	if (rsp_data->status) {
698		dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
699			__func__, rsp_data->status);
700		efi_status = qsee_uefi_status_to_efi(rsp_data->status);
701		goto out_free;
702	}
703
704	if (storage_space)
705		*storage_space = rsp_data->storage_space;
706
707	if (remaining_space)
708		*remaining_space = rsp_data->remaining_space;
709
710	if (max_variable_size)
711		*max_variable_size = rsp_data->max_variable_size;
712
713out_free:
714	kfree(rsp_data);
715out_free_req:
716	kfree(req_data);
717out:
718	return efi_status;
719}
720
721/* -- Global efivar interface. ---------------------------------------------- */
722
723static struct qcuefi_client *__qcuefi;
724static DEFINE_MUTEX(__qcuefi_lock);
725
726static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
727{
728	mutex_lock(&__qcuefi_lock);
729
730	if (qcuefi && __qcuefi) {
731		mutex_unlock(&__qcuefi_lock);
732		return -EEXIST;
733	}
734
735	__qcuefi = qcuefi;
736
737	mutex_unlock(&__qcuefi_lock);
738	return 0;
739}
740
741static struct qcuefi_client *qcuefi_acquire(void)
742{
743	mutex_lock(&__qcuefi_lock);
744	return __qcuefi;
745}
746
747static void qcuefi_release(void)
748{
749	mutex_unlock(&__qcuefi_lock);
750}
751
752static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
753					unsigned long *data_size, void *data)
754{
755	struct qcuefi_client *qcuefi;
756	efi_status_t status;
757
758	qcuefi = qcuefi_acquire();
759	if (!qcuefi)
760		return EFI_NOT_READY;
761
762	status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
763
764	qcuefi_release();
765	return status;
766}
767
768static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
769					u32 attr, unsigned long data_size, void *data)
770{
771	struct qcuefi_client *qcuefi;
772	efi_status_t status;
773
774	qcuefi = qcuefi_acquire();
775	if (!qcuefi)
776		return EFI_NOT_READY;
777
778	status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
779
780	qcuefi_release();
781	return status;
782}
783
784static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
785					     efi_guid_t *vendor)
786{
787	struct qcuefi_client *qcuefi;
788	efi_status_t status;
789
790	qcuefi = qcuefi_acquire();
791	if (!qcuefi)
792		return EFI_NOT_READY;
793
794	status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
795
796	qcuefi_release();
797	return status;
798}
799
800static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
801					       u64 *max_variable_size)
802{
803	struct qcuefi_client *qcuefi;
804	efi_status_t status;
805
806	qcuefi = qcuefi_acquire();
807	if (!qcuefi)
808		return EFI_NOT_READY;
809
810	status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
811					       max_variable_size);
812
813	qcuefi_release();
814	return status;
815}
816
817static const struct efivar_operations qcom_efivar_ops = {
818	.get_variable = qcuefi_get_variable,
819	.set_variable = qcuefi_set_variable,
820	.get_next_variable = qcuefi_get_next_variable,
821	.query_variable_info = qcuefi_query_variable_info,
822};
823
824/* -- Driver setup. --------------------------------------------------------- */
825
826static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
827				 const struct auxiliary_device_id *aux_dev_id)
828{
829	struct qcuefi_client *qcuefi;
830	int status;
831
832	qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
833	if (!qcuefi)
834		return -ENOMEM;
835
836	qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
837
838	auxiliary_set_drvdata(aux_dev, qcuefi);
839	status = qcuefi_set_reference(qcuefi);
840	if (status)
841		return status;
842
843	status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
844	if (status)
845		qcuefi_set_reference(NULL);
846
847	return status;
848}
849
850static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
851{
852	struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
853
854	efivars_unregister(&qcuefi->efivars);
855	qcuefi_set_reference(NULL);
856}
857
858static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
859	{ .name = "qcom_qseecom.uefisecapp" },
860	{}
861};
862MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
863
864static struct auxiliary_driver qcom_uefisecapp_driver = {
865	.probe = qcom_uefisecapp_probe,
866	.remove = qcom_uefisecapp_remove,
867	.id_table = qcom_uefisecapp_id_table,
868	.driver = {
869		.name = "qcom_qseecom_uefisecapp",
870		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
871	},
872};
873module_auxiliary_driver(qcom_uefisecapp_driver);
874
875MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
876MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
877MODULE_LICENSE("GPL");