brintos

brintos / linux-shallow public Read only

0
0
Text · 25.9 KiB · 447246b Raw
867 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).4 * Provides access to UEFI variables on platforms where they are secured by the5 * 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			102429 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 any40 *               parameters (name, GUID) stored after it as well as any padding41 *               thereof for alignment.42 * @name_offset: Offset from the start of this struct to where the variable43 *               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 GUID46 *               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 the64 *               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 is68 *               stored, in bytes.69 * @data_size:   Size of the returned data, in bytes. In case status indicates70 *               that the buffer is too small, this will be the size required71 *               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 any86 *               parameters (name, GUID, data) stored after it as well as any87 *               padding thereof required for alignment.88 * @name_offset: Offset from the start of this struct to where the variable89 *               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 GUID92 *               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 variable96 *               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 in116 *               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 the131 * GetNextVariableName command.132 * @command_id:  The ID of the command. Must be133 *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.134 * @length:      Length of the request in bytes, including this struct and any135 *               parameters (name, GUID) stored after it as well as any padding136 *               thereof for alignment.137 * @guid_offset: Offset from the start of this struct to where the GUID138 *               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 variable141 *               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 the155 * GetNextVariableName command.156 * @command_id:  The ID of the command. Should be157 *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.158 * @length:      Length of the response in bytes, including this struct and any159 *               parameters (name, GUID) stored after it as well as any padding160 *               thereof for alignment.161 * @status:      Status of this command.162 * @guid_offset: Offset from the start of this struct to where the GUID163 *               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 variable166 *               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 the181 * GetNextVariableName command.182 * @command_id: The ID of the command. Must be183 *              %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.184 * @length:     The length of this request, i.e. the size of this struct in185 *              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 the196 * GetNextVariableName command.197 * @command_id:        The ID of the command. Must be198 *                     %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.199 * @length:            The length of this response, i.e. the size of this200 *                     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) when221 * stored in some (contiguous) buffer.222 *223 * Note: The driver from which this one has been reverse-engineered expects an224 * 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 work226 * 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 to229 * it is structured and aligned. In particular the request/response setup used230 * for QSEE_CMD_UEFI_GET_VARIABLE. While qcom_qseecom_app_send(), in theory,231 * accepts separate buffers/addresses for the request and response parts, in232 * practice, however, it seems to expect them to be both part of a larger233 * contiguous block. We initially allocated separate buffers for the request234 * and response but this caused the QSEE_CMD_UEFI_GET_VARIABLE command to235 * either not write any response to the response buffer or outright crash the236 * device. Therefore, we now allocate a single contiguous block of DMA memory237 * 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 is395	 * too small and we won't copy any data. This is described in spec, so396	 * that callers can either allocate a buffer properly (with two calls397	 * to this function) or just read back attributes withouth having to398	 * deal with that.399	 *400	 * Specifically:401	 * - If we have a buffer size of zero and no buffer, just return the402	 *   attributes, required size, and indicate success.403	 * - If the buffer size is nonzero but too small, indicate that as an404	 *   error.405	 * - Otherwise, we are good to copy the data.406	 *407	 * Note that we have already ensured above that the buffer pointer is408	 * 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 using451	 * a size of zero is a valid use-case described in spec and deletes the452	 * 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 the595		 * name_size with the required size, so that callers can596		 * 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 should629		 * have already been validated above, causing this function to630		 * 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	auxiliary_set_drvdata(aux_dev, qcuefi);818	status = qcuefi_set_reference(qcuefi);819	if (status)820		return status;821 822	status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);823	if (status)824		qcuefi_set_reference(NULL);825 826	memset(&pool_config, 0, sizeof(pool_config));827	pool_config.initial_size = SZ_4K;828	pool_config.policy = QCOM_TZMEM_POLICY_MULTIPLIER;829	pool_config.increment = 2;830	pool_config.max_size = SZ_256K;831 832	qcuefi->mempool = devm_qcom_tzmem_pool_new(&aux_dev->dev, &pool_config);833	if (IS_ERR(qcuefi->mempool))834		return PTR_ERR(qcuefi->mempool);835 836	return status;837}838 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");867