Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
26428 views
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 <[email protected]>
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
281
static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
282
{
283
return &qcuefi->client->aux_dev.dev;
284
}
285
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
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
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
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
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
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
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
725
static void qcuefi_release(void)
726
{
727
mutex_unlock(&__qcuefi_lock);
728
}
729
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
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
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
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
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
memset(&pool_config, 0, sizeof(pool_config));
818
pool_config.initial_size = SZ_4K;
819
pool_config.policy = QCOM_TZMEM_POLICY_MULTIPLIER;
820
pool_config.increment = 2;
821
pool_config.max_size = SZ_256K;
822
823
qcuefi->mempool = devm_qcom_tzmem_pool_new(&aux_dev->dev, &pool_config);
824
if (IS_ERR(qcuefi->mempool))
825
return PTR_ERR(qcuefi->mempool);
826
827
auxiliary_set_drvdata(aux_dev, qcuefi);
828
status = qcuefi_set_reference(qcuefi);
829
if (status)
830
return status;
831
832
status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
833
if (status)
834
qcuefi_set_reference(NULL);
835
836
return status;
837
}
838
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 <[email protected]>");
865
MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
866
MODULE_LICENSE("GPL");
867
868