blob: 5f4aae60bf23f53b09cb0d9214993774f4cff19e [file] [log] [blame]
Ilias Apalodimasf042e472020-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 Schuchardtf2d2b3a2020-06-22 18:10:27 +020013#include <efi_variable.h>
Ilias Apalodimasf042e472020-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) {
Ilias Apalodimas5d1f79b2020-07-17 07:55:03 +0300109 case ARM_SVC_SPM_RET_SUCCESS:
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300110 ret = EFI_SUCCESS;
111 break;
112
Ilias Apalodimas5d1f79b2020-07-17 07:55:03 +0300113 case ARM_SVC_SPM_RET_INVALID_PARAMS:
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300114 ret = EFI_INVALID_PARAMETER;
115 break;
116
Ilias Apalodimas5d1f79b2020-07-17 07:55:03 +0300117 case ARM_SVC_SPM_RET_DENIED:
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300118 ret = EFI_ACCESS_DENIED;
119 break;
120
Ilias Apalodimas5d1f79b2020-07-17 07:55:03 +0300121 case ARM_SVC_SPM_RET_NO_MEMORY:
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300122 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 Apalodimasf96744b2020-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 Schuchardtf2d2b3a2020-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 Apalodimasf042e472020-05-17 22:25:44 +0300331{
Ilias Apalodimasf96744b2020-07-09 23:00:40 +0300332 struct var_check_property var_property;
Ilias Apalodimasf042e472020-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 Schuchardtf2d2b3a2020-06-22 18:10:27 +0200340 if (!variable_name || !vendor || !data_size) {
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300341 ret = EFI_INVALID_PARAMETER;
342 goto out;
343 }
344
345 /* Check payload size */
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200346 name_size = u16_strsize(variable_name);
Ilias Apalodimasf042e472020-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 Schuchardtf2d2b3a2020-06-22 18:10:27 +0200369 guidcpy(&var_acc->guid, vendor);
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300370 var_acc->data_size = tmp_dsize;
371 var_acc->name_size = name_size;
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200372 var_acc->attr = attributes ? *attributes : 0;
373 memcpy(var_acc->name, variable_name, name_size);
Ilias Apalodimasf042e472020-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 Apalodimasf96744b2020-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 Schuchardtf2d2b3a2020-06-22 18:10:27 +0200389 *attributes = var_acc->attr;
Ilias Apalodimasf96744b2020-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 Apalodimasf042e472020-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 Schuchardtf2d2b3a2020-06-22 18:10:27 +0200402 return ret;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300403}
404
Heinrich Schuchardt01df8cf2020-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 Apalodimasf042e472020-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 Apalodimasf042e472020-05-17 22:25:44 +0300414 u8 *comm_buf = NULL;
415 efi_status_t ret;
416
Ilias Apalodimasf042e472020-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 Apalodimasecb833a2020-07-01 16:41:25 +0300430 if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
Ilias Apalodimasf042e472020-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 Apalodimasecb833a2020-07-01 16:41:25 +0300437 if (in_name_size + tmp_dsize >
Ilias Apalodimasf042e472020-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 Apalodimasecb833a2020-07-01 16:41:25 +0300441 in_name_size;
Ilias Apalodimasf042e472020-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 Schuchardt01df8cf2020-06-26 17:57:48 +0200473 return ret;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300474}
475
Heinrich Schuchardtf2d2b3a2020-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 Apalodimasf042e472020-05-17 22:25:44 +0300479{
Ilias Apalodimasf96744b2020-07-09 23:00:40 +0300480 efi_status_t ret, alt_ret = EFI_SUCCESS;
481 struct var_check_property var_property;
Ilias Apalodimasf042e472020-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 Apalodimasf96744b2020-07-09 23:00:40 +0300486 bool ro;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300487
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200488 if (!variable_name || variable_name[0] == 0 || !vendor) {
Ilias Apalodimasf042e472020-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 Apalodimasf042e472020-05-17 22:25:44 +0300496 /* Check payload size */
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200497 name_size = u16_strsize(variable_name);
Ilias Apalodimasf042e472020-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 Apalodimasf96744b2020-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 Apalodimasf042e472020-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 Apalodimasf96744b2020-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 Apalodimasf042e472020-05-17 22:25:44 +0300539 /* Fill in contents */
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200540 guidcpy(&var_acc->guid, vendor);
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300541 var_acc->data_size = data_size;
542 var_acc->name_size = name_size;
Heinrich Schuchardtf2d2b3a2020-06-22 18:10:27 +0200543 var_acc->attr = attributes;
544 memcpy(var_acc->name, variable_name, name_size);
Ilias Apalodimasf042e472020-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 Apalodimasf96744b2020-07-09 23:00:40 +0300549 if (ret != EFI_SUCCESS)
550 alt_ret = ret;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300551
Ilias Apalodimasf96744b2020-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 }
Heinrich Schuchardt1a7b0f62020-07-14 08:14:08 +0200560
561 if (alt_ret != EFI_SUCCESS)
562 goto out;
563
564 if (!u16_strcmp(variable_name, L"PK"))
565 alt_ret = efi_init_secure_state();
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300566out:
567 free(comm_buf);
Ilias Apalodimasf96744b2020-07-09 23:00:40 +0300568 return alt_ret == EFI_SUCCESS ? ret : alt_ret;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300569}
570
Heinrich Schuchardt01df8cf2020-06-26 17:57:48 +0200571efi_status_t efi_query_variable_info_int(u32 attributes,
572 u64 *max_variable_storage_size,
573 u64 *remain_variable_storage_size,
574 u64 *max_variable_size)
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300575{
576 struct smm_variable_query_info *mm_query_info;
577 efi_uintn_t payload_size;
578 efi_status_t ret;
579 u8 *comm_buf;
580
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300581 payload_size = sizeof(*mm_query_info);
582 comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
583 SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
584 &ret);
585 if (!comm_buf)
586 goto out;
587
588 mm_query_info->attr = attributes;
589 ret = mm_communicate(comm_buf, payload_size);
590 if (ret != EFI_SUCCESS)
591 goto out;
592 *max_variable_storage_size = mm_query_info->max_variable_storage;
593 *remain_variable_storage_size =
594 mm_query_info->remaining_variable_storage;
595 *max_variable_size = mm_query_info->max_variable_size;
596
597out:
598 free(comm_buf);
Heinrich Schuchardt01df8cf2020-06-26 17:57:48 +0200599 return ret;
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300600}
601
602/**
603 * efi_get_variable_runtime() - runtime implementation of GetVariable()
604 *
605 * @variable_name: name of the variable
606 * @guid: vendor GUID
607 * @attributes: attributes of the variable
608 * @data_size: size of the buffer to which the variable value is copied
609 * @data: buffer to which the variable value is copied
610 * Return: status code
611 */
612static efi_status_t __efi_runtime EFIAPI
613efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
614 u32 *attributes, efi_uintn_t *data_size, void *data)
615{
616 return EFI_UNSUPPORTED;
617}
618
619/**
620 * efi_get_next_variable_name_runtime() - runtime implementation of
621 * GetNextVariable()
622 *
623 * @variable_name_size: size of variable_name buffer in byte
624 * @variable_name: name of uefi variable's name in u16
625 * @guid: vendor's guid
626 * Return: status code
627 */
628static efi_status_t __efi_runtime EFIAPI
629efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
630 u16 *variable_name, efi_guid_t *guid)
631{
632 return EFI_UNSUPPORTED;
633}
634
635/**
636 * efi_query_variable_info() - get information about EFI variables
637 *
638 * This function implements the QueryVariableInfo() runtime service.
639 *
640 * See the Unified Extensible Firmware Interface (UEFI) specification for
641 * details.
642 *
643 * @attributes: bitmask to select variables to be
644 * queried
645 * @maximum_variable_storage_size: maximum size of storage area for the
646 * selected variable types
647 * @remaining_variable_storage_size: remaining size of storage are for the
648 * selected variable types
649 * @maximum_variable_size: maximum size of a variable of the
650 * selected type
651 * Return: status code
652 */
653efi_status_t EFIAPI __efi_runtime
654efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
655 u64 *remain_variable_storage_size,
656 u64 *max_variable_size)
657{
658 return EFI_UNSUPPORTED;
659}
660
661/**
662 * efi_set_variable_runtime() - runtime implementation of SetVariable()
663 *
664 * @variable_name: name of the variable
665 * @guid: vendor GUID
666 * @attributes: attributes of the variable
667 * @data_size: size of the buffer with the variable value
668 * @data: buffer with the variable value
669 * Return: status code
670 */
671static efi_status_t __efi_runtime EFIAPI
672efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
673 u32 attributes, efi_uintn_t data_size,
674 const void *data)
675{
676 return EFI_UNSUPPORTED;
677}
678
679/**
680 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
681 */
682void efi_variables_boot_exit_notify(void)
683{
684 u8 *comm_buf;
685 efi_status_t ret;
686
687 comm_buf = setup_mm_hdr(NULL, 0,
688 SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &ret);
689 if (comm_buf)
690 ret = mm_communicate(comm_buf, 0);
691 else
692 ret = EFI_NOT_FOUND;
693
694 if (ret != EFI_SUCCESS)
695 log_err("Unable to notify StMM for ExitBootServices\n");
696 free(comm_buf);
697
698 /* Update runtime service table */
699 efi_runtime_services.query_variable_info =
700 efi_query_variable_info_runtime;
701 efi_runtime_services.get_variable = efi_get_variable_runtime;
702 efi_runtime_services.get_next_variable_name =
703 efi_get_next_variable_name_runtime;
704 efi_runtime_services.set_variable = efi_set_variable_runtime;
705 efi_update_table_header_crc32(&efi_runtime_services.hdr);
706}
707
708/**
709 * efi_init_variables() - initialize variable services
710 *
711 * Return: status code
712 */
713efi_status_t efi_init_variables(void)
714{
715 efi_status_t ret;
716
717 ret = get_max_payload(&max_payload_size);
718 if (ret != EFI_SUCCESS)
719 return ret;
720
721 max_buffer_size = MM_COMMUNICATE_HEADER_SIZE +
722 MM_VARIABLE_COMMUNICATE_SIZE +
723 max_payload_size;
724
Heinrich Schuchardt1a7b0f62020-07-14 08:14:08 +0200725 ret = efi_init_secure_state();
726 if (ret != EFI_SUCCESS)
727 return ret;
728
Ilias Apalodimasf042e472020-05-17 22:25:44 +0300729 return EFI_SUCCESS;
730}