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