File Index
Files and directories
Sign in
FILE

qcom_qseecom_uefisecapp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c C
  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 */
 50struct 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 */
 73struct 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 */
100struct 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 */
121struct 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 */
144struct 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 */
169struct 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 */
188struct 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 */
207struct 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
275struct qcuefi_client {
276	struct qseecom_client *client;
277	struct efivars efivars;
278	struct qcom_tzmem_pool *mempool;
279};
280
281static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
282{
283	return &qcuefi->client->aux_dev.dev;
284}
285
286static 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
294static 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
425static 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
516static 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
637static 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
697static struct qcuefi_client *__qcuefi;
698static DEFINE_MUTEX(__qcuefi_lock);
699
700static 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
715static 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
725static void qcuefi_release(void)
726{
727	mutex_unlock(&__qcuefi_lock);
728}
729
730static 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
746static 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
762static 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
778static 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
795static 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
804static 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	memset(&pool_config, 0, sizeof(pool_config));
818	pool_config.initial_size = SZ_4K;
819	pool_config.policy = QCOM_TZMEM_POLICY_MULTIPLIER;
820	pool_config.increment = 2;
821	pool_config.max_size = SZ_256K;
822
823	qcuefi->mempool = devm_qcom_tzmem_pool_new(&aux_dev->dev, &pool_config);
824	if (IS_ERR(qcuefi->mempool))
825		return PTR_ERR(qcuefi->mempool);
826
827	auxiliary_set_drvdata(aux_dev, qcuefi);
828	status = qcuefi_set_reference(qcuefi);
829	if (status)
830		return status;
831
832	status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
833	if (status)
834		qcuefi_set_reference(NULL);
835
836	return status;
837}
838
839static 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
847static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
848	{ .name = "qcom_qseecom.uefisecapp" },
849	{}
850};
851MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
852
853static 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};
862module_auxiliary_driver(qcom_uefisecapp_driver);
863
864MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
865MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
866MODULE_LICENSE("GPL");
~/ Read-only file preview.