mirror of https://github.com/acidanthera/audk.git
799 lines
27 KiB
C
799 lines
27 KiB
C
/** @file
|
|
UEFI variable support functions for Firmware Management Protocol based
|
|
firmware updates.
|
|
|
|
Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
|
|
Copyright (c) 2018 - 2019, 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_LOCK_PROTOCOL *VariableLock,
|
|
IN CHAR16 *VariableName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = VariableLock->RequestToLock (
|
|
VariableLock,
|
|
VariableName,
|
|
&gEfiCallerIdGuid
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
return PreviousStatus;
|
|
}
|
|
|
|
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_LOCK_PROTOCOL *VariableLock;
|
|
|
|
VariableLock = NULL;
|
|
Status = gBS->LocateProtocol (
|
|
&gEdkiiVariableLockProtocolGuid,
|
|
NULL,
|
|
(VOID **)&VariableLock
|
|
);
|
|
if (EFI_ERROR (Status) || VariableLock == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to locate Variable Lock Protocol (%r).\n", mImageIdName, Status));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
Status = LockFmpVariable (Status, VariableLock, Private->VersionVariableName);
|
|
Status = LockFmpVariable (Status, VariableLock, Private->LsvVariableName);
|
|
Status = LockFmpVariable (Status, VariableLock, Private->LastAttemptStatusVariableName);
|
|
Status = LockFmpVariable (Status, VariableLock, Private->LastAttemptVersionVariableName);
|
|
Status = LockFmpVariable (Status, VariableLock, Private->FmpStateVariableName);
|
|
|
|
return Status;
|
|
}
|