mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
In PopulateDescriptor(), each FMP device previously called GetFmpControllerState() multiple times through individual getter functions (GetVersionFromVariable, GetLowestSupportedVersionFromVariable, etc.), each performing a separate GetVariable() call to read the same FmpControllerState NV variable. Rename the getter functions to *FromFmpControllerState and simplify them to pure field extractors that take a required FMP_CONTROLLER_STATE pointer. Each getter extracts the field value if the state is non-NULL and the field is valid, returning a default otherwise. No getter calls GetFmpControllerState() internally. PopulateDescriptor() now calls GetFmpControllerState() once and passes the result to all getters, then frees it after the last use. This eliminates redundant NV reads when the variable exists and avoids repeated failed reads and error messages when the variable does not exist. Signed-off-by: Shubham Kumar <kumarshubha@microsoft.com>
813 lines
28 KiB
C
813 lines
28 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 - 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
|
|
is allocated using the UEFI Boot Service AllocatePool(). Caller must free
|
|
the returned buffer with FreePool().
|
|
|
|
@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.
|
|
**/
|
|
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 extracted from the
|
|
provided FmpControllerState. If FmpControllerState is NULL or the Version
|
|
field is not valid, then a default version value is returned.
|
|
|
|
@param[in] FmpControllerState The cached FMP Controller State, or NULL if the
|
|
state could not be retrieved.
|
|
|
|
@return The version of the firmware image in the firmware device.
|
|
**/
|
|
UINT32
|
|
GetVersionFromFmpControllerState (
|
|
IN FMP_CONTROLLER_STATE *FmpControllerState
|
|
)
|
|
{
|
|
UINT32 Value;
|
|
|
|
Value = DEFAULT_VERSION;
|
|
if ((FmpControllerState != NULL) && FmpControllerState->VersionValid) {
|
|
Value = FmpControllerState->Version;
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FmpDxe(%s): FMP Controller State Version %08x\n",
|
|
mImageIdName,
|
|
Value
|
|
));
|
|
}
|
|
|
|
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 extracted from the
|
|
provided FmpControllerState. If FmpControllerState is NULL or the Lsv field
|
|
is not valid, then a default lowest supported version value is returned.
|
|
|
|
@param[in] FmpControllerState The cached FMP Controller State, or NULL if the
|
|
state could not be retrieved.
|
|
|
|
@return The lowest supported version of the firmware image in the firmware
|
|
device.
|
|
**/
|
|
UINT32
|
|
GetLowestSupportedVersionFromFmpControllerState (
|
|
IN FMP_CONTROLLER_STATE *FmpControllerState
|
|
)
|
|
{
|
|
UINT32 Value;
|
|
|
|
Value = DEFAULT_LOWESTSUPPORTEDVERSION;
|
|
if ((FmpControllerState != NULL) && FmpControllerState->LsvValid) {
|
|
Value = FmpControllerState->Lsv;
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FmpDxe(%s): FMP Controller State LowestSupportedVersion %08x\n",
|
|
mImageIdName,
|
|
Value
|
|
));
|
|
}
|
|
|
|
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 extracted from the
|
|
provided FmpControllerState. If FmpControllerState is NULL or the
|
|
LastAttemptStatus field is not valid, then a default last attempt status value
|
|
is returned.
|
|
|
|
@param[in] FmpControllerState The cached FMP Controller State, or NULL if the
|
|
state could not be retrieved.
|
|
|
|
@return The last attempt status value for the most recent capsule update.
|
|
**/
|
|
UINT32
|
|
GetLastAttemptStatusFromFmpControllerState (
|
|
IN FMP_CONTROLLER_STATE *FmpControllerState
|
|
)
|
|
{
|
|
UINT32 Value;
|
|
|
|
Value = DEFAULT_LASTATTEMPTSTATUS;
|
|
if ((FmpControllerState != NULL) && FmpControllerState->LastAttemptStatusValid) {
|
|
Value = FmpControllerState->LastAttemptStatus;
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FmpDxe(%s): FMP Controller State LastAttemptStatus %08x\n",
|
|
mImageIdName,
|
|
Value
|
|
));
|
|
}
|
|
|
|
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 extracted from the
|
|
provided FmpControllerState. If FmpControllerState is NULL or the
|
|
LastAttemptVersion field is not valid, then a default last attempt version
|
|
value is returned.
|
|
|
|
@param[in] FmpControllerState The cached FMP Controller State, or NULL if the
|
|
state could not be retrieved.
|
|
|
|
@return The last attempt version value for the most recent capsule update.
|
|
**/
|
|
UINT32
|
|
GetLastAttemptVersionFromFmpControllerState (
|
|
IN FMP_CONTROLLER_STATE *FmpControllerState
|
|
)
|
|
{
|
|
UINT32 Value;
|
|
|
|
Value = DEFAULT_LASTATTEMPTVERSION;
|
|
if ((FmpControllerState != NULL) && FmpControllerState->LastAttemptVersionValid) {
|
|
Value = FmpControllerState->LastAttemptVersion;
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FmpDxe(%s): FMP Controller State LastAttemptVersion %08x\n",
|
|
mImageIdName,
|
|
Value
|
|
));
|
|
}
|
|
|
|
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;
|
|
}
|