2 UEFI variable support functions for Firmware Management Protocol based
5 Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
6 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "VariableSupport.h"
16 Retrieve the value of a 32-bit UEFI Variable specified by VariableName and
17 a GUID of gEfiCallerIdGuid.
19 @param[in] VariableName Pointer to the UEFI Variable name to retrieve.
20 @param[out] Valid Set to TRUE if UEFI Variable is present and the size
21 of the UEFI Variable value is 32-bits. Otherwise
23 @param[out] Value If Valid is set to TRUE, then the 32-bit value of
24 the UEFI Variable. Otherwise 0.
29 IN CHAR16
*VariableName
,
42 Status
= GetVariable2 (
48 if (!EFI_ERROR (Status
) && Size
== sizeof (*Value
) && Buffer
!= NULL
) {
58 Delete the UEFI Variable with name specified by VariableName and GUID of
59 gEfiCallerIdGuid. If the variable can not be deleted, then print a
62 @param[in] VariableName Pointer to the UEFI Variable name to delete.
67 IN CHAR16
*VariableName
74 GetFmpVariable (VariableName
, &Valid
, &Value
);
76 Status
= gRT
->SetVariable (VariableName
, &gEfiCallerIdGuid
, 0, 0, NULL
);
77 if (EFI_ERROR (Status
)) {
78 DEBUG ((DEBUG_ERROR
, "Failed to delete FMP Variable %s. Status = %r\n", VariableName
, Status
));
80 DEBUG ((DEBUG_INFO
, "Deleted FMP Variable %s\n", VariableName
));
86 Retrieve the FMP Controller State UEFI Variable value. Return NULL if
87 the variable does not exist or if the size of the UEFI Variable is not the
88 size of FMP_CONTROLLER_STATE. The buffer for the UEFI Variable value
89 if allocated using the UEFI Boot Service AllocatePool().
91 @param[in] Private Private context structure for the managed controller.
93 @return Pointer to the allocated FMP Controller State. Returns NULL
94 if the variable does not exist or is a different size than expected.
97 FMP_CONTROLLER_STATE
*
98 GetFmpControllerState (
99 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
103 FMP_CONTROLLER_STATE
*FmpControllerState
;
106 FmpControllerState
= NULL
;
108 Status
= GetVariable2 (
109 Private
->FmpStateVariableName
,
111 (VOID
**)&FmpControllerState
,
114 if (EFI_ERROR (Status
) || FmpControllerState
== NULL
) {
115 DEBUG ((DEBUG_ERROR
, "Failed to get the FMP Controller State. Status = %r\n", Status
));
117 if (Size
== sizeof (*FmpControllerState
)) {
118 return FmpControllerState
;
120 DEBUG ((DEBUG_ERROR
, "Getting FMP Controller State returned a size different than expected. Size = 0x%x\n", Size
));
122 if (FmpControllerState
!= NULL
) {
123 FreePool (FmpControllerState
);
129 Generates a Null-terminated Unicode string UEFI Variable name from a base name
130 and a hardware instance. If the hardware instance value is 0, then the base
131 name is returned. If the hardware instance value is non-zero, then the 64-bit
132 hardware instance value is converted to a 16 character hex string and appended
133 to base name. The UEFI Variable name returned is allocated using the UEFI
134 Boot Service AllocatePool().
136 @param[in] HardwareInstance 64-bit hardware instance value.
137 @param[in] BaseVariableName Null-terminated Unicode string that is the base
138 name of the UEFI Variable.
140 @return Pointer to the allocated UEFI Variable name. Returns NULL if the
141 UEFI Variable can not be allocated.
145 GenerateFmpVariableName (
146 IN UINT64 HardwareInstance
,
147 IN CHAR16
*BaseVariableName
150 CHAR16
*VariableName
;
152 VariableName
= CatSPrint (NULL
, BaseVariableName
);
153 if (VariableName
== NULL
) {
154 DEBUG ((DEBUG_ERROR
, "Failed to generate FMP variable name %s.\n", BaseVariableName
));
157 if (HardwareInstance
== 0) {
160 VariableName
= CatSPrint (VariableName
, L
"%016lx", HardwareInstance
);
161 if (VariableName
== NULL
) {
162 DEBUG ((DEBUG_ERROR
, "Failed to generate FMP variable name %s.\n", BaseVariableName
));
168 Generate the names of the UEFI Variables used to store state information for
169 a managed controller. The UEFI Variables names are a combination of a base
170 name and an optional hardware instance value as a 16 character hex value. If
171 the hardware instance value is 0, then the 16 character hex value is not
172 included. These storage for the UEFI Variable names are allocated using the
173 UEFI Boot Service AllocatePool() and the pointers are stored in the Private.
174 The following are examples of variable names produces for hardware instance
175 value 0 and value 0x1234567812345678.
183 FmpVersion1234567812345678
184 FmpLsv1234567812345678
185 LastAttemptStatus1234567812345678
186 LastAttemptVersion1234567812345678
187 FmpState1234567812345678
189 @param[in,out] Private Private context structure for the managed controller.
192 GenerateFmpVariableNames (
193 IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
198 FMP_CONTROLLER_STATE FmpControllerState
;
200 if (Private
->VersionVariableName
!= NULL
) {
201 FreePool (Private
->VersionVariableName
);
203 if (Private
->LsvVariableName
!= NULL
) {
204 FreePool (Private
->LsvVariableName
);
206 if (Private
->LastAttemptStatusVariableName
!= NULL
) {
207 FreePool (Private
->LastAttemptStatusVariableName
);
209 if (Private
->LastAttemptVersionVariableName
!= NULL
) {
210 FreePool (Private
->LastAttemptVersionVariableName
);
212 if (Private
->FmpStateVariableName
!= NULL
) {
213 FreePool (Private
->FmpStateVariableName
);
216 Private
->VersionVariableName
= GenerateFmpVariableName (
217 Private
->Descriptor
.HardwareInstance
,
220 Private
->LsvVariableName
= GenerateFmpVariableName (
221 Private
->Descriptor
.HardwareInstance
,
224 Private
->LastAttemptStatusVariableName
= GenerateFmpVariableName (
225 Private
->Descriptor
.HardwareInstance
,
226 VARNAME_LASTATTEMPTSTATUS
228 Private
->LastAttemptVersionVariableName
= GenerateFmpVariableName (
229 Private
->Descriptor
.HardwareInstance
,
230 VARNAME_LASTATTEMPTVERSION
232 Private
->FmpStateVariableName
= GenerateFmpVariableName (
233 Private
->Descriptor
.HardwareInstance
,
237 DEBUG ((DEBUG_INFO
, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid
, Private
->VersionVariableName
));
238 DEBUG ((DEBUG_INFO
, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid
, Private
->LsvVariableName
));
239 DEBUG ((DEBUG_INFO
, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid
, Private
->LastAttemptStatusVariableName
));
240 DEBUG ((DEBUG_INFO
, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid
, Private
->LastAttemptVersionVariableName
));
241 DEBUG ((DEBUG_INFO
, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid
, Private
->FmpStateVariableName
));
243 Buffer
= GetFmpControllerState (Private
);
244 if (Buffer
!= NULL
) {
246 // FMP Controller State was found with correct size.
247 // Delete old variables if they exist.
250 DeleteFmpVariable (Private
->VersionVariableName
);
251 DeleteFmpVariable (Private
->LsvVariableName
);
252 DeleteFmpVariable (Private
->LastAttemptStatusVariableName
);
253 DeleteFmpVariable (Private
->LastAttemptVersionVariableName
);
258 // FMP Controller State was either not found or is wrong size.
259 // Create a new FMP Controller State variable with the correct size.
261 DEBUG ((DEBUG_INFO
, "Create FMP Controller State\n"));
263 Private
->VersionVariableName
,
264 &FmpControllerState
.VersionValid
,
265 &FmpControllerState
.Version
268 Private
->LsvVariableName
,
269 &FmpControllerState
.LsvValid
,
270 &FmpControllerState
.Lsv
273 Private
->LastAttemptStatusVariableName
,
274 &FmpControllerState
.LastAttemptStatusValid
,
275 &FmpControllerState
.LastAttemptStatus
278 Private
->LastAttemptVersionVariableName
,
279 &FmpControllerState
.LastAttemptVersionValid
,
280 &FmpControllerState
.LastAttemptVersion
282 Status
= gRT
->SetVariable (
283 Private
->FmpStateVariableName
,
285 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
286 sizeof (FmpControllerState
),
289 if (EFI_ERROR (Status
)) {
291 // Failed to create FMP Controller State. In this case, do not
292 // delete the individual variables. They can be used again on next boot
293 // to create the FMP Controller State.
295 DEBUG ((DEBUG_ERROR
, "Failed to create FMP Controller State. Status = %r\n", Status
));
297 DeleteFmpVariable (Private
->VersionVariableName
);
298 DeleteFmpVariable (Private
->LsvVariableName
);
299 DeleteFmpVariable (Private
->LastAttemptStatusVariableName
);
300 DeleteFmpVariable (Private
->LastAttemptVersionVariableName
);
305 Returns the value used to fill in the Version field of the
306 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
307 service of the Firmware Management Protocol. The value is read from a UEFI
308 variable. If the UEFI variables does not exist, then a default version value
311 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
313 @param[in] Private Private context structure for the managed controller.
315 @return The version of the firmware image in the firmware device.
318 GetVersionFromVariable (
319 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
322 FMP_CONTROLLER_STATE
*FmpControllerState
;
325 Value
= DEFAULT_VERSION
;
326 FmpControllerState
= GetFmpControllerState (Private
);
327 if (FmpControllerState
!= NULL
) {
328 if (FmpControllerState
->VersionValid
) {
329 Value
= FmpControllerState
->Version
;
330 DEBUG ((DEBUG_INFO
, "Get FMP Variable %g %s Version %08x\n",
332 Private
->FmpStateVariableName
,
336 FreePool (FmpControllerState
);
342 Returns the value used to fill in the LowestSupportedVersion field of the
343 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
344 service of the Firmware Management Protocol. The value is read from a UEFI
345 variable. If the UEFI variables does not exist, then a default lowest
346 supported version value is returned.
348 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
350 @param[in] Private Private context structure for the managed controller.
352 @return The lowest supported version of the firmware image in the firmware
356 GetLowestSupportedVersionFromVariable (
357 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
360 FMP_CONTROLLER_STATE
*FmpControllerState
;
363 Value
= DEFAULT_LOWESTSUPPORTEDVERSION
;
364 FmpControllerState
= GetFmpControllerState (Private
);
365 if (FmpControllerState
!= NULL
) {
366 if (FmpControllerState
->LsvValid
) {
367 Value
= FmpControllerState
->Lsv
;
368 DEBUG ((DEBUG_INFO
, "Get FMP Variable %g %s LowestSupportedVersion %08x\n",
370 Private
->FmpStateVariableName
,
374 FreePool (FmpControllerState
);
380 Returns the value used to fill in the LastAttemptStatus field of the
381 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
382 service of the Firmware Management Protocol. The value is read from a UEFI
383 variable. If the UEFI variables does not exist, then a default last attempt
384 status value is returned.
386 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
388 @param[in] Private Private context structure for the managed controller.
390 @return The last attempt status value for the most recent capsule update.
393 GetLastAttemptStatusFromVariable (
394 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
397 FMP_CONTROLLER_STATE
*FmpControllerState
;
400 Value
= DEFAULT_LASTATTEMPTSTATUS
;
401 FmpControllerState
= GetFmpControllerState (Private
);
402 if (FmpControllerState
!= NULL
) {
403 if (FmpControllerState
->LastAttemptStatusValid
) {
404 Value
= FmpControllerState
->LastAttemptStatus
;
405 DEBUG ((DEBUG_INFO
, "Get FMP Variable %g %s LastAttemptStatus %08x\n",
407 Private
->FmpStateVariableName
,
411 FreePool (FmpControllerState
);
417 Returns the value used to fill in the LastAttemptVersion field of the
418 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
419 service of the Firmware Management Protocol. The value is read from a UEFI
420 variable. If the UEFI variables does not exist, then a default last attempt
421 version value is returned.
423 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
425 @param[in] Private Private context structure for the managed controller.
427 @return The last attempt version value for the most recent capsule update.
430 GetLastAttemptVersionFromVariable (
431 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
434 FMP_CONTROLLER_STATE
*FmpControllerState
;
437 Value
= DEFAULT_LASTATTEMPTVERSION
;
438 FmpControllerState
= GetFmpControllerState (Private
);
439 if (FmpControllerState
!= NULL
) {
440 if (FmpControllerState
->LastAttemptVersionValid
) {
441 Value
= FmpControllerState
->LastAttemptVersion
;
442 DEBUG ((DEBUG_INFO
, "Get FMP Variable %g %s LastAttemptVersion %08x\n",
444 Private
->FmpStateVariableName
,
448 FreePool (FmpControllerState
);
454 Saves the version current of the firmware image in the firmware device to a
457 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
459 @param[in] Private Private context structure for the managed controller.
460 @param[in] Version The version of the firmware image in the firmware device.
463 SetVersionInVariable (
464 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
,
469 FMP_CONTROLLER_STATE
*FmpControllerState
;
472 FmpControllerState
= GetFmpControllerState (Private
);
473 if (FmpControllerState
== NULL
) {
475 // Can not update value if FMP Controller State does not exist.
476 // This variable is guaranteed to be created by GenerateFmpVariableNames().
482 if (!FmpControllerState
->VersionValid
) {
485 if (FmpControllerState
->Version
!= Version
) {
489 DEBUG ((DEBUG_INFO
, "No need to update FMP Controller State. Same value as before.\n"));
491 FmpControllerState
->VersionValid
= TRUE
;
492 FmpControllerState
->Version
= Version
;
493 Status
= gRT
->SetVariable (
494 Private
->FmpStateVariableName
,
496 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
497 sizeof (*FmpControllerState
),
500 if (EFI_ERROR (Status
)) {
501 DEBUG ((DEBUG_ERROR
, "Failed to update FMP Controller State. Status = %r\n", Status
));
503 DEBUG ((DEBUG_INFO
, "Set FMP Variable %g %s Version %08x\n",
505 Private
->FmpStateVariableName
,
510 FreePool (FmpControllerState
);
514 Saves the lowest supported version current of the firmware image in the
515 firmware device to a UEFI variable.
517 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
519 @param[in] Private Private context structure for the managed
521 @param[in] LowestSupportedVersion The lowest supported version of the
522 firmware image in the firmware device.
525 SetLowestSupportedVersionInVariable (
526 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
,
527 IN UINT32 LowestSupportedVersion
531 FMP_CONTROLLER_STATE
*FmpControllerState
;
534 FmpControllerState
= GetFmpControllerState (Private
);
535 if (FmpControllerState
== NULL
) {
537 // Can not update value if FMP Controller State does not exist.
538 // This variable is guaranteed to be created by GenerateFmpVariableNames().
544 if (!FmpControllerState
->LsvValid
) {
547 if (FmpControllerState
->Lsv
< LowestSupportedVersion
) {
551 DEBUG ((DEBUG_INFO
, "No need to update FMP Controller State. Same value as before.\n"));
553 FmpControllerState
->LsvValid
= TRUE
;
554 FmpControllerState
->Lsv
= LowestSupportedVersion
;
555 Status
= gRT
->SetVariable (
556 Private
->FmpStateVariableName
,
558 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
559 sizeof (*FmpControllerState
),
562 if (EFI_ERROR (Status
)) {
563 DEBUG ((DEBUG_ERROR
, "Failed to update FMP Controller State. Status = %r\n", Status
));
565 DEBUG ((DEBUG_INFO
, "Set FMP Variable %g %s LowestSupportedVersion %08x\n",
567 Private
->FmpStateVariableName
,
568 LowestSupportedVersion
572 FreePool (FmpControllerState
);
576 Saves the last attempt status value of the most recent FMP capsule update to a
579 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
581 @param[in] Private Private context structure for the managed
583 @param[in] LastAttemptStatus The last attempt status of the most recent FMP
587 SetLastAttemptStatusInVariable (
588 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
,
589 IN UINT32 LastAttemptStatus
593 FMP_CONTROLLER_STATE
*FmpControllerState
;
596 FmpControllerState
= GetFmpControllerState (Private
);
597 if (FmpControllerState
== NULL
) {
599 // Can not update value if FMP Controller State does not exist.
600 // This variable is guaranteed to be created by GenerateFmpVariableNames().
606 if (!FmpControllerState
->LastAttemptStatusValid
) {
609 if (FmpControllerState
->LastAttemptStatus
!= LastAttemptStatus
) {
613 DEBUG ((DEBUG_INFO
, "No need to update FMP Controller State. Same value as before.\n"));
615 FmpControllerState
->LastAttemptStatusValid
= TRUE
;
616 FmpControllerState
->LastAttemptStatus
= LastAttemptStatus
;
617 Status
= gRT
->SetVariable (
618 Private
->FmpStateVariableName
,
620 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
621 sizeof (*FmpControllerState
),
624 if (EFI_ERROR (Status
)) {
625 DEBUG ((DEBUG_ERROR
, "Failed to update FMP Controller State. Status = %r\n", Status
));
627 DEBUG ((DEBUG_INFO
, "Set FMP Variable %g %s LastAttemptStatus %08x\n",
629 Private
->FmpStateVariableName
,
634 FreePool (FmpControllerState
);
638 Saves the last attempt version value of the most recent FMP capsule update to
641 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
643 @param[in] Private Private context structure for the managed
645 @param[in] LastAttemptVersion The last attempt version value of the most
646 recent FMP capsule update.
649 SetLastAttemptVersionInVariable (
650 IN FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
,
651 IN UINT32 LastAttemptVersion
655 FMP_CONTROLLER_STATE
*FmpControllerState
;
658 FmpControllerState
= GetFmpControllerState (Private
);
659 if (FmpControllerState
== NULL
) {
661 // Can not update value if FMP Controller State does not exist.
662 // This variable is guaranteed to be created by GenerateFmpVariableNames().
668 if (!FmpControllerState
->LastAttemptVersionValid
) {
671 if (FmpControllerState
->LastAttemptVersion
!= LastAttemptVersion
) {
675 DEBUG ((DEBUG_INFO
, "No need to update FMP Controller State. Same value as before.\n"));
677 FmpControllerState
->LastAttemptVersionValid
= TRUE
;
678 FmpControllerState
->LastAttemptVersion
= LastAttemptVersion
;
679 Status
= gRT
->SetVariable (
680 Private
->FmpStateVariableName
,
682 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
683 sizeof (*FmpControllerState
),
686 if (EFI_ERROR (Status
)) {
687 DEBUG ((DEBUG_ERROR
, "Failed to update FMP Controller State. Status = %r\n", Status
));
689 DEBUG ((DEBUG_INFO
, "Set FMP Variable %g %s LastAttemptVersion %08x\n",
691 Private
->FmpStateVariableName
,
696 FreePool (FmpControllerState
);
700 Attempts to lock a single UEFI Variable propagating the error state of the
701 first lock attempt that fails. Uses gEfiCallerIdGuid as the variable GUID.
703 @param[in] PreviousStatus The previous UEFI Variable lock attempt status.
704 @param[in] VariableLock The EDK II Variable Lock Protocol instance.
705 @param[in] VariableName The name of the UEFI Variable to lock.
707 @retval EFI_SUCCESS The UEFI Variable was locked and the previous variable
708 lock attempt also succeeded.
709 @retval Other The UEFI Variable could not be locked or the previous
710 variable lock attempt failed.
715 IN EFI_STATUS PreviousStatus
,
716 IN EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
,
717 IN CHAR16
*VariableName
722 Status
= VariableLock
->RequestToLock (
727 if (!EFI_ERROR (Status
)) {
728 return PreviousStatus
;
731 DEBUG ((DEBUG_ERROR
, "FmpDxe: Failed to lock variable %g %s. Status = %r\n",
737 if (EFI_ERROR (PreviousStatus
)) {
738 return PreviousStatus
;
744 Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently
747 @param[in] Private Private context structure for the managed controller.
749 @retval EFI_SUCCESS All UEFI variables are locked.
750 @retval EFI_UNSUPPORTED Variable Lock Protocol not found.
751 @retval Other One of the UEFI variables could not be locked.
754 LockAllFmpVariables (
755 FIRMWARE_MANAGEMENT_PRIVATE_DATA
*Private
759 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
762 Status
= gBS
->LocateProtocol (
763 &gEdkiiVariableLockProtocolGuid
,
765 (VOID
**)&VariableLock
767 if (EFI_ERROR (Status
) || VariableLock
== NULL
) {
768 DEBUG ((DEBUG_ERROR
, "FmpDxe: Failed to locate Variable Lock Protocol (%r).\n", Status
));
769 return EFI_UNSUPPORTED
;
772 Status
= EFI_SUCCESS
;
773 Status
= LockFmpVariable (Status
, VariableLock
, Private
->VersionVariableName
);
774 Status
= LockFmpVariable (Status
, VariableLock
, Private
->LsvVariableName
);
775 Status
= LockFmpVariable (Status
, VariableLock
, Private
->LastAttemptStatusVariableName
);
776 Status
= LockFmpVariable (Status
, VariableLock
, Private
->LastAttemptVersionVariableName
);
777 Status
= LockFmpVariable (Status
, VariableLock
, Private
->FmpStateVariableName
);