1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * 4 * uefi vars device - EfiSmmVariableProtocol implementation 5 */ 6 #include "qemu/osdep.h" 7 #include "qemu/error-report.h" 8 #include "system/dma.h" 9 #include "migration/vmstate.h" 10 11 #include "hw/uefi/var-service.h" 12 #include "hw/uefi/var-service-api.h" 13 #include "hw/uefi/var-service-edk2.h" 14 15 #include "trace/trace-hw_uefi.h" 16 17 #define EFI_VARIABLE_ATTRIBUTE_SUPPORTED \ 18 (EFI_VARIABLE_NON_VOLATILE | \ 19 EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 20 EFI_VARIABLE_RUNTIME_ACCESS | \ 21 EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ 22 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ 23 EFI_VARIABLE_APPEND_WRITE) 24 25 26 const VMStateDescription vmstate_uefi_time = { 27 .name = "uefi-time", 28 .fields = (VMStateField[]) { 29 VMSTATE_UINT16(year, efi_time), 30 VMSTATE_UINT8(month, efi_time), 31 VMSTATE_UINT8(day, efi_time), 32 VMSTATE_UINT8(hour, efi_time), 33 VMSTATE_UINT8(minute, efi_time), 34 VMSTATE_UINT8(second, efi_time), 35 VMSTATE_UINT32(nanosecond, efi_time), 36 VMSTATE_END_OF_LIST() 37 }, 38 }; 39 40 const VMStateDescription vmstate_uefi_variable = { 41 .name = "uefi-variable", 42 .fields = (VMStateField[]) { 43 VMSTATE_UINT8_ARRAY_V(guid.data, uefi_variable, sizeof(QemuUUID), 0), 44 VMSTATE_UINT32(name_size, uefi_variable), 45 VMSTATE_UINT32(data_size, uefi_variable), 46 VMSTATE_UINT32(attributes, uefi_variable), 47 VMSTATE_VBUFFER_ALLOC_UINT32(name, uefi_variable, 0, NULL, name_size), 48 VMSTATE_VBUFFER_ALLOC_UINT32(data, uefi_variable, 0, NULL, data_size), 49 VMSTATE_STRUCT(time, uefi_variable, 0, vmstate_uefi_time, efi_time), 50 VMSTATE_END_OF_LIST() 51 }, 52 }; 53 54 uefi_variable *uefi_vars_find_variable(uefi_vars_state *uv, QemuUUID guid, 55 const uint16_t *name, uint64_t name_size) 56 { 57 uefi_variable *var; 58 59 QTAILQ_FOREACH(var, &uv->variables, next) { 60 if (!uefi_str_equal(var->name, var->name_size, 61 name, name_size)) { 62 continue; 63 } 64 if (!qemu_uuid_is_equal(&var->guid, &guid)) { 65 continue; 66 } 67 if (!var->data_size) { 68 /* in process of being created/updated */ 69 continue; 70 } 71 return var; 72 } 73 return NULL; 74 } 75 76 static uefi_variable *add_variable(uefi_vars_state *uv, QemuUUID guid, 77 const uint16_t *name, uint64_t name_size, 78 uint32_t attributes) 79 { 80 uefi_variable *var; 81 82 var = g_new0(uefi_variable, 1); 83 var->guid = guid; 84 var->name = g_malloc(name_size); 85 memcpy(var->name, name, name_size); 86 var->name_size = name_size; 87 var->attributes = attributes; 88 89 var->attributes &= ~EFI_VARIABLE_APPEND_WRITE; 90 91 QTAILQ_INSERT_TAIL(&uv->variables, var, next); 92 return var; 93 } 94 95 static void del_variable(uefi_vars_state *uv, uefi_variable *var) 96 { 97 if (!var) { 98 return; 99 } 100 101 QTAILQ_REMOVE(&uv->variables, var, next); 102 g_free(var->data); 103 g_free(var->name); 104 g_free(var->digest); 105 g_free(var); 106 } 107 108 static size_t variable_size(uefi_variable *var) 109 { 110 size_t size; 111 112 size = sizeof(*var); 113 size += var->name_size; 114 size += var->data_size; 115 size += var->digest_size; 116 return size; 117 } 118 119 void uefi_vars_set_variable(uefi_vars_state *uv, QemuUUID guid, 120 const uint16_t *name, uint64_t name_size, 121 uint32_t attributes, 122 void *data, uint64_t data_size) 123 { 124 uefi_variable *old_var, *new_var; 125 126 uefi_trace_variable(__func__, guid, name, name_size); 127 128 old_var = uefi_vars_find_variable(uv, guid, name, name_size); 129 if (old_var) { 130 uv->used_storage -= variable_size(old_var); 131 del_variable(uv, old_var); 132 } 133 134 new_var = add_variable(uv, guid, name, name_size, attributes); 135 new_var->data = g_malloc(data_size); 136 new_var->data_size = data_size; 137 memcpy(new_var->data, data, data_size); 138 uv->used_storage += variable_size(new_var); 139 } 140 141 void uefi_vars_clear_volatile(uefi_vars_state *uv) 142 { 143 uefi_variable *var, *n; 144 145 QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) { 146 if (var->attributes & EFI_VARIABLE_NON_VOLATILE) { 147 continue; 148 } 149 uv->used_storage -= variable_size(var); 150 del_variable(uv, var); 151 } 152 } 153 154 void uefi_vars_clear_all(uefi_vars_state *uv) 155 { 156 uefi_variable *var, *n; 157 158 QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) { 159 del_variable(uv, var); 160 } 161 uv->used_storage = 0; 162 } 163 164 void uefi_vars_update_storage(uefi_vars_state *uv) 165 { 166 uefi_variable *var; 167 168 uv->used_storage = 0; 169 QTAILQ_FOREACH(var, &uv->variables, next) { 170 uv->used_storage += variable_size(var); 171 } 172 } 173 174 static gboolean check_access(uefi_vars_state *uv, uefi_variable *var) 175 { 176 if (!uv->exit_boot_service) { 177 if (!(var->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) { 178 return false; 179 } 180 } else { 181 if (!(var->attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { 182 return false; 183 } 184 } 185 return true; 186 } 187 188 static efi_status check_update(uefi_vars_state *uv, uefi_variable *old_var, 189 uefi_variable *new_var) 190 { 191 efi_status status; 192 193 if (old_var) { 194 if (!check_access(uv, old_var)) { 195 return EFI_ACCESS_DENIED; 196 } 197 } 198 199 if (new_var) { 200 if (new_var->attributes & ~EFI_VARIABLE_ATTRIBUTE_SUPPORTED) { 201 return EFI_UNSUPPORTED; 202 } 203 if (!check_access(uv, new_var)) { 204 return EFI_ACCESS_DENIED; 205 } 206 } 207 208 if (old_var && new_var) { 209 if (old_var->attributes != new_var->attributes) { 210 return EFI_INVALID_PARAMETER; 211 } 212 } 213 214 if (new_var) { 215 /* create + update */ 216 status = uefi_vars_policy_check(uv, new_var, old_var == NULL); 217 } else { 218 /* delete */ 219 g_assert(old_var); 220 status = uefi_vars_policy_check(uv, old_var, false); 221 } 222 if (status != EFI_SUCCESS) { 223 return status; 224 } 225 226 status = uefi_vars_check_secure_boot(uv, new_var ?: old_var); 227 if (status != EFI_SUCCESS) { 228 return status; 229 } 230 231 return EFI_SUCCESS; 232 } 233 234 static void append_write(uefi_variable *old_var, 235 uefi_variable *new_var) 236 { 237 uefi_vars_siglist siglist; 238 uint64_t size; 239 void *data; 240 241 uefi_vars_siglist_init(&siglist); 242 uefi_vars_siglist_parse(&siglist, old_var->data, old_var->data_size); 243 uefi_vars_siglist_parse(&siglist, new_var->data, new_var->data_size); 244 245 size = uefi_vars_siglist_blob_size(&siglist); 246 data = g_malloc(size); 247 uefi_vars_siglist_blob_generate(&siglist, data, size); 248 249 g_free(new_var->data); 250 new_var->data = data; 251 new_var->data_size = size; 252 253 uefi_vars_siglist_free(&siglist); 254 } 255 256 static size_t uefi_vars_mm_error(mm_header *mhdr, mm_variable *mvar, 257 uint64_t status) 258 { 259 mvar->status = status; 260 return sizeof(*mvar); 261 } 262 263 static size_t uefi_vars_mm_get_variable(uefi_vars_state *uv, mm_header *mhdr, 264 mm_variable *mvar, void *func) 265 { 266 mm_variable_access *va = func; 267 uint16_t *name; 268 void *data; 269 uefi_variable *var; 270 uint64_t length; 271 272 length = sizeof(*mvar) + sizeof(*va); 273 if (mhdr->length < length) { 274 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 275 } 276 277 if (va->name_size > uv->max_storage || 278 va->data_size > uv->max_storage) { 279 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES); 280 } 281 282 name = func + sizeof(*va); 283 if (uadd64_overflow(length, va->name_size, &length)) { 284 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 285 } 286 if (mhdr->length < length) { 287 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 288 } 289 290 if (!uefi_str_is_valid(name, va->name_size, true)) { 291 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 292 } 293 294 uefi_trace_variable(__func__, va->guid, name, va->name_size); 295 296 var = uefi_vars_find_variable(uv, va->guid, name, va->name_size); 297 if (!var) { 298 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); 299 } 300 301 /* check permissions etc. */ 302 if (!check_access(uv, var)) { 303 return uefi_vars_mm_error(mhdr, mvar, EFI_ACCESS_DENIED); 304 } 305 306 data = func + sizeof(*va) + va->name_size; 307 if (uadd64_overflow(length, va->data_size, &length)) { 308 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 309 } 310 if (uv->buf_size < length) { 311 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 312 } 313 314 va->attributes = var->attributes; 315 if (va->data_size < var->data_size) { 316 va->data_size = var->data_size; 317 length -= va->data_size; 318 mvar->status = EFI_BUFFER_TOO_SMALL; 319 } else { 320 va->data_size = var->data_size; 321 memcpy(data, var->data, var->data_size); 322 mvar->status = EFI_SUCCESS; 323 } 324 return length; 325 } 326 327 static size_t 328 uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr, 329 mm_variable *mvar, void *func) 330 { 331 mm_next_variable *nv = func; 332 uefi_variable *var; 333 uint16_t *name; 334 uint64_t length; 335 336 length = sizeof(*mvar) + sizeof(*nv); 337 if (mhdr->length < length) { 338 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 339 } 340 341 if (nv->name_size > uv->max_storage) { 342 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES); 343 } 344 345 name = func + sizeof(*nv); 346 if (uadd64_overflow(length, nv->name_size, &length)) { 347 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 348 } 349 if (mhdr->length < length) { 350 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 351 } 352 353 if (!uefi_str_is_valid(name, nv->name_size, true)) { 354 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 355 } 356 357 if (uefi_strlen(name, nv->name_size) == 0) { 358 /* empty string -> first */ 359 var = QTAILQ_FIRST(&uv->variables); 360 if (!var) { 361 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); 362 } 363 } else { 364 var = uefi_vars_find_variable(uv, nv->guid, name, nv->name_size); 365 if (!var) { 366 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 367 } 368 do { 369 var = QTAILQ_NEXT(var, next); 370 } while (var && !check_access(uv, var)); 371 if (!var) { 372 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); 373 } 374 } 375 376 length = sizeof(*mvar) + sizeof(*nv) + var->name_size; 377 if (uv->buf_size < length) { 378 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 379 } 380 381 nv->guid = var->guid; 382 nv->name_size = var->name_size; 383 memcpy(name, var->name, var->name_size); 384 mvar->status = EFI_SUCCESS; 385 return length; 386 } 387 388 static bool uefi_vars_mm_digest_compare(uefi_variable *old_var, 389 uefi_variable *new_var) 390 { 391 if (!old_var->digest || 392 !new_var->digest || 393 !old_var->digest_size || 394 !new_var->digest_size) { 395 /* should not happen */ 396 trace_uefi_vars_security_violation("inconsistent authvar digest state"); 397 return false; 398 } 399 if (old_var->digest_size != new_var->digest_size) { 400 trace_uefi_vars_security_violation("authvar digest size mismatch"); 401 return false; 402 } 403 if (memcmp(old_var->digest, new_var->digest, 404 old_var->digest_size) != 0) { 405 trace_uefi_vars_security_violation("authvar digest data mismatch"); 406 return false; 407 } 408 return true; 409 } 410 411 static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr, 412 mm_variable *mvar, void *func) 413 { 414 mm_variable_access *va = func; 415 uint32_t attributes = 0; 416 uint16_t *name; 417 void *data; 418 uefi_variable *old_var, *new_var; 419 uint64_t length; 420 size_t new_storage; 421 efi_status status; 422 423 length = sizeof(*mvar) + sizeof(*va); 424 if (mhdr->length < length) { 425 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 426 } 427 428 if (va->name_size > uv->max_storage || 429 va->data_size > uv->max_storage) { 430 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES); 431 } 432 433 name = func + sizeof(*va); 434 if (uadd64_overflow(length, va->name_size, &length)) { 435 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 436 } 437 if (mhdr->length < length) { 438 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 439 } 440 441 data = func + sizeof(*va) + va->name_size; 442 if (uadd64_overflow(length, va->data_size, &length)) { 443 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 444 } 445 if (mhdr->length < length) { 446 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 447 } 448 449 g_assert(va->name_size < G_MAXUINT32); 450 g_assert(va->data_size < G_MAXUINT32); 451 452 if (!uefi_str_is_valid(name, va->name_size, true)) { 453 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 454 } 455 456 uefi_trace_variable(__func__, va->guid, name, va->name_size); 457 458 old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size); 459 if (va->data_size) { 460 new_var = add_variable(uv, va->guid, name, va->name_size, 461 va->attributes); 462 if (va->attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { 463 /* not implemented (deprecated in uefi spec) */ 464 warn_report("%s: AUTHENTICATED_WRITE_ACCESS", __func__); 465 mvar->status = EFI_UNSUPPORTED; 466 goto rollback; 467 } else if (va->attributes & 468 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { 469 status = uefi_vars_check_auth_2(uv, new_var, va, data); 470 if (status != EFI_SUCCESS) { 471 mvar->status = status; 472 goto rollback; 473 } 474 if (old_var && new_var) { 475 if (uefi_time_compare(&old_var->time, &new_var->time) > 0) { 476 trace_uefi_vars_security_violation("time check failed"); 477 mvar->status = EFI_SECURITY_VIOLATION; 478 goto rollback; 479 } 480 if (old_var->digest_size || new_var->digest_size) { 481 if (!uefi_vars_mm_digest_compare(old_var, new_var)) { 482 mvar->status = EFI_SECURITY_VIOLATION; 483 goto rollback; 484 } 485 } 486 } 487 } else { 488 new_var->data = g_malloc(va->data_size); 489 memcpy(new_var->data, data, va->data_size); 490 new_var->data_size = va->data_size; 491 } 492 if (!new_var->data) { 493 /* we land here when deleting authenticated variables */ 494 del_variable(uv, new_var); 495 new_var = NULL; 496 } 497 } else { 498 new_var = NULL; 499 } 500 501 if (!old_var && !new_var) { 502 /* delete non-existing variable -> nothing to do */ 503 mvar->status = EFI_SUCCESS; 504 return sizeof(*mvar); 505 } 506 507 /* check permissions etc. */ 508 status = check_update(uv, old_var, new_var); 509 if (status != EFI_SUCCESS) { 510 mvar->status = status; 511 goto rollback; 512 } 513 514 if (va->attributes & EFI_VARIABLE_APPEND_WRITE && old_var && new_var) { 515 /* merge signature databases */ 516 if (!uefi_vars_is_sb_any(new_var)) { 517 mvar->status = EFI_UNSUPPORTED; 518 goto rollback; 519 } 520 append_write(old_var, new_var); 521 } 522 523 /* check storage space */ 524 new_storage = uv->used_storage; 525 if (old_var) { 526 new_storage -= variable_size(old_var); 527 } 528 if (new_var) { 529 new_storage += variable_size(new_var); 530 } 531 if (new_storage > uv->max_storage) { 532 mvar->status = EFI_OUT_OF_RESOURCES; 533 goto rollback; 534 } 535 536 attributes = new_var 537 ? new_var->attributes 538 : old_var->attributes; 539 540 /* all good, commit */ 541 del_variable(uv, old_var); 542 uv->used_storage = new_storage; 543 544 if (attributes & EFI_VARIABLE_NON_VOLATILE) { 545 uefi_vars_json_save(uv); 546 } 547 548 if (new_var && uefi_vars_is_sb_pk(new_var)) { 549 uefi_vars_auth_init(uv); 550 } 551 552 mvar->status = EFI_SUCCESS; 553 return sizeof(*mvar); 554 555 rollback: 556 del_variable(uv, new_var); 557 return sizeof(*mvar); 558 } 559 560 static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr, 561 mm_variable *mvar, void *func) 562 { 563 mm_variable_info *vi = func; 564 uint64_t length; 565 566 length = sizeof(*mvar) + sizeof(*vi); 567 if (uv->buf_size < length) { 568 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 569 } 570 571 vi->max_storage_size = uv->max_storage; 572 vi->free_storage_size = uv->max_storage - uv->used_storage; 573 vi->max_variable_size = uv->max_storage >> 2; 574 vi->attributes = 0; 575 576 mvar->status = EFI_SUCCESS; 577 return length; 578 } 579 580 static size_t 581 uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr, 582 mm_variable *mvar, void *func) 583 { 584 mm_get_payload_size *ps = func; 585 uint64_t length; 586 587 length = sizeof(*mvar) + sizeof(*ps); 588 if (uv->buf_size < length) { 589 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 590 } 591 592 ps->payload_size = uv->buf_size; 593 mvar->status = EFI_SUCCESS; 594 return length; 595 } 596 597 static size_t 598 uefi_vars_mm_lock_variable(uefi_vars_state *uv, mm_header *mhdr, 599 mm_variable *mvar, void *func) 600 { 601 mm_lock_variable *lv = func; 602 variable_policy_entry *pe; 603 uint16_t *name, *dest; 604 uint64_t length; 605 606 length = sizeof(*mvar) + sizeof(*lv); 607 if (mhdr->length < length) { 608 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 609 } 610 611 name = func + sizeof(*lv); 612 if (uadd64_overflow(length, lv->name_size, &length)) { 613 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 614 } 615 if (mhdr->length < length) { 616 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 617 } 618 619 uefi_trace_variable(__func__, lv->guid, name, lv->name_size); 620 621 pe = g_malloc0(sizeof(*pe) + lv->name_size); 622 pe->version = VARIABLE_POLICY_ENTRY_REVISION; 623 pe->size = sizeof(*pe) + lv->name_size; 624 pe->offset_to_name = sizeof(*pe); 625 pe->namespace = lv->guid; 626 pe->min_size = 0; 627 pe->max_size = UINT32_MAX; 628 pe->attributes_must_have = 0; 629 pe->attributes_cant_have = 0; 630 pe->lock_policy_type = VARIABLE_POLICY_TYPE_LOCK_NOW; 631 632 dest = (void *)pe + pe->offset_to_name; 633 memcpy(dest, name, lv->name_size); 634 635 uefi_vars_add_policy(uv, pe); 636 g_free(pe); 637 638 mvar->status = EFI_SUCCESS; 639 return length; 640 } 641 642 uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv) 643 { 644 static const char *fnames[] = { 645 "zero", 646 "get-variable", 647 "get-next-variable-name", 648 "set-variable", 649 "query-variable-info", 650 "ready-to-boot", 651 "exit-boot-service", 652 "get-statistics", 653 "lock-variable", 654 "var-check-prop-set", 655 "var-check-prop-get", 656 "get-payload-size", 657 "init-runtime-cache-contect", 658 "sync-runtime-cache", 659 "get-runtime-cache-info", 660 }; 661 const char *fname; 662 uint64_t length; 663 664 mm_header *mhdr = (mm_header *) uv->buffer; 665 mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr)); 666 void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar)); 667 668 if (mhdr->length < sizeof(*mvar)) { 669 return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE; 670 } 671 672 fname = mvar->function < ARRAY_SIZE(fnames) 673 ? fnames[mvar->function] 674 : "unknown"; 675 trace_uefi_vars_proto_cmd(fname); 676 677 switch (mvar->function) { 678 case SMM_VARIABLE_FUNCTION_GET_VARIABLE: 679 length = uefi_vars_mm_get_variable(uv, mhdr, mvar, func); 680 break; 681 682 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: 683 length = uefi_vars_mm_get_next_variable(uv, mhdr, mvar, func); 684 break; 685 686 case SMM_VARIABLE_FUNCTION_SET_VARIABLE: 687 length = uefi_vars_mm_set_variable(uv, mhdr, mvar, func); 688 break; 689 690 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: 691 length = uefi_vars_mm_variable_info(uv, mhdr, mvar, func); 692 break; 693 694 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE: 695 length = uefi_vars_mm_lock_variable(uv, mhdr, mvar, func); 696 break; 697 698 case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE: 699 length = uefi_vars_mm_get_payload_size(uv, mhdr, mvar, func); 700 break; 701 702 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: 703 trace_uefi_event("ready-to-boot"); 704 uv->ready_to_boot = true; 705 length = 0; 706 break; 707 708 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: 709 trace_uefi_event("exit-boot-service"); 710 uv->exit_boot_service = true; 711 length = 0; 712 break; 713 714 default: 715 length = uefi_vars_mm_error(mhdr, mvar, EFI_UNSUPPORTED); 716 break; 717 } 718 719 if (mhdr->length < length) { 720 mvar->status = EFI_BUFFER_TOO_SMALL; 721 } 722 723 uefi_trace_status(__func__, mvar->status); 724 return UEFI_VARS_STS_SUCCESS; 725 } 726