1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
4 * Provides access to UEFI variables on platforms where they are secured by the
5 * aforementioned Secure Execution Environment (SEE) application.
6 *
7 * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
8 */
9
10 #include <linux/efi.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/sizes.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19 #include <linux/ucs2_string.h>
20
21 #include <linux/firmware/qcom/qcom_qseecom.h>
22 #include <linux/firmware/qcom/qcom_scm.h>
23 #include <linux/firmware/qcom/qcom_tzmem.h>
24
25 /* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
26
27 /* Maximum length of name string with null-terminator */
28 #define QSEE_MAX_NAME_LEN 1024
29
30 #define QSEE_CMD_UEFI(x) (0x8000 | (x))
31 #define QSEE_CMD_UEFI_GET_VARIABLE QSEE_CMD_UEFI(0)
32 #define QSEE_CMD_UEFI_SET_VARIABLE QSEE_CMD_UEFI(1)
33 #define QSEE_CMD_UEFI_GET_NEXT_VARIABLE QSEE_CMD_UEFI(2)
34 #define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO QSEE_CMD_UEFI(3)
35
36 /**
37 * struct qsee_req_uefi_get_variable - Request for GetVariable command.
38 * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
39 * @length: Length of the request in bytes, including this struct and any
40 * parameters (name, GUID) stored after it as well as any padding
41 * thereof for alignment.
42 * @name_offset: Offset from the start of this struct to where the variable
43 * name is stored (as utf-16 string), in bytes.
44 * @name_size: Size of the name parameter in bytes, including null-terminator.
45 * @guid_offset: Offset from the start of this struct to where the GUID
46 * parameter is stored, in bytes.
47 * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
48 * @data_size: Size of the output buffer, in bytes.
49 */
50 struct qsee_req_uefi_get_variable {
51 u32 command_id;
52 u32 length;
53 u32 name_offset;
54 u32 name_size;
55 u32 guid_offset;
56 u32 guid_size;
57 u32 data_size;
58 } __packed;
59
60 /**
61 * struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
62 * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
63 * @length: Length of the response in bytes, including this struct and the
64 * returned data.
65 * @status: Status of this command.
66 * @attributes: EFI variable attributes.
67 * @data_offset: Offset from the start of this struct to where the data is
68 * stored, in bytes.
69 * @data_size: Size of the returned data, in bytes. In case status indicates
70 * that the buffer is too small, this will be the size required
71 * to store the EFI variable data.
72 */
73 struct qsee_rsp_uefi_get_variable {
74 u32 command_id;
75 u32 length;
76 u32 status;
77 u32 attributes;
78 u32 data_offset;
79 u32 data_size;
80 } __packed;
81
82 /**
83 * struct qsee_req_uefi_set_variable - Request for the SetVariable command.
84 * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
85 * @length: Length of the request in bytes, including this struct and any
86 * parameters (name, GUID, data) stored after it as well as any
87 * padding thereof required for alignment.
88 * @name_offset: Offset from the start of this struct to where the variable
89 * name is stored (as utf-16 string), in bytes.
90 * @name_size: Size of the name parameter in bytes, including null-terminator.
91 * @guid_offset: Offset from the start of this struct to where the GUID
92 * parameter is stored, in bytes.
93 * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
94 * @attributes: The EFI variable attributes to set for this variable.
95 * @data_offset: Offset from the start of this struct to where the EFI variable
96 * data is stored, in bytes.
97 * @data_size: Size of EFI variable data, in bytes.
98 *
99 */
100 struct qsee_req_uefi_set_variable {
101 u32 command_id;
102 u32 length;
103 u32 name_offset;
104 u32 name_size;
105 u32 guid_offset;
106 u32 guid_size;
107 u32 attributes;
108 u32 data_offset;
109 u32 data_size;
110 } __packed;
111
112 /**
113 * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
114 * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
115 * @length: The length of this response, i.e. the size of this struct in
116 * bytes.
117 * @status: Status of this command.
118 * @_unknown1: Unknown response field.
119 * @_unknown2: Unknown response field.
120 */
121 struct qsee_rsp_uefi_set_variable {
122 u32 command_id;
123 u32 length;
124 u32 status;
125 u32 _unknown1;
126 u32 _unknown2;
127 } __packed;
128
129 /**
130 * struct qsee_req_uefi_get_next_variable - Request for the
131 * GetNextVariableName command.
132 * @command_id: The ID of the command. Must be
133 * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
134 * @length: Length of the request in bytes, including this struct and any
135 * parameters (name, GUID) stored after it as well as any padding
136 * thereof for alignment.
137 * @guid_offset: Offset from the start of this struct to where the GUID
138 * parameter is stored, in bytes.
139 * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
140 * @name_offset: Offset from the start of this struct to where the variable
141 * name is stored (as utf-16 string), in bytes.
142 * @name_size: Size of the name parameter in bytes, including null-terminator.
143 */
144 struct qsee_req_uefi_get_next_variable {
145 u32 command_id;
146 u32 length;
147 u32 guid_offset;
148 u32 guid_size;
149 u32 name_offset;
150 u32 name_size;
151 } __packed;
152
153 /**
154 * struct qsee_rsp_uefi_get_next_variable - Response for the
155 * GetNextVariableName command.
156 * @command_id: The ID of the command. Should be
157 * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
158 * @length: Length of the response in bytes, including this struct and any
159 * parameters (name, GUID) stored after it as well as any padding
160 * thereof for alignment.
161 * @status: Status of this command.
162 * @guid_offset: Offset from the start of this struct to where the GUID
163 * parameter is stored, in bytes.
164 * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
165 * @name_offset: Offset from the start of this struct to where the variable
166 * name is stored (as utf-16 string), in bytes.
167 * @name_size: Size of the name parameter in bytes, including null-terminator.
168 */
169 struct qsee_rsp_uefi_get_next_variable {
170 u32 command_id;
171 u32 length;
172 u32 status;
173 u32 guid_offset;
174 u32 guid_size;
175 u32 name_offset;
176 u32 name_size;
177 } __packed;
178
179 /**
180 * struct qsee_req_uefi_query_variable_info - Response for the
181 * GetNextVariableName command.
182 * @command_id: The ID of the command. Must be
183 * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
184 * @length: The length of this request, i.e. the size of this struct in
185 * bytes.
186 * @attributes: The storage attributes to query the info for.
187 */
188 struct qsee_req_uefi_query_variable_info {
189 u32 command_id;
190 u32 length;
191 u32 attributes;
192 } __packed;
193
194 /**
195 * struct qsee_rsp_uefi_query_variable_info - Response for the
196 * GetNextVariableName command.
197 * @command_id: The ID of the command. Must be
198 * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
199 * @length: The length of this response, i.e. the size of this
200 * struct in bytes.
201 * @status: Status of this command.
202 * @_pad: Padding.
203 * @storage_space: Full storage space size, in bytes.
204 * @remaining_space: Free storage space available, in bytes.
205 * @max_variable_size: Maximum variable data size, in bytes.
206 */
207 struct qsee_rsp_uefi_query_variable_info {
208 u32 command_id;
209 u32 length;
210 u32 status;
211 u32 _pad;
212 u64 storage_space;
213 u64 remaining_space;
214 u64 max_variable_size;
215 } __packed;
216
217 /* -- Alignment helpers ----------------------------------------------------- */
218
219 /*
220 * Helper macro to ensure proper alignment of types (fields and arrays) when
221 * stored in some (contiguous) buffer.
222 *
223 * Note: The driver from which this one has been reverse-engineered expects an
224 * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
225 * however, has an alignment of 4 byte (32 bits). So far, this seems to work
226 * fine here. See also the comment on the typedef of efi_guid_t.
227 *
228 * Note: It looks like uefisecapp is quite picky about how the memory passed to
229 * it is structured and aligned. In particular the request/response setup used
230 * for QSEE_CMD_UEFI_GET_VARIABLE. While qcom_qseecom_app_send(), in theory,
231 * accepts separate buffers/addresses for the request and response parts, in
232 * practice, however, it seems to expect them to be both part of a larger
233 * contiguous block. We initially allocated separate buffers for the request
234 * and response but this caused the QSEE_CMD_UEFI_GET_VARIABLE command to
235 * either not write any response to the response buffer or outright crash the
236 * device. Therefore, we now allocate a single contiguous block of DMA memory
237 * for both and properly align the data using the macros below. In particular,
238 * request and response structs are aligned at 8 byte (via __reqdata_offs()),
239 * following the driver that this has been reverse-engineered from.
240 */
241 #define qcuefi_buf_align_fields(fields...) \
242 ({ \
243 size_t __len = 0; \
244 fields \
245 __len; \
246 })
247
248 #define __field_impl(size, align, offset) \
249 ({ \
250 size_t *__offset = (offset); \
251 size_t __aligned; \
252 \
253 __aligned = ALIGN(__len, align); \
254 __len = __aligned + (size); \
255 \
256 if (__offset) \
257 *__offset = __aligned; \
258 });
259
260 #define __array_offs(type, count, offset) \
261 __field_impl(sizeof(type) * (count), __alignof__(type), offset)
262
263 #define __array_offs_aligned(type, count, align, offset) \
264 __field_impl(sizeof(type) * (count), align, offset)
265
266 #define __reqdata_offs(size, offset) \
267 __array_offs_aligned(u8, size, 8, offset)
268
269 #define __array(type, count) __array_offs(type, count, NULL)
270 #define __field_offs(type, offset) __array_offs(type, 1, offset)
271 #define __field(type) __array_offs(type, 1, NULL)
272
273 /* -- UEFI app interface. --------------------------------------------------- */
274
275 struct qcuefi_client {
276 struct qseecom_client *client;
277 struct efivars efivars;
278 struct qcom_tzmem_pool *mempool;
279 };
280
qcuefi_dev(struct qcuefi_client * qcuefi)281 static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
282 {
283 return &qcuefi->client->aux_dev.dev;
284 }
285
qsee_uefi_status_to_efi(u32 status)286 static 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
qsee_uefi_get_variable(struct qcuefi_client * qcuefi,const efi_char16_t * name,const efi_guid_t * guid,u32 * attributes,unsigned long * data_size,void * data)294 static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
295 const efi_guid_t *guid, u32 *attributes,
296 unsigned long *data_size, void *data)
297 {
298 struct qsee_req_uefi_get_variable *req_data;
299 struct qsee_rsp_uefi_get_variable *rsp_data;
300 void *cmd_buf __free(qcom_tzmem) = NULL;
301 unsigned long buffer_size = *data_size;
302 unsigned long name_length;
303 efi_status_t efi_status;
304 size_t cmd_buf_size;
305 size_t guid_offs;
306 size_t name_offs;
307 size_t req_size;
308 size_t rsp_size;
309 size_t req_offs;
310 size_t rsp_offs;
311 ssize_t status;
312
313 if (!name || !guid)
314 return EFI_INVALID_PARAMETER;
315
316 name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
317 if (name_length > QSEE_MAX_NAME_LEN)
318 return EFI_INVALID_PARAMETER;
319
320 if (buffer_size && !data)
321 return EFI_INVALID_PARAMETER;
322
323 req_size = qcuefi_buf_align_fields(
324 __field(*req_data)
325 __array_offs(*name, name_length, &name_offs)
326 __field_offs(*guid, &guid_offs)
327 );
328
329 rsp_size = qcuefi_buf_align_fields(
330 __field(*rsp_data)
331 __array(u8, buffer_size)
332 );
333
334 cmd_buf_size = qcuefi_buf_align_fields(
335 __reqdata_offs(req_size, &req_offs)
336 __reqdata_offs(rsp_size, &rsp_offs)
337 );
338
339 cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
340 if (!cmd_buf)
341 return EFI_OUT_OF_RESOURCES;
342
343 req_data = cmd_buf + req_offs;
344 rsp_data = cmd_buf + rsp_offs;
345
346 req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
347 req_data->data_size = buffer_size;
348 req_data->name_offset = name_offs;
349 req_data->name_size = name_length * sizeof(*name);
350 req_data->guid_offset = guid_offs;
351 req_data->guid_size = sizeof(*guid);
352 req_data->length = req_size;
353
354 status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
355 if (status < 0)
356 return EFI_INVALID_PARAMETER;
357
358 memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
359
360 status = qcom_qseecom_app_send(qcuefi->client,
361 cmd_buf + req_offs, req_size,
362 cmd_buf + rsp_offs, rsp_size);
363 if (status)
364 return EFI_DEVICE_ERROR;
365
366 if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE)
367 return EFI_DEVICE_ERROR;
368
369 if (rsp_data->length < sizeof(*rsp_data))
370 return EFI_DEVICE_ERROR;
371
372 if (rsp_data->status) {
373 dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
374 __func__, rsp_data->status);
375 efi_status = qsee_uefi_status_to_efi(rsp_data->status);
376
377 /* Update size and attributes in case buffer is too small. */
378 if (efi_status == EFI_BUFFER_TOO_SMALL) {
379 *data_size = rsp_data->data_size;
380 if (attributes)
381 *attributes = rsp_data->attributes;
382 }
383
384 return qsee_uefi_status_to_efi(rsp_data->status);
385 }
386
387 if (rsp_data->length > rsp_size)
388 return EFI_DEVICE_ERROR;
389
390 if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length)
391 return EFI_DEVICE_ERROR;
392
393 /*
394 * Note: We need to set attributes and data size even if the buffer is
395 * too small and we won't copy any data. This is described in spec, so
396 * that callers can either allocate a buffer properly (with two calls
397 * to this function) or just read back attributes withouth having to
398 * deal with that.
399 *
400 * Specifically:
401 * - If we have a buffer size of zero and no buffer, just return the
402 * attributes, required size, and indicate success.
403 * - If the buffer size is nonzero but too small, indicate that as an
404 * error.
405 * - Otherwise, we are good to copy the data.
406 *
407 * Note that we have already ensured above that the buffer pointer is
408 * non-NULL if its size is nonzero.
409 */
410 *data_size = rsp_data->data_size;
411 if (attributes)
412 *attributes = rsp_data->attributes;
413
414 if (buffer_size == 0 && !data)
415 return EFI_SUCCESS;
416
417 if (buffer_size < rsp_data->data_size)
418 return EFI_BUFFER_TOO_SMALL;
419
420 memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
421
422 return EFI_SUCCESS;
423 }
424
qsee_uefi_set_variable(struct qcuefi_client * qcuefi,const efi_char16_t * name,const efi_guid_t * guid,u32 attributes,unsigned long data_size,const void * data)425 static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
426 const efi_guid_t *guid, u32 attributes,
427 unsigned long data_size, const void *data)
428 {
429 struct qsee_req_uefi_set_variable *req_data;
430 struct qsee_rsp_uefi_set_variable *rsp_data;
431 void *cmd_buf __free(qcom_tzmem) = NULL;
432 unsigned long name_length;
433 size_t cmd_buf_size;
434 size_t name_offs;
435 size_t guid_offs;
436 size_t data_offs;
437 size_t req_size;
438 size_t req_offs;
439 size_t rsp_offs;
440 ssize_t status;
441
442 if (!name || !guid)
443 return EFI_INVALID_PARAMETER;
444
445 name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
446 if (name_length > QSEE_MAX_NAME_LEN)
447 return EFI_INVALID_PARAMETER;
448
449 /*
450 * Make sure we have some data if data_size is nonzero. Note that using
451 * a size of zero is a valid use-case described in spec and deletes the
452 * variable.
453 */
454 if (data_size && !data)
455 return EFI_INVALID_PARAMETER;
456
457 req_size = qcuefi_buf_align_fields(
458 __field(*req_data)
459 __array_offs(*name, name_length, &name_offs)
460 __field_offs(*guid, &guid_offs)
461 __array_offs(u8, data_size, &data_offs)
462 );
463
464 cmd_buf_size = qcuefi_buf_align_fields(
465 __reqdata_offs(req_size, &req_offs)
466 __reqdata_offs(sizeof(*rsp_data), &rsp_offs)
467 );
468
469 cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
470 if (!cmd_buf)
471 return EFI_OUT_OF_RESOURCES;
472
473 req_data = cmd_buf + req_offs;
474 rsp_data = cmd_buf + rsp_offs;
475
476 req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
477 req_data->attributes = attributes;
478 req_data->name_offset = name_offs;
479 req_data->name_size = name_length * sizeof(*name);
480 req_data->guid_offset = guid_offs;
481 req_data->guid_size = sizeof(*guid);
482 req_data->data_offset = data_offs;
483 req_data->data_size = data_size;
484 req_data->length = req_size;
485
486 status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
487 if (status < 0)
488 return EFI_INVALID_PARAMETER;
489
490 memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
491
492 if (data_size)
493 memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
494
495 status = qcom_qseecom_app_send(qcuefi->client,
496 cmd_buf + req_offs, req_size,
497 cmd_buf + rsp_offs, sizeof(*rsp_data));
498 if (status)
499 return EFI_DEVICE_ERROR;
500
501 if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE)
502 return EFI_DEVICE_ERROR;
503
504 if (rsp_data->length != sizeof(*rsp_data))
505 return EFI_DEVICE_ERROR;
506
507 if (rsp_data->status) {
508 dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
509 __func__, rsp_data->status);
510 return qsee_uefi_status_to_efi(rsp_data->status);
511 }
512
513 return EFI_SUCCESS;
514 }
515
qsee_uefi_get_next_variable(struct qcuefi_client * qcuefi,unsigned long * name_size,efi_char16_t * name,efi_guid_t * guid)516 static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
517 unsigned long *name_size, efi_char16_t *name,
518 efi_guid_t *guid)
519 {
520 struct qsee_req_uefi_get_next_variable *req_data;
521 struct qsee_rsp_uefi_get_next_variable *rsp_data;
522 void *cmd_buf __free(qcom_tzmem) = NULL;
523 efi_status_t efi_status;
524 size_t cmd_buf_size;
525 size_t guid_offs;
526 size_t name_offs;
527 size_t req_size;
528 size_t rsp_size;
529 size_t req_offs;
530 size_t rsp_offs;
531 ssize_t status;
532
533 if (!name_size || !name || !guid)
534 return EFI_INVALID_PARAMETER;
535
536 if (*name_size == 0)
537 return EFI_INVALID_PARAMETER;
538
539 req_size = qcuefi_buf_align_fields(
540 __field(*req_data)
541 __field_offs(*guid, &guid_offs)
542 __array_offs(*name, *name_size / sizeof(*name), &name_offs)
543 );
544
545 rsp_size = qcuefi_buf_align_fields(
546 __field(*rsp_data)
547 __field(*guid)
548 __array(*name, *name_size / sizeof(*name))
549 );
550
551 cmd_buf_size = qcuefi_buf_align_fields(
552 __reqdata_offs(req_size, &req_offs)
553 __reqdata_offs(rsp_size, &rsp_offs)
554 );
555
556 cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
557 if (!cmd_buf)
558 return EFI_OUT_OF_RESOURCES;
559
560 req_data = cmd_buf + req_offs;
561 rsp_data = cmd_buf + rsp_offs;
562
563 req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
564 req_data->guid_offset = guid_offs;
565 req_data->guid_size = sizeof(*guid);
566 req_data->name_offset = name_offs;
567 req_data->name_size = *name_size;
568 req_data->length = req_size;
569
570 memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
571 status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
572 *name_size / sizeof(*name));
573 if (status < 0)
574 return EFI_INVALID_PARAMETER;
575
576 status = qcom_qseecom_app_send(qcuefi->client,
577 cmd_buf + req_offs, req_size,
578 cmd_buf + rsp_offs, rsp_size);
579 if (status)
580 return EFI_DEVICE_ERROR;
581
582 if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE)
583 return EFI_DEVICE_ERROR;
584
585 if (rsp_data->length < sizeof(*rsp_data))
586 return EFI_DEVICE_ERROR;
587
588 if (rsp_data->status) {
589 dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
590 __func__, rsp_data->status);
591 efi_status = qsee_uefi_status_to_efi(rsp_data->status);
592
593 /*
594 * If the buffer to hold the name is too small, update the
595 * name_size with the required size, so that callers can
596 * reallocate it accordingly.
597 */
598 if (efi_status == EFI_BUFFER_TOO_SMALL)
599 *name_size = rsp_data->name_size;
600
601 return efi_status;
602 }
603
604 if (rsp_data->length > rsp_size)
605 return EFI_DEVICE_ERROR;
606
607 if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length)
608 return EFI_DEVICE_ERROR;
609
610 if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length)
611 return EFI_DEVICE_ERROR;
612
613 if (rsp_data->name_size > *name_size) {
614 *name_size = rsp_data->name_size;
615 return EFI_BUFFER_TOO_SMALL;
616 }
617
618 if (rsp_data->guid_size != sizeof(*guid))
619 return EFI_DEVICE_ERROR;
620
621 memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
622 status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
623 rsp_data->name_size / sizeof(*name));
624 *name_size = rsp_data->name_size;
625
626 if (status < 0)
627 /*
628 * Return EFI_DEVICE_ERROR here because the buffer size should
629 * have already been validated above, causing this function to
630 * bail with EFI_BUFFER_TOO_SMALL.
631 */
632 return EFI_DEVICE_ERROR;
633
634 return EFI_SUCCESS;
635 }
636
qsee_uefi_query_variable_info(struct qcuefi_client * qcuefi,u32 attr,u64 * storage_space,u64 * remaining_space,u64 * max_variable_size)637 static 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
697 static struct qcuefi_client *__qcuefi;
698 static DEFINE_MUTEX(__qcuefi_lock);
699
qcuefi_set_reference(struct qcuefi_client * qcuefi)700 static 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
qcuefi_acquire(void)715 static 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
qcuefi_release(void)725 static void qcuefi_release(void)
726 {
727 mutex_unlock(&__qcuefi_lock);
728 }
729
qcuefi_get_variable(efi_char16_t * name,efi_guid_t * vendor,u32 * attr,unsigned long * data_size,void * data)730 static 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
qcuefi_set_variable(efi_char16_t * name,efi_guid_t * vendor,u32 attr,unsigned long data_size,void * data)746 static 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
qcuefi_get_next_variable(unsigned long * name_size,efi_char16_t * name,efi_guid_t * vendor)762 static 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
qcuefi_query_variable_info(u32 attr,u64 * storage_space,u64 * remaining_space,u64 * max_variable_size)778 static 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
795 static 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
qcom_uefisecapp_probe(struct auxiliary_device * aux_dev,const struct auxiliary_device_id * aux_dev_id)804 static 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
qcom_uefisecapp_remove(struct auxiliary_device * aux_dev)839 static 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
847 static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
848 { .name = "qcom_qseecom.uefisecapp" },
849 {}
850 };
851 MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
852
853 static 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 };
862 module_auxiliary_driver(qcom_uefisecapp_driver);
863
864 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
865 MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
866 MODULE_LICENSE("GPL");
867