/** @file | |
UEFI variable support functions for Firmware Management Protocol based | |
firmware updates. | |
Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR> | |
Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "FmpDxe.h" | |
#include "VariableSupport.h" | |
/** | |
Retrieve the value of a 32-bit UEFI Variable specified by VariableName and | |
a GUID of gEfiCallerIdGuid. | |
@param[in] VariableName Pointer to the UEFI Variable name to retrieve. | |
@param[out] Valid Set to TRUE if UEFI Variable is present and the size | |
of the UEFI Variable value is 32-bits. Otherwise | |
FALSE. | |
@param[out] Value If Valid is set to TRUE, then the 32-bit value of | |
the UEFI Variable. Otherwise 0. | |
**/ | |
static | |
VOID | |
GetFmpVariable ( | |
IN CHAR16 *VariableName, | |
OUT BOOLEAN *Valid, | |
OUT UINT32 *Value | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Size; | |
UINT32 *Buffer; | |
*Valid = FALSE; | |
*Value = 0; | |
Size = 0; | |
Buffer = NULL; | |
Status = GetVariable2 ( | |
VariableName, | |
&gEfiCallerIdGuid, | |
(VOID **)&Buffer, | |
&Size | |
); | |
if (!EFI_ERROR (Status) && (Size == sizeof (*Value)) && (Buffer != NULL)) { | |
*Valid = TRUE; | |
*Value = *Buffer; | |
} | |
if (Buffer != NULL) { | |
FreePool (Buffer); | |
} | |
} | |
/** | |
Delete the UEFI Variable with name specified by VariableName and GUID of | |
gEfiCallerIdGuid. If the variable can not be deleted, then print a | |
DEBUG_ERROR message. | |
@param[in] VariableName Pointer to the UEFI Variable name to delete. | |
**/ | |
static | |
VOID | |
DeleteFmpVariable ( | |
IN CHAR16 *VariableName | |
) | |
{ | |
EFI_STATUS Status; | |
BOOLEAN Valid; | |
UINT32 Value; | |
GetFmpVariable (VariableName, &Valid, &Value); | |
if (Valid) { | |
Status = gRT->SetVariable (VariableName, &gEfiCallerIdGuid, 0, 0, NULL); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to delete variable %s. Status = %r\n", mImageIdName, VariableName, Status)); | |
} else { | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Deleted variable %s\n", mImageIdName, VariableName)); | |
} | |
} | |
} | |
/** | |
Retrieve the FMP Controller State UEFI Variable value. Return NULL if | |
the variable does not exist or if the size of the UEFI Variable is not the | |
size of FMP_CONTROLLER_STATE. The buffer for the UEFI Variable value | |
if allocated using the UEFI Boot Service AllocatePool(). | |
@param[in] Private Private context structure for the managed controller. | |
@return Pointer to the allocated FMP Controller State. Returns NULL | |
if the variable does not exist or is a different size than expected. | |
**/ | |
static | |
FMP_CONTROLLER_STATE * | |
GetFmpControllerState ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
EFI_STATUS Status; | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
UINTN Size; | |
FmpControllerState = NULL; | |
Size = 0; | |
Status = GetVariable2 ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
(VOID **)&FmpControllerState, | |
&Size | |
); | |
if (EFI_ERROR (Status) || (FmpControllerState == NULL)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to get the controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
if (Size == sizeof (*FmpControllerState)) { | |
return FmpControllerState; | |
} | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Getting controller state returned a size different than expected. Size = 0x%x\n", mImageIdName, Size)); | |
} | |
if (FmpControllerState != NULL) { | |
FreePool (FmpControllerState); | |
} | |
return NULL; | |
} | |
/** | |
Generates a Null-terminated Unicode string UEFI Variable name from a base name | |
and a hardware instance. If the hardware instance value is 0, then the base | |
name is returned. If the hardware instance value is non-zero, then the 64-bit | |
hardware instance value is converted to a 16 character hex string and appended | |
to base name. The UEFI Variable name returned is allocated using the UEFI | |
Boot Service AllocatePool(). | |
@param[in] HardwareInstance 64-bit hardware instance value. | |
@param[in] BaseVariableName Null-terminated Unicode string that is the base | |
name of the UEFI Variable. | |
@return Pointer to the allocated UEFI Variable name. Returns NULL if the | |
UEFI Variable can not be allocated. | |
**/ | |
static | |
CHAR16 * | |
GenerateFmpVariableName ( | |
IN UINT64 HardwareInstance, | |
IN CHAR16 *BaseVariableName | |
) | |
{ | |
UINTN Size; | |
CHAR16 *VariableName; | |
// | |
// Allocate Unicode string with room for BaseVariableName and a 16 digit | |
// hexadecimal value for the HardwareInstance value. | |
// | |
Size = StrSize (BaseVariableName) + 16 * sizeof (CHAR16); | |
VariableName = AllocateCopyPool (Size, BaseVariableName); | |
if (VariableName == NULL) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to generate variable name %s.\n", mImageIdName, BaseVariableName)); | |
return VariableName; | |
} | |
if (HardwareInstance == 0) { | |
return VariableName; | |
} | |
UnicodeValueToStringS ( | |
&VariableName[StrLen (BaseVariableName)], | |
Size, | |
PREFIX_ZERO | RADIX_HEX, | |
HardwareInstance, | |
16 | |
); | |
return VariableName; | |
} | |
/** | |
Generate the names of the UEFI Variables used to store state information for | |
a managed controller. The UEFI Variables names are a combination of a base | |
name and an optional hardware instance value as a 16 character hex value. If | |
the hardware instance value is 0, then the 16 character hex value is not | |
included. These storage for the UEFI Variable names are allocated using the | |
UEFI Boot Service AllocatePool() and the pointers are stored in the Private. | |
The following are examples of variable names produces for hardware instance | |
value 0 and value 0x1234567812345678. | |
FmpVersion | |
FmpLsv | |
LastAttemptStatus | |
LastAttemptVersion | |
FmpState | |
FmpVersion1234567812345678 | |
FmpLsv1234567812345678 | |
LastAttemptStatus1234567812345678 | |
LastAttemptVersion1234567812345678 | |
FmpState1234567812345678 | |
@param[in,out] Private Private context structure for the managed controller. | |
**/ | |
VOID | |
GenerateFmpVariableNames ( | |
IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *Buffer; | |
FMP_CONTROLLER_STATE FmpControllerState; | |
if (Private->VersionVariableName != NULL) { | |
FreePool (Private->VersionVariableName); | |
} | |
if (Private->LsvVariableName != NULL) { | |
FreePool (Private->LsvVariableName); | |
} | |
if (Private->LastAttemptStatusVariableName != NULL) { | |
FreePool (Private->LastAttemptStatusVariableName); | |
} | |
if (Private->LastAttemptVersionVariableName != NULL) { | |
FreePool (Private->LastAttemptVersionVariableName); | |
} | |
if (Private->FmpStateVariableName != NULL) { | |
FreePool (Private->FmpStateVariableName); | |
} | |
Private->VersionVariableName = GenerateFmpVariableName ( | |
Private->Descriptor.HardwareInstance, | |
VARNAME_VERSION | |
); | |
Private->LsvVariableName = GenerateFmpVariableName ( | |
Private->Descriptor.HardwareInstance, | |
VARNAME_LSV | |
); | |
Private->LastAttemptStatusVariableName = GenerateFmpVariableName ( | |
Private->Descriptor.HardwareInstance, | |
VARNAME_LASTATTEMPTSTATUS | |
); | |
Private->LastAttemptVersionVariableName = GenerateFmpVariableName ( | |
Private->Descriptor.HardwareInstance, | |
VARNAME_LASTATTEMPTVERSION | |
); | |
Private->FmpStateVariableName = GenerateFmpVariableName ( | |
Private->Descriptor.HardwareInstance, | |
VARNAME_FMPSTATE | |
); | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->VersionVariableName)); | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LsvVariableName)); | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptStatusVariableName)); | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptVersionVariableName)); | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->FmpStateVariableName)); | |
Buffer = GetFmpControllerState (Private); | |
if (Buffer != NULL) { | |
// | |
// FMP Controller State was found with correct size. | |
// Delete old variables if they exist. | |
// | |
FreePool (Buffer); | |
DeleteFmpVariable (Private->VersionVariableName); | |
DeleteFmpVariable (Private->LsvVariableName); | |
DeleteFmpVariable (Private->LastAttemptStatusVariableName); | |
DeleteFmpVariable (Private->LastAttemptVersionVariableName); | |
return; | |
} | |
// | |
// FMP Controller State was either not found or is wrong size. | |
// Create a new FMP Controller State variable with the correct size. | |
// | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): Create controller state\n", mImageIdName)); | |
GetFmpVariable ( | |
Private->VersionVariableName, | |
&FmpControllerState.VersionValid, | |
&FmpControllerState.Version | |
); | |
GetFmpVariable ( | |
Private->LsvVariableName, | |
&FmpControllerState.LsvValid, | |
&FmpControllerState.Lsv | |
); | |
GetFmpVariable ( | |
Private->LastAttemptStatusVariableName, | |
&FmpControllerState.LastAttemptStatusValid, | |
&FmpControllerState.LastAttemptStatus | |
); | |
GetFmpVariable ( | |
Private->LastAttemptVersionVariableName, | |
&FmpControllerState.LastAttemptVersionValid, | |
&FmpControllerState.LastAttemptVersion | |
); | |
Status = gRT->SetVariable ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
sizeof (FmpControllerState), | |
&FmpControllerState | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Failed to create FMP Controller State. In this case, do not | |
// delete the individual variables. They can be used again on next boot | |
// to create the FMP Controller State. | |
// | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to create controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
DeleteFmpVariable (Private->VersionVariableName); | |
DeleteFmpVariable (Private->LsvVariableName); | |
DeleteFmpVariable (Private->LastAttemptStatusVariableName); | |
DeleteFmpVariable (Private->LastAttemptVersionVariableName); | |
} | |
} | |
/** | |
Returns the value used to fill in the Version field of the | |
EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo() | |
service of the Firmware Management Protocol. The value is read from a UEFI | |
variable. If the UEFI variables does not exist, then a default version value | |
is returned. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed controller. | |
@return The version of the firmware image in the firmware device. | |
**/ | |
UINT32 | |
GetVersionFromVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
UINT32 Value; | |
Value = DEFAULT_VERSION; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState != NULL) { | |
if (FmpControllerState->VersionValid) { | |
Value = FmpControllerState->Version; | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Get variable %g %s Version %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
Value | |
)); | |
} | |
FreePool (FmpControllerState); | |
} | |
return Value; | |
} | |
/** | |
Returns the value used to fill in the LowestSupportedVersion field of the | |
EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo() | |
service of the Firmware Management Protocol. The value is read from a UEFI | |
variable. If the UEFI variables does not exist, then a default lowest | |
supported version value is returned. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed controller. | |
@return The lowest supported version of the firmware image in the firmware | |
device. | |
**/ | |
UINT32 | |
GetLowestSupportedVersionFromVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
UINT32 Value; | |
Value = DEFAULT_LOWESTSUPPORTEDVERSION; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState != NULL) { | |
if (FmpControllerState->LsvValid) { | |
Value = FmpControllerState->Lsv; | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Get variable %g %s LowestSupportedVersion %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
Value | |
)); | |
} | |
FreePool (FmpControllerState); | |
} | |
return Value; | |
} | |
/** | |
Returns the value used to fill in the LastAttemptStatus field of the | |
EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo() | |
service of the Firmware Management Protocol. The value is read from a UEFI | |
variable. If the UEFI variables does not exist, then a default last attempt | |
status value is returned. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed controller. | |
@return The last attempt status value for the most recent capsule update. | |
**/ | |
UINT32 | |
GetLastAttemptStatusFromVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
UINT32 Value; | |
Value = DEFAULT_LASTATTEMPTSTATUS; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState != NULL) { | |
if (FmpControllerState->LastAttemptStatusValid) { | |
Value = FmpControllerState->LastAttemptStatus; | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Get variable %g %s LastAttemptStatus %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
Value | |
)); | |
} | |
FreePool (FmpControllerState); | |
} | |
return Value; | |
} | |
/** | |
Returns the value used to fill in the LastAttemptVersion field of the | |
EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo() | |
service of the Firmware Management Protocol. The value is read from a UEFI | |
variable. If the UEFI variables does not exist, then a default last attempt | |
version value is returned. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed controller. | |
@return The last attempt version value for the most recent capsule update. | |
**/ | |
UINT32 | |
GetLastAttemptVersionFromVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
UINT32 Value; | |
Value = DEFAULT_LASTATTEMPTVERSION; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState != NULL) { | |
if (FmpControllerState->LastAttemptVersionValid) { | |
Value = FmpControllerState->LastAttemptVersion; | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Get variable %g %s LastAttemptVersion %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
Value | |
)); | |
} | |
FreePool (FmpControllerState); | |
} | |
return Value; | |
} | |
/** | |
Saves the version current of the firmware image in the firmware device to a | |
UEFI variable. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed controller. | |
@param[in] Version The version of the firmware image in the firmware device. | |
**/ | |
VOID | |
SetVersionInVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private, | |
IN UINT32 Version | |
) | |
{ | |
EFI_STATUS Status; | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
BOOLEAN Update; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState == NULL) { | |
// | |
// Can not update value if FMP Controller State does not exist. | |
// This variable is guaranteed to be created by GenerateFmpVariableNames(). | |
// | |
return; | |
} | |
Update = FALSE; | |
if (!FmpControllerState->VersionValid) { | |
Update = TRUE; | |
} | |
if (FmpControllerState->Version != Version) { | |
Update = TRUE; | |
} | |
if (!Update) { | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName)); | |
} else { | |
FmpControllerState->VersionValid = TRUE; | |
FmpControllerState->Version = Version; | |
Status = gRT->SetVariable ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
sizeof (*FmpControllerState), | |
FmpControllerState | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Set variable %g %s Version %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
Version | |
)); | |
} | |
} | |
FreePool (FmpControllerState); | |
} | |
/** | |
Saves the lowest supported version current of the firmware image in the | |
firmware device to a UEFI variable. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed | |
controller. | |
@param[in] LowestSupportedVersion The lowest supported version of the | |
firmware image in the firmware device. | |
**/ | |
VOID | |
SetLowestSupportedVersionInVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private, | |
IN UINT32 LowestSupportedVersion | |
) | |
{ | |
EFI_STATUS Status; | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
BOOLEAN Update; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState == NULL) { | |
// | |
// Can not update value if FMP Controller State does not exist. | |
// This variable is guaranteed to be created by GenerateFmpVariableNames(). | |
// | |
return; | |
} | |
Update = FALSE; | |
if (!FmpControllerState->LsvValid) { | |
Update = TRUE; | |
} | |
if (FmpControllerState->Lsv < LowestSupportedVersion) { | |
Update = TRUE; | |
} | |
if (!Update) { | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName)); | |
} else { | |
FmpControllerState->LsvValid = TRUE; | |
FmpControllerState->Lsv = LowestSupportedVersion; | |
Status = gRT->SetVariable ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
sizeof (*FmpControllerState), | |
FmpControllerState | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Set variable %g %s LowestSupportedVersion %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
LowestSupportedVersion | |
)); | |
} | |
} | |
FreePool (FmpControllerState); | |
} | |
/** | |
Saves the last attempt status value of the most recent FMP capsule update to a | |
UEFI variable. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed | |
controller. | |
@param[in] LastAttemptStatus The last attempt status of the most recent FMP | |
capsule update. | |
**/ | |
VOID | |
SetLastAttemptStatusInVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private, | |
IN UINT32 LastAttemptStatus | |
) | |
{ | |
EFI_STATUS Status; | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
BOOLEAN Update; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState == NULL) { | |
// | |
// Can not update value if FMP Controller State does not exist. | |
// This variable is guaranteed to be created by GenerateFmpVariableNames(). | |
// | |
return; | |
} | |
Update = FALSE; | |
if (!FmpControllerState->LastAttemptStatusValid) { | |
Update = TRUE; | |
} | |
if (FmpControllerState->LastAttemptStatus != LastAttemptStatus) { | |
Update = TRUE; | |
} | |
if (!Update) { | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName)); | |
} else { | |
FmpControllerState->LastAttemptStatusValid = TRUE; | |
FmpControllerState->LastAttemptStatus = LastAttemptStatus; | |
Status = gRT->SetVariable ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
sizeof (*FmpControllerState), | |
FmpControllerState | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Set variable %g %s LastAttemptStatus %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
LastAttemptStatus | |
)); | |
} | |
} | |
FreePool (FmpControllerState); | |
} | |
/** | |
Saves the last attempt version value of the most recent FMP capsule update to | |
a UEFI variable. | |
UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState" | |
@param[in] Private Private context structure for the managed | |
controller. | |
@param[in] LastAttemptVersion The last attempt version value of the most | |
recent FMP capsule update. | |
**/ | |
VOID | |
SetLastAttemptVersionInVariable ( | |
IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private, | |
IN UINT32 LastAttemptVersion | |
) | |
{ | |
EFI_STATUS Status; | |
FMP_CONTROLLER_STATE *FmpControllerState; | |
BOOLEAN Update; | |
FmpControllerState = GetFmpControllerState (Private); | |
if (FmpControllerState == NULL) { | |
// | |
// Can not update value if FMP Controller State does not exist. | |
// This variable is guaranteed to be created by GenerateFmpVariableNames(). | |
// | |
return; | |
} | |
Update = FALSE; | |
if (!FmpControllerState->LastAttemptVersionValid) { | |
Update = TRUE; | |
} | |
if (FmpControllerState->LastAttemptVersion != LastAttemptVersion) { | |
Update = TRUE; | |
} | |
if (!Update) { | |
DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName)); | |
} else { | |
FmpControllerState->LastAttemptVersionValid = TRUE; | |
FmpControllerState->LastAttemptVersion = LastAttemptVersion; | |
Status = gRT->SetVariable ( | |
Private->FmpStateVariableName, | |
&gEfiCallerIdGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
sizeof (*FmpControllerState), | |
FmpControllerState | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status)); | |
} else { | |
DEBUG (( | |
DEBUG_INFO, | |
"FmpDxe(%s): Set variable %g %s LastAttemptVersion %08x\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
Private->FmpStateVariableName, | |
LastAttemptVersion | |
)); | |
} | |
} | |
FreePool (FmpControllerState); | |
} | |
/** | |
Attempts to lock a single UEFI Variable propagating the error state of the | |
first lock attempt that fails. Uses gEfiCallerIdGuid as the variable GUID. | |
@param[in] PreviousStatus The previous UEFI Variable lock attempt status. | |
@param[in] VariableLock The EDK II Variable Lock Protocol instance. | |
@param[in] VariableName The name of the UEFI Variable to lock. | |
@retval EFI_SUCCESS The UEFI Variable was locked and the previous variable | |
lock attempt also succeeded. | |
@retval Other The UEFI Variable could not be locked or the previous | |
variable lock attempt failed. | |
**/ | |
static | |
EFI_STATUS | |
LockFmpVariable ( | |
IN EFI_STATUS PreviousStatus, | |
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy, | |
IN CHAR16 *VariableName | |
) | |
{ | |
EFI_STATUS Status; | |
// If success, go ahead and set the policies to protect the target variables. | |
Status = RegisterBasicVariablePolicy ( | |
VariablePolicy, | |
&gEfiCallerIdGuid, | |
VariableName, | |
VARIABLE_POLICY_NO_MIN_SIZE, | |
VARIABLE_POLICY_NO_MAX_SIZE, | |
VARIABLE_POLICY_NO_MUST_ATTR, | |
VARIABLE_POLICY_NO_CANT_ATTR, | |
VARIABLE_POLICY_TYPE_LOCK_NOW | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"FmpDxe(%s): Failed to lock variable %g %s. Status = %r\n", | |
mImageIdName, | |
&gEfiCallerIdGuid, | |
VariableName, | |
Status | |
)); | |
} | |
if (EFI_ERROR (PreviousStatus)) { | |
return PreviousStatus; | |
} | |
return Status; | |
} | |
/** | |
Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently | |
executing module. | |
@param[in] Private Private context structure for the managed controller. | |
@retval EFI_SUCCESS All UEFI variables are locked. | |
@retval EFI_UNSUPPORTED Variable Lock Protocol not found. | |
@retval Other One of the UEFI variables could not be locked. | |
**/ | |
EFI_STATUS | |
LockAllFmpVariables ( | |
FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private | |
) | |
{ | |
EFI_STATUS Status; | |
EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy; | |
// Locate the VariablePolicy protocol. | |
Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "FmpDxe %a - Could not locate VariablePolicy protocol! %r\n", __func__, Status)); | |
return Status; | |
} | |
Status = EFI_SUCCESS; | |
Status = LockFmpVariable (Status, VariablePolicy, Private->VersionVariableName); | |
Status = LockFmpVariable (Status, VariablePolicy, Private->LsvVariableName); | |
Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptStatusVariableName); | |
Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptVersionVariableName); | |
Status = LockFmpVariable (Status, VariablePolicy, Private->FmpStateVariableName); | |
return Status; | |
} |