xref: /linux/drivers/firmware/efi/stmm/tee_stmm_efi.c (revision f283371efd6a0ec1713349cd8c12fa5ffb19c60a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI variable service via TEE
4  *
5  *  Copyright (C) 2022 Linaro
6  */
7 
8 #include <linux/efi.h>
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11 #include <linux/tee.h>
12 #include <linux/tee_drv.h>
13 #include <linux/ucs2_string.h>
14 #include "mm_communication.h"
15 
16 static struct efivars tee_efivars;
17 
18 static size_t max_buffer_size; /* comm + var + func + data */
19 static size_t max_payload_size; /* func + data */
20 
21 struct tee_stmm_efi_private {
22 	struct tee_context *ctx;
23 	u32 session;
24 	struct device *dev;
25 };
26 
27 static struct tee_stmm_efi_private pvt_data;
28 
29 /* UUID of the stmm PTA */
30 static const struct tee_client_device_id tee_stmm_efi_id_table[] = {
31 	{PTA_STMM_UUID},
32 	{}
33 };
34 
tee_ctx_match(struct tee_ioctl_version_data * ver,const void * data)35 static int tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
36 {
37 	/* currently only OP-TEE is supported as a communication path */
38 	if (ver->impl_id == TEE_IMPL_ID_OPTEE)
39 		return 1;
40 	else
41 		return 0;
42 }
43 
44 /**
45  * tee_mm_communicate() - Pass a buffer to StandaloneMM running in TEE
46  *
47  * @comm_buf:		locally allocated communication buffer
48  * @dsize:		buffer size
49  * Return:		status code
50  */
tee_mm_communicate(void * comm_buf,size_t dsize)51 static efi_status_t tee_mm_communicate(void *comm_buf, size_t dsize)
52 {
53 	size_t buf_size;
54 	struct efi_mm_communicate_header *mm_hdr;
55 	struct tee_ioctl_invoke_arg arg;
56 	struct tee_param param[4];
57 	struct tee_shm *shm = NULL;
58 	int rc;
59 
60 	if (!comm_buf)
61 		return EFI_INVALID_PARAMETER;
62 
63 	mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
64 	buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
65 
66 	if (dsize != buf_size)
67 		return EFI_INVALID_PARAMETER;
68 
69 	shm = tee_shm_register_kernel_buf(pvt_data.ctx, comm_buf, buf_size);
70 	if (IS_ERR(shm)) {
71 		dev_err(pvt_data.dev, "Unable to register shared memory\n");
72 		return EFI_UNSUPPORTED;
73 	}
74 
75 	memset(&arg, 0, sizeof(arg));
76 	arg.func = PTA_STMM_CMD_COMMUNICATE;
77 	arg.session = pvt_data.session;
78 	arg.num_params = 4;
79 
80 	memset(param, 0, sizeof(param));
81 	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
82 	param[0].u.memref.size = buf_size;
83 	param[0].u.memref.shm = shm;
84 	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
85 	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
86 	param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
87 
88 	rc = tee_client_invoke_func(pvt_data.ctx, &arg, param);
89 	tee_shm_free(shm);
90 
91 	if (rc < 0 || arg.ret != 0) {
92 		dev_err(pvt_data.dev,
93 			"PTA_STMM_CMD_COMMUNICATE invoke error: 0x%x\n", arg.ret);
94 		return EFI_DEVICE_ERROR;
95 	}
96 
97 	switch (param[1].u.value.a) {
98 	case ARM_SVC_SPM_RET_SUCCESS:
99 		return EFI_SUCCESS;
100 
101 	case ARM_SVC_SPM_RET_INVALID_PARAMS:
102 		return EFI_INVALID_PARAMETER;
103 
104 	case ARM_SVC_SPM_RET_DENIED:
105 		return EFI_ACCESS_DENIED;
106 
107 	case ARM_SVC_SPM_RET_NO_MEMORY:
108 		return EFI_OUT_OF_RESOURCES;
109 
110 	default:
111 		return EFI_ACCESS_DENIED;
112 	}
113 }
114 
115 /**
116  * mm_communicate() - Adjust the communication buffer to StandAlonneMM and send
117  * it to TEE
118  *
119  * @comm_buf:		locally allocated communication buffer, buffer should
120  *			be enough big to have some headers and payload
121  * @payload_size:	payload size
122  * Return:		status code
123  */
mm_communicate(u8 * comm_buf,size_t payload_size)124 static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size)
125 {
126 	size_t dsize;
127 	efi_status_t ret;
128 	struct efi_mm_communicate_header *mm_hdr;
129 	struct smm_variable_communicate_header *var_hdr;
130 
131 	dsize = payload_size + MM_COMMUNICATE_HEADER_SIZE +
132 		MM_VARIABLE_COMMUNICATE_SIZE;
133 	mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
134 	var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
135 
136 	ret = tee_mm_communicate(comm_buf, dsize);
137 	if (ret != EFI_SUCCESS) {
138 		dev_err(pvt_data.dev, "%s failed!\n", __func__);
139 		return ret;
140 	}
141 
142 	return var_hdr->ret_status;
143 }
144 
145 #define COMM_BUF_SIZE(__payload_size)	(MM_COMMUNICATE_HEADER_SIZE + \
146 					 MM_VARIABLE_COMMUNICATE_SIZE + \
147 					 (__payload_size))
148 
149 /**
150  * setup_mm_hdr() -	Allocate a buffer for StandAloneMM and initialize the
151  *			header data.
152  *
153  * @dptr:		pointer address to store allocated buffer
154  * @payload_size:	payload size
155  * @func:		standAloneMM function number
156  * Return:		pointer to corresponding StandAloneMM function buffer or NULL
157  */
setup_mm_hdr(u8 ** dptr,size_t payload_size,size_t func)158 static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func)
159 {
160 	const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
161 	struct efi_mm_communicate_header *mm_hdr;
162 	struct smm_variable_communicate_header *var_hdr;
163 	u8 *comm_buf;
164 
165 	/* In the init function we initialize max_buffer_size with
166 	 * get_max_payload(). So skip the test if max_buffer_size is initialized
167 	 * StandAloneMM will perform similar checks and drop the buffer if it's
168 	 * too long
169 	 */
170 	if (max_buffer_size &&
171 	    max_buffer_size < (MM_COMMUNICATE_HEADER_SIZE +
172 			       MM_VARIABLE_COMMUNICATE_SIZE + payload_size)) {
173 		return NULL;
174 	}
175 
176 	comm_buf = alloc_pages_exact(COMM_BUF_SIZE(payload_size),
177 				     GFP_KERNEL | __GFP_ZERO);
178 	if (!comm_buf)
179 		return NULL;
180 
181 	mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
182 	memcpy(&mm_hdr->header_guid, &mm_var_guid, sizeof(mm_hdr->header_guid));
183 	mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
184 
185 	var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
186 	var_hdr->function = func;
187 	*dptr = comm_buf;
188 
189 	return var_hdr->data;
190 }
191 
192 /**
193  * get_max_payload() - Get variable payload size from StandAloneMM.
194  *
195  * @size:    size of the variable in storage
196  * Return:   status code
197  */
get_max_payload(size_t * size)198 static efi_status_t get_max_payload(size_t *size)
199 {
200 	struct smm_variable_payload_size *var_payload = NULL;
201 	size_t payload_size;
202 	u8 *comm_buf = NULL;
203 	efi_status_t ret;
204 
205 	if (!size)
206 		return EFI_INVALID_PARAMETER;
207 
208 	payload_size = sizeof(*var_payload);
209 	var_payload = setup_mm_hdr(&comm_buf, payload_size,
210 				   SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE);
211 	if (!var_payload)
212 		return EFI_DEVICE_ERROR;
213 
214 	ret = mm_communicate(comm_buf, payload_size);
215 	if (ret != EFI_SUCCESS)
216 		goto out;
217 
218 	/* Make sure the buffer is big enough for storing variables */
219 	if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) {
220 		ret = EFI_DEVICE_ERROR;
221 		goto out;
222 	}
223 	*size = var_payload->size;
224 	/*
225 	 * There seems to be a bug in EDK2 miscalculating the boundaries and
226 	 * size checks, so deduct 2 more bytes to fulfill this requirement. Fix
227 	 * it up here to ensure backwards compatibility with older versions
228 	 * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c.
229 	 * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the
230 	 * flexible array member).
231 	 *
232 	 * size is guaranteed to be > 2 due to checks on the beginning.
233 	 */
234 	*size -= 2;
235 out:
236 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
237 	return ret;
238 }
239 
get_property_int(u16 * name,size_t name_size,const efi_guid_t * vendor,struct var_check_property * var_property)240 static efi_status_t get_property_int(u16 *name, size_t name_size,
241 				     const efi_guid_t *vendor,
242 				     struct var_check_property *var_property)
243 {
244 	struct smm_variable_var_check_property *smm_property;
245 	size_t payload_size;
246 	u8 *comm_buf = NULL;
247 	efi_status_t ret;
248 
249 	memset(var_property, 0, sizeof(*var_property));
250 	payload_size = sizeof(*smm_property) + name_size;
251 	if (payload_size > max_payload_size)
252 		return EFI_INVALID_PARAMETER;
253 
254 	smm_property = setup_mm_hdr(
255 		&comm_buf, payload_size,
256 		SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
257 	if (!smm_property)
258 		return EFI_DEVICE_ERROR;
259 
260 	memcpy(&smm_property->guid, vendor, sizeof(smm_property->guid));
261 	smm_property->name_size = name_size;
262 	memcpy(smm_property->name, name, name_size);
263 
264 	ret = mm_communicate(comm_buf, payload_size);
265 	/*
266 	 * Currently only R/O property is supported in StMM.
267 	 * Variables that are not set to R/O will not set the property in StMM
268 	 * and the call will return EFI_NOT_FOUND. We are setting the
269 	 * properties to 0x0 so checking against that is enough for the
270 	 * EFI_NOT_FOUND case.
271 	 */
272 	if (ret == EFI_NOT_FOUND)
273 		ret = EFI_SUCCESS;
274 	if (ret != EFI_SUCCESS)
275 		goto out;
276 	memcpy(var_property, &smm_property->property, sizeof(*var_property));
277 
278 out:
279 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
280 	return ret;
281 }
282 
tee_get_variable(u16 * name,efi_guid_t * vendor,u32 * attributes,unsigned long * data_size,void * data)283 static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor,
284 				     u32 *attributes, unsigned long *data_size,
285 				     void *data)
286 {
287 	struct var_check_property var_property;
288 	struct smm_variable_access *var_acc;
289 	size_t payload_size;
290 	size_t name_size;
291 	size_t tmp_dsize;
292 	u8 *comm_buf = NULL;
293 	efi_status_t ret;
294 
295 	if (!name || !vendor || !data_size)
296 		return EFI_INVALID_PARAMETER;
297 
298 	name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16);
299 	if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE)
300 		return EFI_INVALID_PARAMETER;
301 
302 	/* Trim output buffer size */
303 	tmp_dsize = *data_size;
304 	if (name_size + tmp_dsize >
305 	    max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
306 		tmp_dsize = max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE -
307 			    name_size;
308 	}
309 
310 	payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
311 	var_acc = setup_mm_hdr(&comm_buf, payload_size,
312 			       SMM_VARIABLE_FUNCTION_GET_VARIABLE);
313 	if (!var_acc)
314 		return EFI_DEVICE_ERROR;
315 
316 	/* Fill in contents */
317 	memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid));
318 	var_acc->data_size = tmp_dsize;
319 	var_acc->name_size = name_size;
320 	var_acc->attr = attributes ? *attributes : 0;
321 	memcpy(var_acc->name, name, name_size);
322 
323 	ret = mm_communicate(comm_buf, payload_size);
324 	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL)
325 		/* Update with reported data size for trimmed case */
326 		*data_size = var_acc->data_size;
327 	if (ret != EFI_SUCCESS)
328 		goto out;
329 
330 	ret = get_property_int(name, name_size, vendor, &var_property);
331 	if (ret != EFI_SUCCESS)
332 		goto out;
333 
334 	if (attributes)
335 		*attributes = var_acc->attr;
336 
337 	if (!data) {
338 		ret = EFI_INVALID_PARAMETER;
339 		goto out;
340 	}
341 	memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
342 	       var_acc->data_size);
343 out:
344 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
345 	return ret;
346 }
347 
tee_get_next_variable(unsigned long * name_size,efi_char16_t * name,efi_guid_t * guid)348 static efi_status_t tee_get_next_variable(unsigned long *name_size,
349 					  efi_char16_t *name, efi_guid_t *guid)
350 {
351 	struct smm_variable_getnext *var_getnext;
352 	size_t payload_size;
353 	size_t out_name_size;
354 	size_t in_name_size;
355 	u8 *comm_buf = NULL;
356 	efi_status_t ret;
357 
358 	if (!name_size || !name || !guid)
359 		return EFI_INVALID_PARAMETER;
360 
361 	out_name_size = *name_size;
362 	in_name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16);
363 
364 	if (out_name_size < in_name_size)
365 		return EFI_INVALID_PARAMETER;
366 
367 	if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
368 		return EFI_INVALID_PARAMETER;
369 
370 	/* Trim output buffer size */
371 	if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
372 		out_name_size =
373 			max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
374 
375 	payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
376 	var_getnext = setup_mm_hdr(&comm_buf, payload_size,
377 				SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
378 	if (!var_getnext)
379 		return EFI_DEVICE_ERROR;
380 
381 	/* Fill in contents */
382 	memcpy(&var_getnext->guid, guid, sizeof(var_getnext->guid));
383 	var_getnext->name_size = out_name_size;
384 	memcpy(var_getnext->name, name, in_name_size);
385 	memset((u8 *)var_getnext->name + in_name_size, 0x0,
386 	       out_name_size - in_name_size);
387 
388 	ret = mm_communicate(comm_buf, payload_size);
389 	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
390 		/* Update with reported data size for trimmed case */
391 		*name_size = var_getnext->name_size;
392 	}
393 	if (ret != EFI_SUCCESS)
394 		goto out;
395 
396 	memcpy(guid, &var_getnext->guid, sizeof(*guid));
397 	memcpy(name, var_getnext->name, var_getnext->name_size);
398 
399 out:
400 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
401 	return ret;
402 }
403 
tee_set_variable(efi_char16_t * name,efi_guid_t * vendor,u32 attributes,unsigned long data_size,void * data)404 static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor,
405 				     u32 attributes, unsigned long data_size,
406 				     void *data)
407 {
408 	efi_status_t ret;
409 	struct var_check_property var_property;
410 	struct smm_variable_access *var_acc;
411 	size_t payload_size;
412 	size_t name_size;
413 	u8 *comm_buf = NULL;
414 
415 	if (!name || name[0] == 0 || !vendor)
416 		return EFI_INVALID_PARAMETER;
417 
418 	if (data_size > 0 && !data)
419 		return EFI_INVALID_PARAMETER;
420 
421 	/* Check payload size */
422 	name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16);
423 	payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
424 	if (payload_size > max_payload_size)
425 		return EFI_INVALID_PARAMETER;
426 
427 	/*
428 	 * Allocate the buffer early, before switching to RW (if needed)
429 	 * so we won't need to account for any failures in reading/setting
430 	 * the properties, if the allocation fails
431 	 */
432 	var_acc = setup_mm_hdr(&comm_buf, payload_size,
433 			       SMM_VARIABLE_FUNCTION_SET_VARIABLE);
434 	if (!var_acc)
435 		return EFI_DEVICE_ERROR;
436 
437 	/*
438 	 * The API has the ability to override RO flags. If no RO check was
439 	 * requested switch the variable to RW for the duration of this call
440 	 */
441 	ret = get_property_int(name, name_size, vendor, &var_property);
442 	if (ret != EFI_SUCCESS) {
443 		dev_err(pvt_data.dev, "Getting variable property failed\n");
444 		goto out;
445 	}
446 
447 	if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
448 		ret = EFI_WRITE_PROTECTED;
449 		goto out;
450 	}
451 
452 	/* Fill in contents */
453 	memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid));
454 	var_acc->data_size = data_size;
455 	var_acc->name_size = name_size;
456 	var_acc->attr = attributes;
457 	memcpy(var_acc->name, name, name_size);
458 	memcpy((u8 *)var_acc->name + name_size, data, data_size);
459 
460 	ret = mm_communicate(comm_buf, payload_size);
461 	dev_dbg(pvt_data.dev, "Set Variable %s %d %lx\n", __FILE__, __LINE__, ret);
462 out:
463 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
464 	return ret;
465 }
466 
tee_set_variable_nonblocking(efi_char16_t * name,efi_guid_t * vendor,u32 attributes,unsigned long data_size,void * data)467 static efi_status_t tee_set_variable_nonblocking(efi_char16_t *name,
468 						 efi_guid_t *vendor,
469 						 u32 attributes,
470 						 unsigned long data_size,
471 						 void *data)
472 {
473 	return EFI_UNSUPPORTED;
474 }
475 
tee_query_variable_info(u32 attributes,u64 * max_variable_storage_size,u64 * remain_variable_storage_size,u64 * max_variable_size)476 static efi_status_t tee_query_variable_info(u32 attributes,
477 					    u64 *max_variable_storage_size,
478 					    u64 *remain_variable_storage_size,
479 					    u64 *max_variable_size)
480 {
481 	struct smm_variable_query_info *mm_query_info;
482 	size_t payload_size;
483 	efi_status_t ret;
484 	u8 *comm_buf;
485 
486 	payload_size = sizeof(*mm_query_info);
487 	mm_query_info = setup_mm_hdr(&comm_buf, payload_size,
488 				SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
489 	if (!mm_query_info)
490 		return EFI_DEVICE_ERROR;
491 
492 	mm_query_info->attr = attributes;
493 	ret = mm_communicate(comm_buf, payload_size);
494 	if (ret != EFI_SUCCESS)
495 		goto out;
496 	*max_variable_storage_size = mm_query_info->max_variable_storage;
497 	*remain_variable_storage_size =
498 		mm_query_info->remaining_variable_storage;
499 	*max_variable_size = mm_query_info->max_variable_size;
500 
501 out:
502 	free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size));
503 	return ret;
504 }
505 
tee_stmm_efi_close_context(void * data)506 static void tee_stmm_efi_close_context(void *data)
507 {
508 	tee_client_close_context(pvt_data.ctx);
509 }
510 
tee_stmm_efi_close_session(void * data)511 static void tee_stmm_efi_close_session(void *data)
512 {
513 	tee_client_close_session(pvt_data.ctx, pvt_data.session);
514 }
515 
tee_stmm_restore_efivars_generic_ops(void)516 static void tee_stmm_restore_efivars_generic_ops(void)
517 {
518 	efivars_unregister(&tee_efivars);
519 	efivars_generic_ops_register();
520 }
521 
522 static const struct efivar_operations tee_efivar_ops = {
523 	.get_variable			= tee_get_variable,
524 	.get_next_variable		= tee_get_next_variable,
525 	.set_variable			= tee_set_variable,
526 	.set_variable_nonblocking	= tee_set_variable_nonblocking,
527 	.query_variable_store		= efi_query_variable_store,
528 	.query_variable_info		= tee_query_variable_info,
529 };
530 
tee_stmm_efi_probe(struct tee_client_device * tee_dev)531 static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
532 {
533 	struct device *dev = &tee_dev->dev;
534 	struct tee_ioctl_open_session_arg sess_arg;
535 	efi_status_t ret;
536 	int rc;
537 
538 	pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, NULL);
539 	if (IS_ERR(pvt_data.ctx))
540 		return -ENODEV;
541 
542 	rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_context, NULL);
543 	if (rc)
544 		return rc;
545 
546 	/* Open session with StMM PTA */
547 	memset(&sess_arg, 0, sizeof(sess_arg));
548 	export_uuid(sess_arg.uuid, &tee_stmm_efi_id_table[0].uuid);
549 	rc = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
550 	if ((rc < 0) || (sess_arg.ret != 0)) {
551 		dev_err(dev, "tee_client_open_session failed, err: %x\n",
552 			sess_arg.ret);
553 		return -EINVAL;
554 	}
555 	pvt_data.session = sess_arg.session;
556 	pvt_data.dev = dev;
557 	rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_session, NULL);
558 	if (rc)
559 		return rc;
560 
561 	ret = get_max_payload(&max_payload_size);
562 	if (ret != EFI_SUCCESS)
563 		return -EIO;
564 
565 	max_buffer_size = MM_COMMUNICATE_HEADER_SIZE +
566 			  MM_VARIABLE_COMMUNICATE_SIZE +
567 			  max_payload_size;
568 
569 	efivars_generic_ops_unregister();
570 	pr_info("Using TEE-based EFI runtime variable services\n");
571 	efivars_register(&tee_efivars, &tee_efivar_ops);
572 
573 	return 0;
574 }
575 
tee_stmm_efi_remove(struct tee_client_device * dev)576 static void tee_stmm_efi_remove(struct tee_client_device *dev)
577 {
578 	tee_stmm_restore_efivars_generic_ops();
579 }
580 
581 MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
582 
583 static struct tee_client_driver tee_stmm_efi_driver = {
584 	.id_table	= tee_stmm_efi_id_table,
585 	.probe		= tee_stmm_efi_probe,
586 	.remove		= tee_stmm_efi_remove,
587 	.driver		= {
588 		.name		= "tee-stmm-efi",
589 	},
590 };
591 
592 module_tee_client_driver(tee_stmm_efi_driver);
593 
594 MODULE_LICENSE("GPL");
595 MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas@linaro.org>");
596 MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>");
597 MODULE_DESCRIPTION("TEE based EFI runtime variable service driver");
598