uboot/lib/efi_loader/efi_variable_tee.c
<<
>>
Prefs
   1// 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>
  13#include <efi_variable.h>
  14#include <tee.h>
  15#include <malloc.h>
  16#include <mm_communication.h>
  17
  18extern struct efi_var_file __efi_runtime_data *efi_var_buf;
  19static efi_uintn_t max_buffer_size;     /* comm + var + func + data */
  20static efi_uintn_t max_payload_size;    /* func + data */
  21
  22struct mm_connection {
  23        struct udevice *tee;
  24        u32 session;
  25};
  26
  27/**
  28 * get_connection() - Retrieve OP-TEE session for a specific UUID.
  29 *
  30 * @conn:   session buffer to fill
  31 * Return:  status code
  32 */
  33static int get_connection(struct mm_connection *conn)
  34{
  35        static const struct tee_optee_ta_uuid uuid = PTA_STMM_UUID;
  36        struct udevice *tee = NULL;
  37        struct tee_open_session_arg arg;
  38        int rc = -ENODEV;
  39
  40        tee = tee_find_device(tee, NULL, NULL, NULL);
  41        if (!tee)
  42                goto out;
  43
  44        memset(&arg, 0, sizeof(arg));
  45        tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
  46        rc = tee_open_session(tee, &arg, 0, NULL);
  47        if (rc)
  48                goto out;
  49
  50        /* Check the internal OP-TEE result */
  51        if (arg.ret != TEE_SUCCESS) {
  52                rc = -EIO;
  53                goto out;
  54        }
  55
  56        conn->tee = tee;
  57        conn->session = arg.session;
  58
  59        return 0;
  60out:
  61        return rc;
  62}
  63
  64/**
  65 * optee_mm_communicate() - Pass a buffer to StandaloneMM running in OP-TEE
  66 *
  67 * @comm_buf:           locally allocted communcation buffer
  68 * @dsize:              buffer size
  69 * Return:              status code
  70 */
  71static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
  72{
  73        ulong buf_size;
  74        efi_status_t ret;
  75        struct efi_mm_communicate_header *mm_hdr;
  76        struct mm_connection conn = { NULL, 0 };
  77        struct tee_invoke_arg arg;
  78        struct tee_param param[2];
  79        struct tee_shm *shm = NULL;
  80        int rc;
  81
  82        if (!comm_buf)
  83                return EFI_INVALID_PARAMETER;
  84
  85        mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
  86        buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
  87
  88        if (dsize != buf_size)
  89                return EFI_INVALID_PARAMETER;
  90
  91        rc = get_connection(&conn);
  92        if (rc) {
  93                log_err("Unable to open OP-TEE session (err=%d)\n", rc);
  94                return EFI_UNSUPPORTED;
  95        }
  96
  97        if (tee_shm_register(conn.tee, comm_buf, buf_size, 0, &shm)) {
  98                log_err("Unable to register shared memory\n");
  99                tee_close_session(conn.tee, conn.session);
 100                return EFI_UNSUPPORTED;
 101        }
 102
 103        memset(&arg, 0, sizeof(arg));
 104        arg.func = PTA_STMM_CMDID_COMMUNICATE;
 105        arg.session = conn.session;
 106
 107        memset(param, 0, sizeof(param));
 108        param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
 109        param[0].u.memref.size = buf_size;
 110        param[0].u.memref.shm = shm;
 111        param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
 112
 113        rc = tee_invoke_func(conn.tee, &arg, 2, param);
 114        tee_shm_free(shm);
 115        tee_close_session(conn.tee, conn.session);
 116        if (rc)
 117                return EFI_DEVICE_ERROR;
 118        if (arg.ret == TEE_ERROR_EXCESS_DATA)
 119                log_err("Variable payload too large\n");
 120        if (arg.ret != TEE_SUCCESS)
 121                return EFI_DEVICE_ERROR;
 122
 123        switch (param[1].u.value.a) {
 124        case ARM_SVC_SPM_RET_SUCCESS:
 125                ret = EFI_SUCCESS;
 126                break;
 127
 128        case ARM_SVC_SPM_RET_INVALID_PARAMS:
 129                ret = EFI_INVALID_PARAMETER;
 130                break;
 131
 132        case ARM_SVC_SPM_RET_DENIED:
 133                ret = EFI_ACCESS_DENIED;
 134                break;
 135
 136        case ARM_SVC_SPM_RET_NO_MEMORY:
 137                ret = EFI_OUT_OF_RESOURCES;
 138                break;
 139
 140        default:
 141                ret = EFI_ACCESS_DENIED;
 142        }
 143
 144        return ret;
 145}
 146
 147/**
 148 * mm_communicate() - Adjust the cmonnucation buffer to StandAlonneMM and send
 149 * it to OP-TEE
 150 *
 151 * @comm_buf:           locally allocted communcation buffer
 152 * @dsize:              buffer size
 153 * Return:              status code
 154 */
 155static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
 156{
 157        efi_status_t ret;
 158        struct efi_mm_communicate_header *mm_hdr;
 159        struct smm_variable_communicate_header *var_hdr;
 160
 161        dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
 162        mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
 163        var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
 164
 165        ret = optee_mm_communicate(comm_buf, dsize);
 166        if (ret != EFI_SUCCESS) {
 167                log_err("%s failed!\n", __func__);
 168                return ret;
 169        }
 170
 171        return var_hdr->ret_status;
 172}
 173
 174/**
 175 * setup_mm_hdr() -     Allocate a buffer for StandAloneMM and initialize the
 176 *                      header data.
 177 *
 178 * @dptr:               pointer address of the corresponding StandAloneMM
 179 *                      function
 180 * @payload_size:       buffer size
 181 * @func:               standAloneMM function number
 182 * @ret:                EFI return code
 183 * Return:              buffer or NULL
 184 */
 185static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
 186                        efi_uintn_t func, efi_status_t *ret)
 187{
 188        const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
 189        struct efi_mm_communicate_header *mm_hdr;
 190        struct smm_variable_communicate_header *var_hdr;
 191        u8 *comm_buf;
 192
 193        /* In the init function we initialize max_buffer_size with
 194         * get_max_payload(). So skip the test if max_buffer_size is initialized
 195         * StandAloneMM will perform similar checks and drop the buffer if it's
 196         * too long
 197         */
 198        if (max_buffer_size && max_buffer_size <
 199                        (MM_COMMUNICATE_HEADER_SIZE +
 200                         MM_VARIABLE_COMMUNICATE_SIZE +
 201                         payload_size)) {
 202                *ret = EFI_INVALID_PARAMETER;
 203                return NULL;
 204        }
 205
 206        comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
 207                          MM_VARIABLE_COMMUNICATE_SIZE +
 208                          payload_size);
 209        if (!comm_buf) {
 210                *ret = EFI_OUT_OF_RESOURCES;
 211                return NULL;
 212        }
 213
 214        mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
 215        guidcpy(&mm_hdr->header_guid, &mm_var_guid);
 216        mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
 217
 218        var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
 219        var_hdr->function = func;
 220        if (dptr)
 221                *dptr = var_hdr->data;
 222        *ret = EFI_SUCCESS;
 223
 224        return comm_buf;
 225}
 226
 227/**
 228 * get_max_payload() - Get variable payload size from StandAloneMM.
 229 *
 230 * @size:    size of the variable in storage
 231 * Return:   status code
 232 */
 233efi_status_t EFIAPI get_max_payload(efi_uintn_t *size)
 234{
 235        struct smm_variable_payload_size *var_payload = NULL;
 236        efi_uintn_t payload_size;
 237        u8 *comm_buf = NULL;
 238        efi_status_t ret;
 239
 240        if (!size) {
 241                ret = EFI_INVALID_PARAMETER;
 242                goto out;
 243        }
 244
 245        payload_size = sizeof(*var_payload);
 246        comm_buf = setup_mm_hdr((void **)&var_payload, payload_size,
 247                                SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &ret);
 248        if (!comm_buf)
 249                goto out;
 250
 251        ret = mm_communicate(comm_buf, payload_size);
 252        if (ret != EFI_SUCCESS)
 253                goto out;
 254
 255        /* Make sure the buffer is big enough for storing variables */
 256        if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) {
 257                ret = EFI_DEVICE_ERROR;
 258                goto out;
 259        }
 260        *size = var_payload->size;
 261        /*
 262         * There seems to be a bug in EDK2 miscalculating the boundaries and
 263         * size checks, so deduct 2 more bytes to fulfill this requirement. Fix
 264         * it up here to ensure backwards compatibility with older versions
 265         * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c.
 266         * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the
 267         * flexible array member).
 268         *
 269         * size is guaranteed to be > 2 due to checks on the beginning.
 270         */
 271        *size -= 2;
 272out:
 273        free(comm_buf);
 274        return ret;
 275}
 276
 277/*
 278 * StMM can store internal attributes and properties for variables, i.e enabling
 279 * R/O variables
 280 */
 281static efi_status_t set_property_int(const u16 *variable_name,
 282                                     efi_uintn_t name_size,
 283                                     const efi_guid_t *vendor,
 284                                     struct var_check_property *var_property)
 285{
 286        struct smm_variable_var_check_property *smm_property;
 287        efi_uintn_t payload_size;
 288        u8 *comm_buf = NULL;
 289        efi_status_t ret;
 290
 291        payload_size = sizeof(*smm_property) + name_size;
 292        if (payload_size > max_payload_size) {
 293                ret = EFI_INVALID_PARAMETER;
 294                goto out;
 295        }
 296        comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
 297                                SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
 298                                &ret);
 299        if (!comm_buf)
 300                goto out;
 301
 302        guidcpy(&smm_property->guid, vendor);
 303        smm_property->name_size = name_size;
 304        memcpy(&smm_property->property, var_property,
 305               sizeof(smm_property->property));
 306        memcpy(smm_property->name, variable_name, name_size);
 307
 308        ret = mm_communicate(comm_buf, payload_size);
 309
 310out:
 311        free(comm_buf);
 312        return ret;
 313}
 314
 315static efi_status_t get_property_int(const u16 *variable_name,
 316                                     efi_uintn_t name_size,
 317                                     const efi_guid_t *vendor,
 318                                     struct var_check_property *var_property)
 319{
 320        struct smm_variable_var_check_property *smm_property;
 321        efi_uintn_t payload_size;
 322        u8 *comm_buf = NULL;
 323        efi_status_t ret;
 324
 325        memset(var_property, 0, sizeof(*var_property));
 326        payload_size = sizeof(*smm_property) + name_size;
 327        if (payload_size > max_payload_size) {
 328                ret = EFI_INVALID_PARAMETER;
 329                goto out;
 330        }
 331        comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
 332                                SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
 333                                &ret);
 334        if (!comm_buf)
 335                goto out;
 336
 337        guidcpy(&smm_property->guid, vendor);
 338        smm_property->name_size = name_size;
 339        memcpy(smm_property->name, variable_name, name_size);
 340
 341        ret = mm_communicate(comm_buf, payload_size);
 342        /*
 343         * Currently only R/O property is supported in StMM.
 344         * Variables that are not set to R/O will not set the property in StMM
 345         * and the call will return EFI_NOT_FOUND. We are setting the
 346         * properties to 0x0 so checking against that is enough for the
 347         * EFI_NOT_FOUND case.
 348         */
 349        if (ret == EFI_NOT_FOUND)
 350                ret = EFI_SUCCESS;
 351        if (ret != EFI_SUCCESS)
 352                goto out;
 353        memcpy(var_property, &smm_property->property, sizeof(*var_property));
 354
 355out:
 356        free(comm_buf);
 357        return ret;
 358}
 359
 360efi_status_t efi_get_variable_int(const u16 *variable_name,
 361                                  const efi_guid_t *vendor,
 362                                  u32 *attributes, efi_uintn_t *data_size,
 363                                  void *data, u64 *timep)
 364{
 365        struct var_check_property var_property;
 366        struct smm_variable_access *var_acc;
 367        efi_uintn_t payload_size;
 368        efi_uintn_t name_size;
 369        efi_uintn_t tmp_dsize;
 370        u8 *comm_buf = NULL;
 371        efi_status_t ret, tmp;
 372
 373        if (!variable_name || !vendor || !data_size) {
 374                ret = EFI_INVALID_PARAMETER;
 375                goto out;
 376        }
 377
 378        /* Check payload size */
 379        name_size = u16_strsize(variable_name);
 380        if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
 381                ret = EFI_INVALID_PARAMETER;
 382                goto out;
 383        }
 384
 385        /* Trim output buffer size */
 386        tmp_dsize = *data_size;
 387        if (name_size + tmp_dsize >
 388                        max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
 389                tmp_dsize = max_payload_size -
 390                                MM_VARIABLE_ACCESS_HEADER_SIZE -
 391                                name_size;
 392        }
 393
 394        /* Get communication buffer and initialize header */
 395        payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
 396        comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
 397                                SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
 398        if (!comm_buf)
 399                goto out;
 400
 401        /* Fill in contents */
 402        guidcpy(&var_acc->guid, vendor);
 403        var_acc->data_size = tmp_dsize;
 404        var_acc->name_size = name_size;
 405        var_acc->attr = attributes ? *attributes : 0;
 406        memcpy(var_acc->name, variable_name, name_size);
 407
 408        /* Communicate */
 409        ret = mm_communicate(comm_buf, payload_size);
 410        if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)
 411                goto out;
 412
 413        /* Update with reported data size for trimmed case */
 414        *data_size = var_acc->data_size;
 415        /*
 416         * UEFI > 2.7 needs the attributes set even if the buffer is
 417         * smaller
 418         */
 419        if (attributes) {
 420                tmp = get_property_int(variable_name, name_size, vendor,
 421                                       &var_property);
 422                if (tmp != EFI_SUCCESS) {
 423                        ret = tmp;
 424                        goto out;
 425                }
 426                *attributes = var_acc->attr;
 427                if (var_property.property &
 428                    VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
 429                        *attributes |= EFI_VARIABLE_READ_ONLY;
 430        }
 431
 432        /* return if ret is EFI_BUFFER_TOO_SMALL */
 433        if (ret != EFI_SUCCESS)
 434                goto out;
 435
 436        if (data)
 437                memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
 438                       var_acc->data_size);
 439        else
 440                ret = EFI_INVALID_PARAMETER;
 441
 442out:
 443        free(comm_buf);
 444        return ret;
 445}
 446
 447efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
 448                                            u16 *variable_name,
 449                                            efi_guid_t *guid)
 450{
 451        struct smm_variable_getnext *var_getnext;
 452        efi_uintn_t payload_size;
 453        efi_uintn_t out_name_size;
 454        efi_uintn_t in_name_size;
 455        u8 *comm_buf = NULL;
 456        efi_status_t ret;
 457
 458        if (!variable_name_size || !variable_name || !guid) {
 459                ret = EFI_INVALID_PARAMETER;
 460                goto out;
 461        }
 462
 463        out_name_size = *variable_name_size;
 464        in_name_size = u16_strsize(variable_name);
 465
 466        if (out_name_size < in_name_size) {
 467                ret = EFI_INVALID_PARAMETER;
 468                goto out;
 469        }
 470
 471        if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
 472                ret = EFI_INVALID_PARAMETER;
 473                goto out;
 474        }
 475
 476        /* Trim output buffer size */
 477        if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
 478                out_name_size = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
 479
 480        payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
 481        comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
 482                                SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
 483                                &ret);
 484        if (!comm_buf)
 485                goto out;
 486
 487        /* Fill in contents */
 488        guidcpy(&var_getnext->guid, guid);
 489        var_getnext->name_size = out_name_size;
 490        memcpy(var_getnext->name, variable_name, in_name_size);
 491        memset((u8 *)var_getnext->name + in_name_size, 0x0,
 492               out_name_size - in_name_size);
 493
 494        /* Communicate */
 495        ret = mm_communicate(comm_buf, payload_size);
 496        if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
 497                /* Update with reported data size for trimmed case */
 498                *variable_name_size = var_getnext->name_size;
 499        }
 500        if (ret != EFI_SUCCESS)
 501                goto out;
 502
 503        guidcpy(guid, &var_getnext->guid);
 504        memcpy(variable_name, var_getnext->name, var_getnext->name_size);
 505
 506out:
 507        free(comm_buf);
 508        return ret;
 509}
 510
 511efi_status_t efi_set_variable_int(const u16 *variable_name,
 512                                  const efi_guid_t *vendor, u32 attributes,
 513                                  efi_uintn_t data_size, const void *data,
 514                                  bool ro_check)
 515{
 516        efi_status_t ret, alt_ret = EFI_SUCCESS;
 517        struct var_check_property var_property;
 518        struct smm_variable_access *var_acc;
 519        efi_uintn_t payload_size;
 520        efi_uintn_t name_size;
 521        u8 *comm_buf = NULL;
 522        bool ro;
 523
 524        if (!variable_name || variable_name[0] == 0 || !vendor) {
 525                ret = EFI_INVALID_PARAMETER;
 526                goto out;
 527        }
 528        if (data_size > 0 && !data) {
 529                ret = EFI_INVALID_PARAMETER;
 530                goto out;
 531        }
 532        /* Check payload size */
 533        name_size = u16_strsize(variable_name);
 534        payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
 535        if (payload_size > max_payload_size) {
 536                ret = EFI_INVALID_PARAMETER;
 537                goto out;
 538        }
 539
 540        /*
 541         * Allocate the buffer early, before switching to RW (if needed)
 542         * so we won't need to account for any failures in reading/setting
 543         * the properties, if the allocation fails
 544         */
 545        comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
 546                                SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
 547        if (!comm_buf)
 548                goto out;
 549
 550        ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
 551        attributes &= EFI_VARIABLE_MASK;
 552
 553        /*
 554         * The API has the ability to override RO flags. If no RO check was
 555         * requested switch the variable to RW for the duration of this call
 556         */
 557        ret = get_property_int(variable_name, name_size, vendor,
 558                               &var_property);
 559        if (ret != EFI_SUCCESS)
 560                goto out;
 561
 562        if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
 563                /* Bypass r/o check */
 564                if (!ro_check) {
 565                        var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
 566                        ret = set_property_int(variable_name, name_size, vendor, &var_property);
 567                        if (ret != EFI_SUCCESS)
 568                                goto out;
 569                } else {
 570                        ret = EFI_WRITE_PROTECTED;
 571                        goto out;
 572                }
 573        }
 574
 575        /* Fill in contents */
 576        guidcpy(&var_acc->guid, vendor);
 577        var_acc->data_size = data_size;
 578        var_acc->name_size = name_size;
 579        var_acc->attr = attributes;
 580        memcpy(var_acc->name, variable_name, name_size);
 581        memcpy((u8 *)var_acc->name + name_size, data, data_size);
 582
 583        /* Communicate */
 584        ret = mm_communicate(comm_buf, payload_size);
 585        if (ret != EFI_SUCCESS)
 586                alt_ret = ret;
 587
 588        if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
 589                var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
 590                var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
 591                var_property.attributes = attributes;
 592                var_property.minsize = 1;
 593                var_property.maxsize = var_acc->data_size;
 594                ret = set_property_int(variable_name, name_size, vendor, &var_property);
 595        }
 596
 597        if (alt_ret != EFI_SUCCESS)
 598                goto out;
 599
 600        if (!u16_strcmp(variable_name, u"PK"))
 601                alt_ret = efi_init_secure_state();
 602out:
 603        free(comm_buf);
 604        return alt_ret == EFI_SUCCESS ? ret : alt_ret;
 605}
 606
 607efi_status_t efi_query_variable_info_int(u32 attributes,
 608                                         u64 *max_variable_storage_size,
 609                                         u64 *remain_variable_storage_size,
 610                                         u64 *max_variable_size)
 611{
 612        struct smm_variable_query_info *mm_query_info;
 613        efi_uintn_t payload_size;
 614        efi_status_t ret;
 615        u8 *comm_buf;
 616
 617        payload_size = sizeof(*mm_query_info);
 618        comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
 619                                SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
 620                                &ret);
 621        if (!comm_buf)
 622                goto out;
 623
 624        mm_query_info->attr = attributes;
 625        ret = mm_communicate(comm_buf, payload_size);
 626        if (ret != EFI_SUCCESS)
 627                goto out;
 628        *max_variable_storage_size = mm_query_info->max_variable_storage;
 629        *remain_variable_storage_size =
 630                        mm_query_info->remaining_variable_storage;
 631        *max_variable_size = mm_query_info->max_variable_size;
 632
 633out:
 634        free(comm_buf);
 635        return ret;
 636}
 637
 638/**
 639 * efi_query_variable_info() - get information about EFI variables
 640 *
 641 * This function implements the QueryVariableInfo() runtime service.
 642 *
 643 * See the Unified Extensible Firmware Interface (UEFI) specification for
 644 * details.
 645 *
 646 * @attributes:                         bitmask to select variables to be
 647 *                                      queried
 648 * @maximum_variable_storage_size:      maximum size of storage area for the
 649 *                                      selected variable types
 650 * @remaining_variable_storage_size:    remaining size of storage are for the
 651 *                                      selected variable types
 652 * @maximum_variable_size:              maximum size of a variable of the
 653 *                                      selected type
 654 * Return:                              status code
 655 */
 656efi_status_t EFIAPI __efi_runtime
 657efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
 658                                u64 *remain_variable_storage_size,
 659                                u64 *max_variable_size)
 660{
 661        return EFI_UNSUPPORTED;
 662}
 663
 664/**
 665 * efi_set_variable_runtime() - runtime implementation of SetVariable()
 666 *
 667 * @variable_name:      name of the variable
 668 * @guid:               vendor GUID
 669 * @attributes:         attributes of the variable
 670 * @data_size:          size of the buffer with the variable value
 671 * @data:               buffer with the variable value
 672 * Return:              status code
 673 */
 674static efi_status_t __efi_runtime EFIAPI
 675efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
 676                         u32 attributes, efi_uintn_t data_size,
 677                         const void *data)
 678{
 679        return EFI_UNSUPPORTED;
 680}
 681
 682/**
 683 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
 684 */
 685void efi_variables_boot_exit_notify(void)
 686{
 687        efi_status_t ret;
 688        u8 *comm_buf;
 689        loff_t len;
 690        struct efi_var_file *var_buf;
 691
 692        comm_buf = setup_mm_hdr(NULL, 0,
 693                                SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &ret);
 694        if (comm_buf)
 695                ret = mm_communicate(comm_buf, 0);
 696        else
 697                ret = EFI_NOT_FOUND;
 698
 699        if (ret != EFI_SUCCESS)
 700                log_err("Unable to notify StMM for ExitBootServices\n");
 701        free(comm_buf);
 702
 703        /*
 704         * Populate the list for runtime variables.
 705         * asking EFI_VARIABLE_RUNTIME_ACCESS is redundant, since
 706         * efi_var_mem_notify_exit_boot_services will clean those, but that's fine
 707         */
 708        ret = efi_var_collect(&var_buf, &len, EFI_VARIABLE_RUNTIME_ACCESS);
 709        if (ret != EFI_SUCCESS)
 710                log_err("Can't populate EFI variables. No runtime variables will be available\n");
 711        else
 712                efi_var_buf_update(var_buf);
 713        free(var_buf);
 714
 715        /* Update runtime service table */
 716        efi_runtime_services.query_variable_info =
 717                        efi_query_variable_info_runtime;
 718        efi_runtime_services.get_variable = efi_get_variable_runtime;
 719        efi_runtime_services.get_next_variable_name =
 720                        efi_get_next_variable_name_runtime;
 721        efi_runtime_services.set_variable = efi_set_variable_runtime;
 722        efi_update_table_header_crc32(&efi_runtime_services.hdr);
 723}
 724
 725/**
 726 * efi_init_variables() - initialize variable services
 727 *
 728 * Return:      status code
 729 */
 730efi_status_t efi_init_variables(void)
 731{
 732        efi_status_t ret;
 733
 734        /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
 735        ret = efi_var_mem_init();
 736        if (ret != EFI_SUCCESS)
 737                return ret;
 738
 739        ret = get_max_payload(&max_payload_size);
 740        if (ret != EFI_SUCCESS)
 741                return ret;
 742
 743        max_buffer_size = MM_COMMUNICATE_HEADER_SIZE +
 744                          MM_VARIABLE_COMMUNICATE_SIZE +
 745                          max_payload_size;
 746
 747        ret = efi_init_secure_state();
 748        if (ret != EFI_SUCCESS)
 749                return ret;
 750
 751        return EFI_SUCCESS;
 752}
 753