/** @file | |
Implementation functions and structures for var check services. | |
Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Library/VarCheckLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Guid/GlobalVariable.h> | |
#include <Guid/HardwareErrorVariable.h> | |
BOOLEAN mVarCheckLibEndOfDxe = FALSE; | |
#define VAR_CHECK_TABLE_SIZE 0x8 | |
UINTN mVarCheckLibEndOfDxeCallbackCount = 0; | |
UINTN mVarCheckLibEndOfDxeCallbackMaxCount = 0; | |
VAR_CHECK_END_OF_DXE_CALLBACK *mVarCheckLibEndOfDxeCallback = NULL; | |
UINTN mVarCheckLibAddressPointerCount = 0; | |
UINTN mVarCheckLibAddressPointerMaxCount = 0; | |
VOID ***mVarCheckLibAddressPointer = NULL; | |
UINTN mNumberOfVarCheckHandler = 0; | |
UINTN mMaxNumberOfVarCheckHandler = 0; | |
VAR_CHECK_SET_VARIABLE_CHECK_HANDLER *mVarCheckHandlerTable = NULL; | |
typedef struct { | |
EFI_GUID Guid; | |
VAR_CHECK_VARIABLE_PROPERTY VariableProperty; | |
// CHAR16 *Name; | |
} VAR_CHECK_VARIABLE_ENTRY; | |
UINTN mNumberOfVarCheckVariable = 0; | |
UINTN mMaxNumberOfVarCheckVariable = 0; | |
VARIABLE_ENTRY_PROPERTY **mVarCheckVariableTable = NULL; | |
// | |
// Handle variables with wildcard name specially. | |
// | |
VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = { | |
{ | |
&gEfiGlobalVariableGuid, | |
L"Boot####", | |
{ | |
0 | |
}, | |
}, | |
{ | |
&gEfiGlobalVariableGuid, | |
L"Driver####", | |
{ | |
0 | |
}, | |
}, | |
{ | |
&gEfiGlobalVariableGuid, | |
L"SysPrep####", | |
{ | |
0 | |
}, | |
}, | |
{ | |
&gEfiGlobalVariableGuid, | |
L"Key####", | |
{ | |
0 | |
}, | |
}, | |
{ | |
&gEfiGlobalVariableGuid, | |
L"PlatformRecovery####", | |
{ | |
0 | |
}, | |
}, | |
{ | |
&gEfiHardwareErrorVariableGuid, | |
L"HwErrRec####", | |
{ | |
0 | |
}, | |
}, | |
}; | |
/** | |
Check if a Unicode character is an upper case hexadecimal character. | |
This function checks if a Unicode character is an upper case | |
hexadecimal character. The valid upper case hexadecimal character is | |
L'0' to L'9', or L'A' to L'F'. | |
@param[in] Char The character to check against. | |
@retval TRUE If the Char is an upper case hexadecmial character. | |
@retval FALSE If the Char is not an upper case hexadecmial character. | |
**/ | |
BOOLEAN | |
EFIAPI | |
VarCheckInternalIsHexaDecimalDigitCharacter ( | |
IN CHAR16 Char | |
) | |
{ | |
return (BOOLEAN)((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F')); | |
} | |
/** | |
Variable property get with wildcard name. | |
@param[in] VariableName Pointer to variable name. | |
@param[in] VendorGuid Pointer to variable vendor GUID. | |
@param[in] WildcardMatch Try wildcard match or not. | |
@return Pointer to variable property. | |
**/ | |
VAR_CHECK_VARIABLE_PROPERTY * | |
VariablePropertyGetWithWildcardName ( | |
IN CHAR16 *VariableName, | |
IN EFI_GUID *VendorGuid, | |
IN BOOLEAN WildcardMatch | |
) | |
{ | |
UINTN Index; | |
UINTN NameLength; | |
NameLength = StrLen (VariableName) - 4; | |
for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) { | |
if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)) { | |
if (WildcardMatch) { | |
if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) && | |
(StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) && | |
VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) && | |
VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) && | |
VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) && | |
VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) | |
{ | |
return &mVarCheckVariableWithWildcardName[Index].VariableProperty; | |
} | |
} | |
if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) { | |
return &mVarCheckVariableWithWildcardName[Index].VariableProperty; | |
} | |
} | |
} | |
return NULL; | |
} | |
/** | |
Variable property get function. | |
@param[in] Name Pointer to the variable name. | |
@param[in] Guid Pointer to the vendor GUID. | |
@param[in] WildcardMatch Try wildcard match or not. | |
@return Pointer to the property of variable specified by the Name and Guid. | |
**/ | |
VAR_CHECK_VARIABLE_PROPERTY * | |
VariablePropertyGetFunction ( | |
IN CHAR16 *Name, | |
IN EFI_GUID *Guid, | |
IN BOOLEAN WildcardMatch | |
) | |
{ | |
UINTN Index; | |
VAR_CHECK_VARIABLE_ENTRY *Entry; | |
CHAR16 *VariableName; | |
for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) { | |
Entry = (VAR_CHECK_VARIABLE_ENTRY *)mVarCheckVariableTable[Index]; | |
VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry)); | |
if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) { | |
return &Entry->VariableProperty; | |
} | |
} | |
return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch); | |
} | |
/** | |
Var check add table entry. | |
@param[in, out] Table Pointer to table buffer. | |
@param[in, out] MaxNumber Pointer to maximum number of entry in the table. | |
@param[in, out] CurrentNumber Pointer to current number of entry in the table. | |
@param[in] Entry Entry will be added to the table. | |
@retval EFI_SUCCESS Reallocate memory successfully. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to allocate. | |
**/ | |
EFI_STATUS | |
VarCheckAddTableEntry ( | |
IN OUT UINTN **Table, | |
IN OUT UINTN *MaxNumber, | |
IN OUT UINTN *CurrentNumber, | |
IN UINTN Entry | |
) | |
{ | |
UINTN *TempTable; | |
// | |
// Check whether the table is enough to store new entry. | |
// | |
if (*CurrentNumber == *MaxNumber) { | |
// | |
// Reallocate memory for the table. | |
// | |
TempTable = ReallocateRuntimePool ( | |
*MaxNumber * sizeof (UINTN), | |
(*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN), | |
*Table | |
); | |
// | |
// No enough resource to allocate. | |
// | |
if (TempTable == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
*Table = TempTable; | |
// | |
// Increase max number. | |
// | |
*MaxNumber += VAR_CHECK_TABLE_SIZE; | |
} | |
// | |
// Add entry to the table. | |
// | |
(*Table)[*CurrentNumber] = Entry; | |
(*CurrentNumber)++; | |
return EFI_SUCCESS; | |
} | |
/** | |
Register END_OF_DXE callback. | |
The callback will be invoked by VarCheckLibInitializeAtEndOfDxe(). | |
@param[in] Callback END_OF_DXE callback. | |
@retval EFI_SUCCESS The callback was registered successfully. | |
@retval EFI_INVALID_PARAMETER Callback is NULL. | |
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has | |
already been signaled. | |
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibRegisterEndOfDxeCallback ( | |
IN VAR_CHECK_END_OF_DXE_CALLBACK Callback | |
) | |
{ | |
EFI_STATUS Status; | |
if (Callback == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (mVarCheckLibEndOfDxe) { | |
return EFI_ACCESS_DENIED; | |
} | |
Status = VarCheckAddTableEntry ( | |
(UINTN **)&mVarCheckLibEndOfDxeCallback, | |
&mVarCheckLibEndOfDxeCallbackMaxCount, | |
&mVarCheckLibEndOfDxeCallbackCount, | |
(UINTN)Callback | |
); | |
DEBUG ((DEBUG_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status)); | |
return Status; | |
} | |
/** | |
Var check initialize at END_OF_DXE. | |
This function needs to be called at END_OF_DXE. | |
Address pointers may be returned, | |
and caller needs to ConvertPointer() for the pointers. | |
@param[in, out] AddressPointerCount Output pointer to address pointer count. | |
@return Address pointer buffer, NULL if input AddressPointerCount is NULL. | |
**/ | |
VOID *** | |
EFIAPI | |
VarCheckLibInitializeAtEndOfDxe ( | |
IN OUT UINTN *AddressPointerCount OPTIONAL | |
) | |
{ | |
VOID *TempTable; | |
UINTN TotalCount; | |
UINTN Index; | |
for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) { | |
// | |
// Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback(). | |
// | |
mVarCheckLibEndOfDxeCallback[Index](); | |
} | |
if (mVarCheckLibEndOfDxeCallback != NULL) { | |
// | |
// Free the callback buffer. | |
// | |
mVarCheckLibEndOfDxeCallbackCount = 0; | |
mVarCheckLibEndOfDxeCallbackMaxCount = 0; | |
FreePool ((VOID *)mVarCheckLibEndOfDxeCallback); | |
mVarCheckLibEndOfDxeCallback = NULL; | |
} | |
mVarCheckLibEndOfDxe = TRUE; | |
if (AddressPointerCount == NULL) { | |
if (mVarCheckLibAddressPointer != NULL) { | |
// | |
// Free the address pointer buffer. | |
// | |
mVarCheckLibAddressPointerCount = 0; | |
mVarCheckLibAddressPointerMaxCount = 0; | |
FreePool ((VOID *)mVarCheckLibAddressPointer); | |
mVarCheckLibAddressPointer = NULL; | |
} | |
return NULL; | |
} | |
// | |
// Get the total count needed. | |
// Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries. | |
// | |
TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1); | |
TempTable = ReallocateRuntimePool ( | |
mVarCheckLibAddressPointerMaxCount * sizeof (VOID **), | |
TotalCount * sizeof (VOID **), | |
(VOID *)mVarCheckLibAddressPointer | |
); | |
if (TempTable != NULL) { | |
mVarCheckLibAddressPointer = (VOID ***)TempTable; | |
// | |
// Cover VarCheckHandler and the entries. | |
// | |
mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable; | |
for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) { | |
mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable[Index]; | |
} | |
// | |
// Cover VarCheckVariable and the entries. | |
// | |
mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable; | |
for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) { | |
mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable[Index]; | |
} | |
ASSERT (mVarCheckLibAddressPointerCount == TotalCount); | |
mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount; | |
} | |
*AddressPointerCount = mVarCheckLibAddressPointerCount; | |
return mVarCheckLibAddressPointer; | |
} | |
/** | |
Register address pointer. | |
The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe(). | |
@param[in] AddressPointer Address pointer. | |
@retval EFI_SUCCESS The address pointer was registered successfully. | |
@retval EFI_INVALID_PARAMETER AddressPointer is NULL. | |
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has | |
already been signaled. | |
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibRegisterAddressPointer ( | |
IN VOID **AddressPointer | |
) | |
{ | |
EFI_STATUS Status; | |
if (AddressPointer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (mVarCheckLibEndOfDxe) { | |
return EFI_ACCESS_DENIED; | |
} | |
Status = VarCheckAddTableEntry ( | |
(UINTN **)&mVarCheckLibAddressPointer, | |
&mVarCheckLibAddressPointerMaxCount, | |
&mVarCheckLibAddressPointerCount, | |
(UINTN)AddressPointer | |
); | |
DEBUG ((DEBUG_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status)); | |
return Status; | |
} | |
/** | |
Register SetVariable check handler. | |
@param[in] Handler Pointer to check handler. | |
@retval EFI_SUCCESS The SetVariable check handler was registered successfully. | |
@retval EFI_INVALID_PARAMETER Handler is NULL. | |
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has | |
already been signaled. | |
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request. | |
@retval EFI_UNSUPPORTED This interface is not implemented. | |
For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibRegisterSetVariableCheckHandler ( | |
IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler | |
) | |
{ | |
EFI_STATUS Status; | |
if (Handler == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (mVarCheckLibEndOfDxe) { | |
return EFI_ACCESS_DENIED; | |
} | |
Status = VarCheckAddTableEntry ( | |
(UINTN **)&mVarCheckHandlerTable, | |
&mMaxNumberOfVarCheckHandler, | |
&mNumberOfVarCheckHandler, | |
(UINTN)Handler | |
); | |
DEBUG ((DEBUG_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status)); | |
return Status; | |
} | |
/** | |
Variable property set. | |
@param[in] Name Pointer to the variable name. | |
@param[in] Guid Pointer to the vendor GUID. | |
@param[in] VariableProperty Pointer to the input variable property. | |
@retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully. | |
@retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string, | |
or the fields of VariableProperty are not valid. | |
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has | |
already been signaled. | |
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibVariablePropertySet ( | |
IN CHAR16 *Name, | |
IN EFI_GUID *Guid, | |
IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty | |
) | |
{ | |
EFI_STATUS Status; | |
VAR_CHECK_VARIABLE_ENTRY *Entry; | |
CHAR16 *VariableName; | |
VAR_CHECK_VARIABLE_PROPERTY *Property; | |
if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (VariableProperty == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (mVarCheckLibEndOfDxe) { | |
return EFI_ACCESS_DENIED; | |
} | |
Status = EFI_SUCCESS; | |
// | |
// Get the pointer of property data for set. | |
// | |
Property = VariablePropertyGetFunction (Name, Guid, FALSE); | |
if (Property != NULL) { | |
CopyMem (Property, VariableProperty, sizeof (*VariableProperty)); | |
} else { | |
Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name)); | |
if (Entry == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry)); | |
StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name); | |
CopyGuid (&Entry->Guid, Guid); | |
CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty)); | |
Status = VarCheckAddTableEntry ( | |
(UINTN **)&mVarCheckVariableTable, | |
&mMaxNumberOfVarCheckVariable, | |
&mNumberOfVarCheckVariable, | |
(UINTN)Entry | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (Entry); | |
} | |
} | |
return Status; | |
} | |
/** | |
Variable property get. | |
@param[in] Name Pointer to the variable name. | |
@param[in] Guid Pointer to the vendor GUID. | |
@param[out] VariableProperty Pointer to the output variable property. | |
@retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully. | |
@retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string. | |
@retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibVariablePropertyGet ( | |
IN CHAR16 *Name, | |
IN EFI_GUID *Guid, | |
OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty | |
) | |
{ | |
VAR_CHECK_VARIABLE_PROPERTY *Property; | |
if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (VariableProperty == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Property = VariablePropertyGetFunction (Name, Guid, TRUE); | |
// | |
// Also check the property revision before using the property data. | |
// There is no property set to this variable(wildcard name) | |
// if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. | |
// | |
if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { | |
CopyMem (VariableProperty, Property, sizeof (*VariableProperty)); | |
return EFI_SUCCESS; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
SetVariable check. | |
@param[in] VariableName Name of Variable to set. | |
@param[in] VendorGuid Variable vendor GUID. | |
@param[in] Attributes Attribute value of the variable. | |
@param[in] DataSize Size of Data to set. | |
@param[in] Data Data pointer. | |
@param[in] RequestSource Request source. | |
@retval EFI_SUCCESS The SetVariable check result was success. | |
@retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID, | |
DataSize and Data value was supplied. | |
@retval EFI_WRITE_PROTECTED The variable in question is read-only. | |
@retval Others The other return status from check handler. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VarCheckLibSetVariableCheck ( | |
IN CHAR16 *VariableName, | |
IN EFI_GUID *VendorGuid, | |
IN UINT32 Attributes, | |
IN UINTN DataSize, | |
IN VOID *Data, | |
IN VAR_CHECK_REQUEST_SOURCE RequestSource | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
VAR_CHECK_VARIABLE_PROPERTY *Property; | |
if (!mVarCheckLibEndOfDxe) { | |
// | |
// Only do check after End Of Dxe. | |
// | |
return EFI_SUCCESS; | |
} | |
Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE); | |
// | |
// Also check the property revision before using the property data. | |
// There is no property set to this variable(wildcard name) | |
// if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. | |
// | |
if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { | |
if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) { | |
DEBUG ((DEBUG_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName)); | |
return EFI_WRITE_PROTECTED; | |
} | |
if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) { | |
// | |
// Not to delete variable. | |
// | |
if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) { | |
DEBUG ((DEBUG_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); | |
return EFI_INVALID_PARAMETER; | |
} | |
if (DataSize != 0) { | |
if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) { | |
DEBUG ((DEBUG_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); | |
return EFI_INVALID_PARAMETER; | |
} | |
} | |
} | |
} | |
for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) { | |
Status = mVarCheckHandlerTable[Index]( | |
VariableName, | |
VendorGuid, | |
Attributes, | |
DataSize, | |
Data | |
); | |
if ((Status == EFI_WRITE_PROTECTED) && (RequestSource == VarCheckFromTrusted)) { | |
// | |
// If RequestSource is trusted, then allow variable to be set even if it | |
// is write protected. | |
// | |
continue; | |
} | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName)); | |
return Status; | |
} | |
} | |
return EFI_SUCCESS; | |
} |