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 * 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
272struct qcuefi_client {
273	struct qseecom_client *client;
274	struct efivars efivars;
275};
276
277static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
278{
279	return &qcuefi->client->aux_dev.dev;
280}
281
282static 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
290static 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
437out_free:
438	qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
439out:
440	return efi_status;
441}
442
443static 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
543out_free:
544	qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
545out:
546	return efi_status;
547}
548
549static 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
688out_free:
689	qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
690out:
691	return efi_status;
692}
693
694static 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
760out_free:
761	qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
762out:
763	return efi_status;
764}
765
766/* -- Global efivar interface. ---------------------------------------------- */
767
768static struct qcuefi_client *__qcuefi;
769static DEFINE_MUTEX(__qcuefi_lock);
770
771static 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
786static struct qcuefi_client *qcuefi_acquire(void)
787{
788	mutex_lock(&__qcuefi_lock);
789	return __qcuefi;
790}
791
792static void qcuefi_release(void)
793{
794	mutex_unlock(&__qcuefi_lock);
795}
796
797static 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
813static 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
829static 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
845static 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
862static 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
871static 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
895static 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
903static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
904	{ .name = "qcom_qseecom.uefisecapp" },
905	{}
906};
907MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
908
909static 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};
918module_auxiliary_driver(qcom_uefisecapp_driver);
919
920MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
921MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
922MODULE_LICENSE("GPL");
923