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.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 while (var && !check_access(uv, var)) { 361 var = QTAILQ_NEXT(var, next); 362 } 363 if (!var) { 364 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); 365 } 366 } else { 367 var = uefi_vars_find_variable(uv, nv->guid, name, nv->name_size); 368 if (!var) { 369 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 370 } 371 do { 372 var = QTAILQ_NEXT(var, next); 373 } while (var && !check_access(uv, var)); 374 if (!var) { 375 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); 376 } 377 } 378 379 length = sizeof(*mvar) + sizeof(*nv) + var->name_size; 380 if (uv->buf_size < length) { 381 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 382 } 383 384 nv->guid = var->guid; 385 nv->name_size = var->name_size; 386 memcpy(name, var->name, var->name_size); 387 mvar->status = EFI_SUCCESS; 388 return length; 389 } 390 391 static bool uefi_vars_mm_digest_compare(uefi_variable *old_var, 392 uefi_variable *new_var) 393 { 394 if (!old_var->digest || 395 !new_var->digest || 396 !old_var->digest_size || 397 !new_var->digest_size) { 398 /* should not happen */ 399 trace_uefi_vars_security_violation("inconsistent authvar digest state"); 400 return false; 401 } 402 if (old_var->digest_size != new_var->digest_size) { 403 trace_uefi_vars_security_violation("authvar digest size mismatch"); 404 return false; 405 } 406 if (memcmp(old_var->digest, new_var->digest, 407 old_var->digest_size) != 0) { 408 trace_uefi_vars_security_violation("authvar digest data mismatch"); 409 return false; 410 } 411 return true; 412 } 413 414 static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr, 415 mm_variable *mvar, void *func) 416 { 417 mm_variable_access *va = func; 418 uint32_t attributes = 0; 419 uint16_t *name; 420 void *data; 421 uefi_variable *old_var, *new_var; 422 uint64_t length; 423 size_t new_storage; 424 efi_status status; 425 426 length = sizeof(*mvar) + sizeof(*va); 427 if (mhdr->length < length) { 428 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 429 } 430 431 if (va->name_size > uv->max_storage || 432 va->data_size > uv->max_storage) { 433 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES); 434 } 435 436 name = func + sizeof(*va); 437 if (uadd64_overflow(length, va->name_size, &length)) { 438 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 439 } 440 if (mhdr->length < length) { 441 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 442 } 443 444 data = func + sizeof(*va) + va->name_size; 445 if (uadd64_overflow(length, va->data_size, &length)) { 446 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 447 } 448 if (mhdr->length < length) { 449 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 450 } 451 452 g_assert(va->name_size < G_MAXUINT32); 453 g_assert(va->data_size < G_MAXUINT32); 454 455 if (!uefi_str_is_valid(name, va->name_size, true)) { 456 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER); 457 } 458 459 uefi_trace_variable(__func__, va->guid, name, va->name_size); 460 461 old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size); 462 if (va->data_size) { 463 new_var = add_variable(uv, va->guid, name, va->name_size, 464 va->attributes); 465 if (va->attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { 466 /* not implemented (deprecated in uefi spec) */ 467 warn_report("%s: AUTHENTICATED_WRITE_ACCESS", __func__); 468 mvar->status = EFI_UNSUPPORTED; 469 goto rollback; 470 } else if (va->attributes & 471 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { 472 status = uefi_vars_check_auth_2(uv, new_var, va, data); 473 if (status != EFI_SUCCESS) { 474 mvar->status = status; 475 goto rollback; 476 } 477 if (old_var && new_var) { 478 if (uefi_time_compare(&old_var->time, &new_var->time) > 0) { 479 trace_uefi_vars_security_violation("time check failed"); 480 mvar->status = EFI_SECURITY_VIOLATION; 481 goto rollback; 482 } 483 if (old_var->digest_size || new_var->digest_size) { 484 if (!uefi_vars_mm_digest_compare(old_var, new_var)) { 485 mvar->status = EFI_SECURITY_VIOLATION; 486 goto rollback; 487 } 488 } 489 } 490 } else { 491 new_var->data = g_malloc(va->data_size); 492 memcpy(new_var->data, data, va->data_size); 493 new_var->data_size = va->data_size; 494 } 495 if (!new_var->data) { 496 /* we land here when deleting authenticated variables */ 497 del_variable(uv, new_var); 498 new_var = NULL; 499 } 500 } else { 501 new_var = NULL; 502 } 503 504 if (!old_var && !new_var) { 505 /* delete non-existing variable -> nothing to do */ 506 mvar->status = EFI_SUCCESS; 507 return sizeof(*mvar); 508 } 509 510 /* check permissions etc. */ 511 status = check_update(uv, old_var, new_var); 512 if (status != EFI_SUCCESS) { 513 mvar->status = status; 514 goto rollback; 515 } 516 517 if (va->attributes & EFI_VARIABLE_APPEND_WRITE && old_var && new_var) { 518 /* merge signature databases */ 519 if (!uefi_vars_is_sb_any(new_var)) { 520 mvar->status = EFI_UNSUPPORTED; 521 goto rollback; 522 } 523 append_write(old_var, new_var); 524 } 525 526 /* check storage space */ 527 new_storage = uv->used_storage; 528 if (old_var) { 529 new_storage -= variable_size(old_var); 530 } 531 if (new_var) { 532 new_storage += variable_size(new_var); 533 } 534 if (new_storage > uv->max_storage) { 535 mvar->status = EFI_OUT_OF_RESOURCES; 536 goto rollback; 537 } 538 539 attributes = new_var 540 ? new_var->attributes 541 : old_var->attributes; 542 543 /* all good, commit */ 544 del_variable(uv, old_var); 545 uv->used_storage = new_storage; 546 547 if (attributes & EFI_VARIABLE_NON_VOLATILE) { 548 uefi_vars_json_save(uv); 549 } 550 551 if (new_var && uefi_vars_is_sb_pk(new_var)) { 552 uefi_vars_auth_init(uv); 553 } 554 555 mvar->status = EFI_SUCCESS; 556 return sizeof(*mvar); 557 558 rollback: 559 del_variable(uv, new_var); 560 return sizeof(*mvar); 561 } 562 563 static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr, 564 mm_variable *mvar, void *func) 565 { 566 mm_variable_info *vi = func; 567 uint64_t length; 568 569 length = sizeof(*mvar) + sizeof(*vi); 570 if (uv->buf_size < length) { 571 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 572 } 573 574 vi->max_storage_size = uv->max_storage; 575 vi->free_storage_size = uv->max_storage - uv->used_storage; 576 vi->max_variable_size = uv->max_storage >> 2; 577 vi->attributes = 0; 578 579 mvar->status = EFI_SUCCESS; 580 return length; 581 } 582 583 static size_t 584 uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr, 585 mm_variable *mvar, void *func) 586 { 587 mm_get_payload_size *ps = func; 588 uint64_t length; 589 590 length = sizeof(*mvar) + sizeof(*ps); 591 if (uv->buf_size < length) { 592 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 593 } 594 595 ps->payload_size = uv->buf_size; 596 mvar->status = EFI_SUCCESS; 597 return length; 598 } 599 600 static size_t 601 uefi_vars_mm_lock_variable(uefi_vars_state *uv, mm_header *mhdr, 602 mm_variable *mvar, void *func) 603 { 604 mm_lock_variable *lv = func; 605 variable_policy_entry *pe; 606 uint16_t *name, *dest; 607 uint64_t length; 608 609 length = sizeof(*mvar) + sizeof(*lv); 610 if (mhdr->length < length) { 611 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 612 } 613 614 name = func + sizeof(*lv); 615 if (uadd64_overflow(length, lv->name_size, &length)) { 616 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 617 } 618 if (mhdr->length < length) { 619 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE); 620 } 621 622 uefi_trace_variable(__func__, lv->guid, name, lv->name_size); 623 624 pe = g_malloc0(sizeof(*pe) + lv->name_size); 625 pe->version = VARIABLE_POLICY_ENTRY_REVISION; 626 pe->size = sizeof(*pe) + lv->name_size; 627 pe->offset_to_name = sizeof(*pe); 628 pe->namespace = lv->guid; 629 pe->min_size = 0; 630 pe->max_size = UINT32_MAX; 631 pe->attributes_must_have = 0; 632 pe->attributes_cant_have = 0; 633 pe->lock_policy_type = VARIABLE_POLICY_TYPE_LOCK_NOW; 634 635 dest = (void *)pe + pe->offset_to_name; 636 memcpy(dest, name, lv->name_size); 637 638 uefi_vars_add_policy(uv, pe); 639 g_free(pe); 640 641 mvar->status = EFI_SUCCESS; 642 return length; 643 } 644 645 uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv) 646 { 647 static const char *fnames[] = { 648 "zero", 649 "get-variable", 650 "get-next-variable-name", 651 "set-variable", 652 "query-variable-info", 653 "ready-to-boot", 654 "exit-boot-service", 655 "get-statistics", 656 "lock-variable", 657 "var-check-prop-set", 658 "var-check-prop-get", 659 "get-payload-size", 660 "init-runtime-cache-contect", 661 "sync-runtime-cache", 662 "get-runtime-cache-info", 663 }; 664 const char *fname; 665 uint64_t length; 666 667 mm_header *mhdr = (mm_header *) uv->buffer; 668 mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr)); 669 void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar)); 670 671 if (mhdr->length < sizeof(*mvar)) { 672 return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE; 673 } 674 675 fname = mvar->function < ARRAY_SIZE(fnames) 676 ? fnames[mvar->function] 677 : "unknown"; 678 trace_uefi_vars_proto_cmd(fname); 679 680 switch (mvar->function) { 681 case SMM_VARIABLE_FUNCTION_GET_VARIABLE: 682 length = uefi_vars_mm_get_variable(uv, mhdr, mvar, func); 683 break; 684 685 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: 686 length = uefi_vars_mm_get_next_variable(uv, mhdr, mvar, func); 687 break; 688 689 case SMM_VARIABLE_FUNCTION_SET_VARIABLE: 690 length = uefi_vars_mm_set_variable(uv, mhdr, mvar, func); 691 break; 692 693 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: 694 length = uefi_vars_mm_variable_info(uv, mhdr, mvar, func); 695 break; 696 697 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE: 698 length = uefi_vars_mm_lock_variable(uv, mhdr, mvar, func); 699 break; 700 701 case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE: 702 length = uefi_vars_mm_get_payload_size(uv, mhdr, mvar, func); 703 break; 704 705 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: 706 trace_uefi_event("ready-to-boot"); 707 uv->ready_to_boot = true; 708 mvar->status = EFI_SUCCESS; 709 length = 0; 710 break; 711 712 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: 713 trace_uefi_event("exit-boot-service"); 714 uv->exit_boot_service = true; 715 mvar->status = EFI_SUCCESS; 716 length = 0; 717 break; 718 719 default: 720 length = uefi_vars_mm_error(mhdr, mvar, EFI_UNSUPPORTED); 721 break; 722 } 723 724 if (mhdr->length < length) { 725 mvar->status = EFI_BUFFER_TOO_SMALL; 726 } 727 728 uefi_trace_status(__func__, mvar->status); 729 return UEFI_VARS_STS_SUCCESS; 730 } 731