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(s: 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(size: req_size, GFP_KERNEL);
308 if (!req_data) {
309 efi_status = EFI_OUT_OF_RESOURCES;
310 goto out;
311 }
312
313 rsp_data = kzalloc(size: 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(dst: ((void *)req_data) + req_data->name_offset, src: name, count: 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(client: qcuefi->client, req: req_data, req_size, rsp: 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(status: 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(objp: rsp_data);
411out_free_req:
412 kfree(objp: 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(s: 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(size: req_size, GFP_KERNEL);
454 if (!req_data) {
455 efi_status = EFI_OUT_OF_RESOURCES;
456 goto out;
457 }
458
459 rsp_data = kzalloc(size: 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(dst: ((void *)req_data) + req_data->name_offset, src: name, count: 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(client: qcuefi->client, req: req_data, req_size, rsp: rsp_data,
487 rsp_size: 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(status: rsp_data->status);
507 }
508
509out_free:
510 kfree(objp: rsp_data);
511out_free_req:
512 kfree(objp: 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(size: req_size, GFP_KERNEL);
549 if (!req_data) {
550 efi_status = EFI_OUT_OF_RESOURCES;
551 goto out;
552 }
553
554 rsp_data = kzalloc(size: 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(dst: ((void *)req_data) + req_data->name_offset, src: name,
569 count: *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(client: qcuefi->client, req: req_data, req_size, rsp: 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(status: 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(dst: name, src: ((void *)rsp_data) + rsp_data->name_offset,
635 count: 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(objp: rsp_data);
649out_free_req:
650 kfree(objp: 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(size: 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(size: 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(client: qcuefi->client, req: req_data, req_size: sizeof(*req_data), rsp: rsp_data,
681 rsp_size: 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(status: 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(objp: rsp_data);
715out_free_req:
716 kfree(objp: 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(lock: &__qcuefi_lock);
732 return -EEXIST;
733 }
734
735 __qcuefi = qcuefi;
736
737 mutex_unlock(lock: &__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(lock: &__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, guid: vendor, attributes: 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, guid: vendor, attributes: 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, guid: 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(dev: &aux_dev->dev, size: 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(auxdev: aux_dev, data: qcuefi);
839 status = qcuefi_set_reference(qcuefi);
840 if (status)
841 return status;
842
843 status = efivars_register(efivars: &qcuefi->efivars, ops: &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(auxdev: aux_dev);
853
854 efivars_unregister(efivars: &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");
878

source code of linux/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c