blob: 24e0663ebd421d23838e0d8dbb77453d2ea9c599 [file] [log] [blame]
Ilias Apalodimas77a364f2020-05-17 22:25:44 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * EFI variable service via OP-TEE
4 *
5 * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
6 * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
7 */
8
9#include <common.h>
10#include <efi.h>
11#include <efi_api.h>
12#include <efi_loader.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020013#include <efi_variable.h>
Ilias Apalodimas77a364f2020-05-17 22:25:44 +030014#include <tee.h>
15#include <malloc.h>
16#include <mm_communication.h>
17
18static efi_uintn_t max_buffer_size; /* comm + var + func + data */
19static efi_uintn_t max_payload_size; /* func + data */
20
21struct mm_connection {
22 struct udevice *tee;
23 u32 session;
24};
25
26/**
27 * get_connection() - Retrieve OP-TEE session for a specific UUID.
28 *
29 * @conn: session buffer to fill
30 * Return: status code
31 */
32static int get_connection(struct mm_connection *conn)
33{
34 static const struct tee_optee_ta_uuid uuid = PTA_STMM_UUID;
35 struct udevice *tee = NULL;
36 struct tee_open_session_arg arg;
37 int rc;
38
39 tee = tee_find_device(tee, NULL, NULL, NULL);
40 if (!tee)
41 return -ENODEV;
42
43 memset(&arg, 0, sizeof(arg));
44 tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
45 rc = tee_open_session(tee, &arg, 0, NULL);
46 if (!rc) {
47 conn->tee = tee;
48 conn->session = arg.session;
49 }
50
51 return rc;
52}
53
54/**
55 * optee_mm_communicate() - Pass a buffer to StandaloneMM running in OP-TEE
56 *
57 * @comm_buf: locally allocted communcation buffer
58 * @dsize: buffer size
59 * Return: status code
60 */
61static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
62{
63 ulong buf_size;
64 efi_status_t ret;
65 struct efi_mm_communicate_header *mm_hdr;
66 struct mm_connection conn = { NULL, 0 };
67 struct tee_invoke_arg arg;
68 struct tee_param param[2];
69 struct tee_shm *shm = NULL;
70 int rc;
71
72 if (!comm_buf)
73 return EFI_INVALID_PARAMETER;
74
75 mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
76 buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
77
78 if (dsize != buf_size)
79 return EFI_INVALID_PARAMETER;
80
81 rc = get_connection(&conn);
82 if (rc) {
83 log_err("Unable to open OP-TEE session (err=%d)\n", rc);
84 return EFI_UNSUPPORTED;
85 }
86
87 if (tee_shm_register(conn.tee, comm_buf, buf_size, 0, &shm)) {
88 log_err("Unable to register shared memory\n");
89 return EFI_UNSUPPORTED;
90 }
91
92 memset(&arg, 0, sizeof(arg));
93 arg.func = PTA_STMM_CMDID_COMMUNICATE;
94 arg.session = conn.session;
95
96 memset(param, 0, sizeof(param));
97 param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
98 param[0].u.memref.size = buf_size;
99 param[0].u.memref.shm = shm;
100 param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
101
102 rc = tee_invoke_func(conn.tee, &arg, 2, param);
103 if (rc)
104 return EFI_INVALID_PARAMETER;
105 tee_shm_free(shm);
106 tee_close_session(conn.tee, conn.session);
107
108 switch (param[1].u.value.a) {
109 case ARM_SMC_MM_RET_SUCCESS:
110 ret = EFI_SUCCESS;
111 break;
112
113 case ARM_SMC_MM_RET_INVALID_PARAMS:
114 ret = EFI_INVALID_PARAMETER;
115 break;
116
117 case ARM_SMC_MM_RET_DENIED:
118 ret = EFI_ACCESS_DENIED;
119 break;
120
121 case ARM_SMC_MM_RET_NO_MEMORY:
122 ret = EFI_OUT_OF_RESOURCES;
123 break;
124
125 default:
126 ret = EFI_ACCESS_DENIED;
127 }
128
129 return ret;
130}
131
132/**
133 * mm_communicate() - Adjust the cmonnucation buffer to StandAlonneMM and send
134 * it to OP-TEE
135 *
136 * @comm_buf: locally allocted communcation buffer
137 * @dsize: buffer size
138 * Return: status code
139 */
140static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
141{
142 efi_status_t ret;
143 struct efi_mm_communicate_header *mm_hdr;
144 struct smm_variable_communicate_header *var_hdr;
145
146 dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
147 mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
148 var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
149
150 ret = optee_mm_communicate(comm_buf, dsize);
151 if (ret != EFI_SUCCESS) {
152 log_err("%s failed!\n", __func__);
153 return ret;
154 }
155
156 return var_hdr->ret_status;
157}
158
159/**
160 * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
161 * header data.
162 *
163 * @dptr: pointer address of the corresponding StandAloneMM
164 * function
165 * @payload_size: buffer size
166 * @func: standAloneMM function number
167 * @ret: EFI return code
168 * Return: buffer or NULL
169 */
170static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
171 efi_uintn_t func, efi_status_t *ret)
172{
173 const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
174 struct efi_mm_communicate_header *mm_hdr;
175 struct smm_variable_communicate_header *var_hdr;
176 u8 *comm_buf;
177
178 /* In the init function we initialize max_buffer_size with
179 * get_max_payload(). So skip the test if max_buffer_size is initialized
180 * StandAloneMM will perform similar checks and drop the buffer if it's
181 * too long
182 */
183 if (max_buffer_size && max_buffer_size <
184 (MM_COMMUNICATE_HEADER_SIZE +
185 MM_VARIABLE_COMMUNICATE_SIZE +
186 payload_size)) {
187 *ret = EFI_INVALID_PARAMETER;
188 return NULL;
189 }
190
191 comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
192 MM_VARIABLE_COMMUNICATE_SIZE +
193 payload_size);
194 if (!comm_buf) {
195 *ret = EFI_OUT_OF_RESOURCES;
196 return NULL;
197 }
198
199 mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
200 guidcpy(&mm_hdr->header_guid, &mm_var_guid);
201 mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
202
203 var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
204 var_hdr->function = func;
205 if (dptr)
206 *dptr = var_hdr->data;
207 *ret = EFI_SUCCESS;
208
209 return comm_buf;
210}
211
212/**
213 * get_max_payload() - Get variable payload size from StandAloneMM.
214 *
215 * @size: size of the variable in storage
216 * Return: status code
217 */
218efi_status_t EFIAPI get_max_payload(efi_uintn_t *size)
219{
220 struct smm_variable_payload_size *var_payload = NULL;
221 efi_uintn_t payload_size;
222 u8 *comm_buf = NULL;
223 efi_status_t ret;
224
225 if (!size) {
226 ret = EFI_INVALID_PARAMETER;
227 goto out;
228 }
229
230 payload_size = sizeof(*var_payload);
231 comm_buf = setup_mm_hdr((void **)&var_payload, payload_size,
232 SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &ret);
233 if (!comm_buf)
234 goto out;
235
236 ret = mm_communicate(comm_buf, payload_size);
237 if (ret != EFI_SUCCESS)
238 goto out;
239
240 *size = var_payload->size;
241
242out:
243 free(comm_buf);
244 return ret;
245}
246
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300247/*
248 * StMM can store internal attributes and properties for variables, i.e enabling
249 * R/O variables
250 */
251static efi_status_t set_property_int(u16 *variable_name, efi_uintn_t name_size,
252 const efi_guid_t *vendor,
253 struct var_check_property *var_property)
254{
255 struct smm_variable_var_check_property *smm_property;
256 efi_uintn_t payload_size;
257 u8 *comm_buf = NULL;
258 efi_status_t ret;
259
260 payload_size = sizeof(*smm_property) + name_size;
261 if (payload_size > max_payload_size) {
262 ret = EFI_INVALID_PARAMETER;
263 goto out;
264 }
265 comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
266 SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
267 &ret);
268 if (!comm_buf)
269 goto out;
270
271 guidcpy(&smm_property->guid, vendor);
272 smm_property->name_size = name_size;
273 memcpy(&smm_property->property, var_property,
274 sizeof(smm_property->property));
275 memcpy(smm_property->name, variable_name, name_size);
276
277 ret = mm_communicate(comm_buf, payload_size);
278
279out:
280 free(comm_buf);
281 return ret;
282}
283
284static efi_status_t get_property_int(u16 *variable_name, efi_uintn_t name_size,
285 const efi_guid_t *vendor,
286 struct var_check_property *var_property)
287{
288 struct smm_variable_var_check_property *smm_property;
289 efi_uintn_t payload_size;
290 u8 *comm_buf = NULL;
291 efi_status_t ret;
292
293 memset(var_property, 0, sizeof(*var_property));
294 payload_size = sizeof(*smm_property) + name_size;
295 if (payload_size > max_payload_size) {
296 ret = EFI_INVALID_PARAMETER;
297 goto out;
298 }
299 comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
300 SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
301 &ret);
302 if (!comm_buf)
303 goto out;
304
305 guidcpy(&smm_property->guid, vendor);
306 smm_property->name_size = name_size;
307 memcpy(smm_property->name, variable_name, name_size);
308
309 ret = mm_communicate(comm_buf, payload_size);
310 /*
311 * Currently only R/O property is supported in StMM.
312 * Variables that are not set to R/O will not set the property in StMM
313 * and the call will return EFI_NOT_FOUND. We are setting the
314 * properties to 0x0 so checking against that is enough for the
315 * EFI_NOT_FOUND case.
316 */
317 if (ret == EFI_NOT_FOUND)
318 ret = EFI_SUCCESS;
319 if (ret != EFI_SUCCESS)
320 goto out;
321 memcpy(var_property, &smm_property->property, sizeof(*var_property));
322
323out:
324 free(comm_buf);
325 return ret;
326}
327
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200328efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
329 u32 *attributes, efi_uintn_t *data_size,
330 void *data, u64 *timep)
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300331{
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300332 struct var_check_property var_property;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300333 struct smm_variable_access *var_acc;
334 efi_uintn_t payload_size;
335 efi_uintn_t name_size;
336 efi_uintn_t tmp_dsize;
337 u8 *comm_buf = NULL;
338 efi_status_t ret;
339
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200340 if (!variable_name || !vendor || !data_size) {
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300341 ret = EFI_INVALID_PARAMETER;
342 goto out;
343 }
344
345 /* Check payload size */
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200346 name_size = u16_strsize(variable_name);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300347 if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
348 ret = EFI_INVALID_PARAMETER;
349 goto out;
350 }
351
352 /* Trim output buffer size */
353 tmp_dsize = *data_size;
354 if (name_size + tmp_dsize >
355 max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
356 tmp_dsize = max_payload_size -
357 MM_VARIABLE_ACCESS_HEADER_SIZE -
358 name_size;
359 }
360
361 /* Get communication buffer and initialize header */
362 payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
363 comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
364 SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
365 if (!comm_buf)
366 goto out;
367
368 /* Fill in contents */
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200369 guidcpy(&var_acc->guid, vendor);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300370 var_acc->data_size = tmp_dsize;
371 var_acc->name_size = name_size;
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200372 var_acc->attr = attributes ? *attributes : 0;
373 memcpy(var_acc->name, variable_name, name_size);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300374
375 /* Communicate */
376 ret = mm_communicate(comm_buf, payload_size);
377 if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
378 /* Update with reported data size for trimmed case */
379 *data_size = var_acc->data_size;
380 }
381 if (ret != EFI_SUCCESS)
382 goto out;
383
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300384 ret = get_property_int(variable_name, name_size, vendor, &var_property);
385 if (ret != EFI_SUCCESS)
386 goto out;
387
388 if (attributes) {
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200389 *attributes = var_acc->attr;
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300390 if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
391 *attributes |= EFI_VARIABLE_READ_ONLY;
392 }
393
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300394 if (data)
395 memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
396 var_acc->data_size);
397 else
398 ret = EFI_INVALID_PARAMETER;
399
400out:
401 free(comm_buf);
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200402 return ret;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300403}
404
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200405efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
406 u16 *variable_name,
407 efi_guid_t *guid)
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300408{
409 struct smm_variable_getnext *var_getnext;
410 efi_uintn_t payload_size;
411 efi_uintn_t out_name_size;
412 efi_uintn_t in_name_size;
413 efi_uintn_t tmp_dsize;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300414 u8 *comm_buf = NULL;
415 efi_status_t ret;
416
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300417 if (!variable_name_size || !variable_name || !guid) {
418 ret = EFI_INVALID_PARAMETER;
419 goto out;
420 }
421
422 out_name_size = *variable_name_size;
423 in_name_size = u16_strsize(variable_name);
424
425 if (out_name_size < in_name_size) {
426 ret = EFI_INVALID_PARAMETER;
427 goto out;
428 }
429
Ilias Apalodimas24105b82020-07-01 16:41:25 +0300430 if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300431 ret = EFI_INVALID_PARAMETER;
432 goto out;
433 }
434
435 /* Trim output buffer size */
436 tmp_dsize = *variable_name_size;
Ilias Apalodimas24105b82020-07-01 16:41:25 +0300437 if (in_name_size + tmp_dsize >
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300438 max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
439 tmp_dsize = max_payload_size -
440 MM_VARIABLE_GET_NEXT_HEADER_SIZE -
Ilias Apalodimas24105b82020-07-01 16:41:25 +0300441 in_name_size;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300442 }
443
444 payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
445 comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
446 SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
447 &ret);
448 if (!comm_buf)
449 goto out;
450
451 /* Fill in contents */
452 guidcpy(&var_getnext->guid, guid);
453 var_getnext->name_size = out_name_size;
454 memcpy(var_getnext->name, variable_name, in_name_size);
455 memset((u8 *)var_getnext->name + in_name_size, 0x0,
456 out_name_size - in_name_size);
457
458 /* Communicate */
459 ret = mm_communicate(comm_buf, payload_size);
460 if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
461 /* Update with reported data size for trimmed case */
462 *variable_name_size = var_getnext->name_size;
463 }
464 if (ret != EFI_SUCCESS)
465 goto out;
466
467 guidcpy(guid, &var_getnext->guid);
468 memcpy(variable_name, (u8 *)var_getnext->name,
469 var_getnext->name_size);
470
471out:
472 free(comm_buf);
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200473 return ret;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300474}
475
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200476efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
477 u32 attributes, efi_uintn_t data_size,
478 const void *data, bool ro_check)
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300479{
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300480 efi_status_t ret, alt_ret = EFI_SUCCESS;
481 struct var_check_property var_property;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300482 struct smm_variable_access *var_acc;
483 efi_uintn_t payload_size;
484 efi_uintn_t name_size;
485 u8 *comm_buf = NULL;
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300486 bool ro;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300487
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200488 if (!variable_name || variable_name[0] == 0 || !vendor) {
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300489 ret = EFI_INVALID_PARAMETER;
490 goto out;
491 }
492 if (data_size > 0 && !data) {
493 ret = EFI_INVALID_PARAMETER;
494 goto out;
495 }
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300496 /* Check payload size */
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200497 name_size = u16_strsize(variable_name);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300498 payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
499 if (payload_size > max_payload_size) {
500 ret = EFI_INVALID_PARAMETER;
501 goto out;
502 }
503
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300504 /*
505 * Allocate the buffer early, before switching to RW (if needed)
506 * so we won't need to account for any failures in reading/setting
507 * the properties, if the allocation fails
508 */
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300509 comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
510 SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
511 if (!comm_buf)
512 goto out;
513
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300514 ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
515 attributes &= EFI_VARIABLE_MASK;
516
517 /*
518 * The API has the ability to override RO flags. If no RO check was
519 * requested switch the variable to RW for the duration of this call
520 */
521 ret = get_property_int(variable_name, name_size, vendor,
522 &var_property);
523 if (ret != EFI_SUCCESS)
524 goto out;
525
526 if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
527 /* Bypass r/o check */
528 if (!ro_check) {
529 var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
530 ret = set_property_int(variable_name, name_size, vendor, &var_property);
531 if (ret != EFI_SUCCESS)
532 goto out;
533 } else {
534 ret = EFI_WRITE_PROTECTED;
535 goto out;
536 }
537 }
538
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300539 /* Fill in contents */
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200540 guidcpy(&var_acc->guid, vendor);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300541 var_acc->data_size = data_size;
542 var_acc->name_size = name_size;
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200543 var_acc->attr = attributes;
544 memcpy(var_acc->name, variable_name, name_size);
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300545 memcpy((u8 *)var_acc->name + name_size, data, data_size);
546
547 /* Communicate */
548 ret = mm_communicate(comm_buf, payload_size);
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300549 if (ret != EFI_SUCCESS)
550 alt_ret = ret;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300551
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300552 if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
553 var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
554 var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
555 var_property.attributes = attributes;
556 var_property.minsize = 1;
557 var_property.maxsize = var_acc->data_size;
558 ret = set_property_int(variable_name, name_size, vendor, &var_property);
559 }
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300560out:
561 free(comm_buf);
Ilias Apalodimas5f1bce92020-07-09 23:00:40 +0300562 return alt_ret == EFI_SUCCESS ? ret : alt_ret;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300563}
564
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200565efi_status_t efi_query_variable_info_int(u32 attributes,
566 u64 *max_variable_storage_size,
567 u64 *remain_variable_storage_size,
568 u64 *max_variable_size)
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300569{
570 struct smm_variable_query_info *mm_query_info;
571 efi_uintn_t payload_size;
572 efi_status_t ret;
573 u8 *comm_buf;
574
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300575 payload_size = sizeof(*mm_query_info);
576 comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
577 SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
578 &ret);
579 if (!comm_buf)
580 goto out;
581
582 mm_query_info->attr = attributes;
583 ret = mm_communicate(comm_buf, payload_size);
584 if (ret != EFI_SUCCESS)
585 goto out;
586 *max_variable_storage_size = mm_query_info->max_variable_storage;
587 *remain_variable_storage_size =
588 mm_query_info->remaining_variable_storage;
589 *max_variable_size = mm_query_info->max_variable_size;
590
591out:
592 free(comm_buf);
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200593 return ret;
Ilias Apalodimas77a364f2020-05-17 22:25:44 +0300594}
595
596/**
597 * efi_get_variable_runtime() - runtime implementation of GetVariable()
598 *
599 * @variable_name: name of the variable
600 * @guid: vendor GUID
601 * @attributes: attributes of the variable
602 * @data_size: size of the buffer to which the variable value is copied
603 * @data: buffer to which the variable value is copied
604 * Return: status code
605 */
606static efi_status_t __efi_runtime EFIAPI
607efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
608 u32 *attributes, efi_uintn_t *data_size, void *data)
609{
610 return EFI_UNSUPPORTED;
611}
612
613/**
614 * efi_get_next_variable_name_runtime() - runtime implementation of
615 * GetNextVariable()
616 *
617 * @variable_name_size: size of variable_name buffer in byte
618 * @variable_name: name of uefi variable's name in u16
619 * @guid: vendor's guid
620 * Return: status code
621 */
622static efi_status_t __efi_runtime EFIAPI
623efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
624 u16 *variable_name, efi_guid_t *guid)
625{
626 return EFI_UNSUPPORTED;
627}
628
629/**
630 * efi_query_variable_info() - get information about EFI variables
631 *
632 * This function implements the QueryVariableInfo() runtime service.
633 *
634 * See the Unified Extensible Firmware Interface (UEFI) specification for
635 * details.
636 *
637 * @attributes: bitmask to select variables to be
638 * queried
639 * @maximum_variable_storage_size: maximum size of storage area for the
640 * selected variable types
641 * @remaining_variable_storage_size: remaining size of storage are for the
642 * selected variable types
643 * @maximum_variable_size: maximum size of a variable of the
644 * selected type
645 * Return: status code
646 */
647efi_status_t EFIAPI __efi_runtime
648efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
649 u64 *remain_variable_storage_size,
650 u64 *max_variable_size)
651{
652 return EFI_UNSUPPORTED;
653}
654
655/**
656 * efi_set_variable_runtime() - runtime implementation of SetVariable()
657 *
658 * @variable_name: name of the variable
659 * @guid: vendor GUID
660 * @attributes: attributes of the variable
661 * @data_size: size of the buffer with the variable value
662 * @data: buffer with the variable value
663 * Return: status code
664 */
665static efi_status_t __efi_runtime EFIAPI
666efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
667 u32 attributes, efi_uintn_t data_size,
668 const void *data)
669{
670 return EFI_UNSUPPORTED;
671}
672
673/**
674 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
675 */
676void efi_variables_boot_exit_notify(void)
677{
678 u8 *comm_buf;
679 efi_status_t ret;
680
681 comm_buf = setup_mm_hdr(NULL, 0,
682 SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &ret);
683 if (comm_buf)
684 ret = mm_communicate(comm_buf, 0);
685 else
686 ret = EFI_NOT_FOUND;
687
688 if (ret != EFI_SUCCESS)
689 log_err("Unable to notify StMM for ExitBootServices\n");
690 free(comm_buf);
691
692 /* Update runtime service table */
693 efi_runtime_services.query_variable_info =
694 efi_query_variable_info_runtime;
695 efi_runtime_services.get_variable = efi_get_variable_runtime;
696 efi_runtime_services.get_next_variable_name =
697 efi_get_next_variable_name_runtime;
698 efi_runtime_services.set_variable = efi_set_variable_runtime;
699 efi_update_table_header_crc32(&efi_runtime_services.hdr);
700}
701
702/**
703 * efi_init_variables() - initialize variable services
704 *
705 * Return: status code
706 */
707efi_status_t efi_init_variables(void)
708{
709 efi_status_t ret;
710
711 ret = get_max_payload(&max_payload_size);
712 if (ret != EFI_SUCCESS)
713 return ret;
714
715 max_buffer_size = MM_COMMUNICATE_HEADER_SIZE +
716 MM_VARIABLE_COMMUNICATE_SIZE +
717 max_payload_size;
718
719 return EFI_SUCCESS;
720}