mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-27 12:15:19 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
1275 lines
43 KiB
C
1275 lines
43 KiB
C
/** @file
|
|
Sample platform variable cleanup library implementation.
|
|
|
|
Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "PlatVarCleanup.h"
|
|
|
|
VAR_ERROR_FLAG mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
|
|
EDKII_VAR_CHECK_PROTOCOL *mVarCheck = NULL;
|
|
|
|
///
|
|
/// The flag to indicate whether the platform has left the DXE phase of execution.
|
|
///
|
|
BOOLEAN mEndOfDxe = FALSE;
|
|
|
|
EFI_EVENT mPlatVarCleanupLibEndOfDxeEvent = NULL;
|
|
|
|
LIST_ENTRY mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
|
|
UINT16 mUserVariableCount = 0;
|
|
UINT16 mMarkedUserVariableCount = 0;
|
|
|
|
EFI_GUID mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
|
|
CHAR16 mVarStoreName[] = L"VariableCleanup";
|
|
|
|
HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
VARIABLE_CLEANUP_HII_GUID
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
|
|
(UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
Internal get variable error flag.
|
|
|
|
@return Variable error flag.
|
|
|
|
**/
|
|
VAR_ERROR_FLAG
|
|
InternalGetVarErrorFlag (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Size;
|
|
VAR_ERROR_FLAG ErrorFlag;
|
|
|
|
Size = sizeof (ErrorFlag);
|
|
Status = gRT->GetVariable (
|
|
VAR_ERROR_FLAG_NAME,
|
|
&gEdkiiVarErrorFlagGuid,
|
|
NULL,
|
|
&Size,
|
|
&ErrorFlag
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));
|
|
return VAR_ERROR_FLAG_NO_ERROR;
|
|
}
|
|
return ErrorFlag;
|
|
}
|
|
|
|
/**
|
|
Is user variable?
|
|
|
|
@param[in] Name Pointer to variable name.
|
|
@param[in] Guid Pointer to vendor guid.
|
|
|
|
@retval TRUE User variable.
|
|
@retval FALSE System variable.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsUserVariable (
|
|
IN CHAR16 *Name,
|
|
IN EFI_GUID *Guid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VAR_CHECK_VARIABLE_PROPERTY Property;
|
|
|
|
if (mVarCheck == NULL) {
|
|
gBS->LocateProtocol (
|
|
&gEdkiiVarCheckProtocolGuid,
|
|
NULL,
|
|
(VOID **) &mVarCheck
|
|
);
|
|
}
|
|
ASSERT (mVarCheck != NULL);
|
|
|
|
ZeroMem (&Property, sizeof (Property));
|
|
Status = mVarCheck->VariablePropertyGet (
|
|
Name,
|
|
Guid,
|
|
&Property
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// No property, it is user variable.
|
|
//
|
|
DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
|
|
return TRUE;
|
|
}
|
|
|
|
// DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
|
|
// DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));
|
|
// DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));
|
|
// DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));
|
|
// DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));
|
|
// DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Find user variable node by variable GUID.
|
|
|
|
@param[in] Guid Pointer to vendor guid.
|
|
|
|
@return Pointer to user variable node.
|
|
|
|
**/
|
|
USER_VARIABLE_NODE *
|
|
FindUserVariableNodeByGuid (
|
|
IN EFI_GUID *Guid
|
|
)
|
|
{
|
|
USER_VARIABLE_NODE *UserVariableNode;
|
|
LIST_ENTRY *Link;
|
|
|
|
for (Link = mUserVariableList.ForwardLink
|
|
;Link != &mUserVariableList
|
|
;Link = Link->ForwardLink) {
|
|
UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
|
|
|
|
if (CompareGuid (Guid, &UserVariableNode->Guid)) {
|
|
//
|
|
// Found it.
|
|
//
|
|
return UserVariableNode;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create new one if not found.
|
|
//
|
|
UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
|
|
ASSERT (UserVariableNode != NULL);
|
|
UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
|
|
CopyGuid (&UserVariableNode->Guid, Guid);
|
|
//
|
|
// (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
|
|
//
|
|
UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
|
|
ASSERT (UserVariableNode->PromptString != NULL);
|
|
UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
|
|
InitializeListHead (&UserVariableNode->NameLink);
|
|
InsertTailList (&mUserVariableList, &UserVariableNode->Link);
|
|
return UserVariableNode;
|
|
}
|
|
|
|
/**
|
|
Create user variable node.
|
|
|
|
**/
|
|
VOID
|
|
CreateUserVariableNode (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS GetVariableStatus;
|
|
CHAR16 *VarName;
|
|
UINTN MaxVarNameSize;
|
|
UINTN VarNameSize;
|
|
UINTN MaxDataSize;
|
|
UINTN DataSize;
|
|
VOID *Data;
|
|
UINT32 Attributes;
|
|
EFI_GUID Guid;
|
|
USER_VARIABLE_NODE *UserVariableNode;
|
|
USER_VARIABLE_NAME_NODE *UserVariableNameNode;
|
|
UINT16 Index;
|
|
UINTN StringSize;
|
|
|
|
//
|
|
// Initialize 128 * sizeof (CHAR16) variable name size.
|
|
//
|
|
MaxVarNameSize = 128 * sizeof (CHAR16);
|
|
VarName = AllocateZeroPool (MaxVarNameSize);
|
|
ASSERT (VarName != NULL);
|
|
|
|
//
|
|
// Initialize 0x1000 variable data size.
|
|
//
|
|
MaxDataSize = 0x1000;
|
|
Data = AllocateZeroPool (MaxDataSize);
|
|
ASSERT (Data != NULL);
|
|
|
|
Index = 0;
|
|
do {
|
|
VarNameSize = MaxVarNameSize;
|
|
Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
|
|
ASSERT (VarName != NULL);
|
|
MaxVarNameSize = VarNameSize;
|
|
Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (IsUserVariable (VarName, &Guid)) {
|
|
DataSize = MaxDataSize;
|
|
GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
|
|
if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
|
|
Data = ReallocatePool (MaxDataSize, DataSize, Data);
|
|
ASSERT (Data != NULL);
|
|
MaxDataSize = DataSize;
|
|
GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
|
|
}
|
|
ASSERT_EFI_ERROR (GetVariableStatus);
|
|
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
UserVariableNode = FindUserVariableNodeByGuid (&Guid);
|
|
ASSERT (UserVariableNode != NULL);
|
|
|
|
//
|
|
// Different variables that have same variable GUID share same user variable node.
|
|
//
|
|
UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
|
|
ASSERT (UserVariableNameNode != NULL);
|
|
UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
|
|
UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
|
|
UserVariableNameNode->Attributes = Attributes;
|
|
UserVariableNameNode->DataSize = DataSize;
|
|
UserVariableNameNode->Index = Index;
|
|
UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
|
|
//
|
|
// 2 space * sizeof (CHAR16) + StrSize.
|
|
//
|
|
StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
|
|
UserVariableNameNode->PromptString = AllocatePool (StringSize);
|
|
ASSERT (UserVariableNameNode->PromptString != NULL);
|
|
UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L" %s", UserVariableNameNode->Name);
|
|
//
|
|
// (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
|
|
//
|
|
StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
|
|
UserVariableNameNode->HelpString = AllocatePool (StringSize);
|
|
ASSERT (UserVariableNameNode->HelpString != NULL);
|
|
UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
|
|
UserVariableNameNode->Deleted = FALSE;
|
|
InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
|
|
Index++;
|
|
}
|
|
}
|
|
}
|
|
} while (Status != EFI_NOT_FOUND);
|
|
|
|
mUserVariableCount = Index;
|
|
ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
|
|
DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
|
|
|
|
FreePool (VarName);
|
|
FreePool (Data);
|
|
}
|
|
|
|
/**
|
|
Destroy user variable nodes.
|
|
|
|
**/
|
|
VOID
|
|
DestroyUserVariableNode (
|
|
VOID
|
|
)
|
|
{
|
|
USER_VARIABLE_NODE *UserVariableNode;
|
|
LIST_ENTRY *Link;
|
|
USER_VARIABLE_NAME_NODE *UserVariableNameNode;
|
|
LIST_ENTRY *NameLink;
|
|
|
|
while (mUserVariableList.ForwardLink != &mUserVariableList) {
|
|
Link = mUserVariableList.ForwardLink;
|
|
UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
|
|
|
|
RemoveEntryList (&UserVariableNode->Link);
|
|
|
|
while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
|
|
NameLink = UserVariableNode->NameLink.ForwardLink;
|
|
UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
|
|
|
|
RemoveEntryList (&UserVariableNameNode->Link);
|
|
|
|
FreePool (UserVariableNameNode->Name);
|
|
FreePool (UserVariableNameNode->PromptString);
|
|
FreePool (UserVariableNameNode->HelpString);
|
|
FreePool (UserVariableNameNode);
|
|
}
|
|
|
|
FreePool (UserVariableNode->PromptString);
|
|
FreePool (UserVariableNode);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
|
|
descriptor with the input data. NO authentication is required in this function.
|
|
|
|
@param[in, out] DataSize On input, the size of Data buffer in bytes.
|
|
On output, the size of data returned in Data
|
|
buffer in bytes.
|
|
@param[in, out] Data On input, Pointer to data buffer to be wrapped or
|
|
pointer to NULL to wrap an empty payload.
|
|
On output, Pointer to the new payload date buffer allocated from pool,
|
|
it's caller's responsibility to free the memory after using it.
|
|
|
|
@retval EFI_SUCCESS Create time based payload successfully.
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
|
|
@retval EFI_INVALID_PARAMETER The parameter is invalid.
|
|
@retval Others Unexpected error happens.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CreateTimeBasedPayload (
|
|
IN OUT UINTN *DataSize,
|
|
IN OUT UINT8 **Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *NewData;
|
|
UINT8 *Payload;
|
|
UINTN PayloadSize;
|
|
EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
|
|
UINTN DescriptorSize;
|
|
EFI_TIME Time;
|
|
|
|
if (Data == NULL || DataSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// At user physical presence, the variable does not need to be signed but the
|
|
// parameters to the SetVariable() call still need to be prepared as authenticated
|
|
// variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
|
|
// data in it.
|
|
//
|
|
Payload = *Data;
|
|
PayloadSize = *DataSize;
|
|
|
|
DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
|
|
NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
|
|
if (NewData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if ((Payload != NULL) && (PayloadSize != 0)) {
|
|
CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
|
|
}
|
|
|
|
DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
|
|
|
|
ZeroMem (&Time, sizeof (EFI_TIME));
|
|
Status = gRT->GetTime (&Time, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (NewData);
|
|
return Status;
|
|
}
|
|
Time.Pad1 = 0;
|
|
Time.Nanosecond = 0;
|
|
Time.TimeZone = 0;
|
|
Time.Daylight = 0;
|
|
Time.Pad2 = 0;
|
|
CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
|
|
|
|
DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
|
|
DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
|
|
DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
|
|
CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
|
|
|
|
if (Payload != NULL) {
|
|
FreePool (Payload);
|
|
}
|
|
|
|
*DataSize = DescriptorSize + PayloadSize;
|
|
*Data = NewData;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
|
|
descriptor with the input data. NO authentication is required in this function.
|
|
|
|
@param[in, out] DataSize On input, the size of Data buffer in bytes.
|
|
On output, the size of data returned in Data
|
|
buffer in bytes.
|
|
@param[in, out] Data On input, Pointer to data buffer to be wrapped or
|
|
pointer to NULL to wrap an empty payload.
|
|
On output, Pointer to the new payload date buffer allocated from pool,
|
|
it's caller's responsibility to free the memory after using it.
|
|
|
|
@retval EFI_SUCCESS Create counter based payload successfully.
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
|
|
@retval EFI_INVALID_PARAMETER The parameter is invalid.
|
|
@retval Others Unexpected error happens.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CreateCounterBasedPayload (
|
|
IN OUT UINTN *DataSize,
|
|
IN OUT UINT8 **Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *NewData;
|
|
UINT8 *Payload;
|
|
UINTN PayloadSize;
|
|
EFI_VARIABLE_AUTHENTICATION *DescriptorData;
|
|
UINTN DescriptorSize;
|
|
UINT64 MonotonicCount;
|
|
|
|
if (Data == NULL || DataSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// At user physical presence, the variable does not need to be signed but the
|
|
// parameters to the SetVariable() call still need to be prepared as authenticated
|
|
// variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
|
|
// data in it.
|
|
//
|
|
Payload = *Data;
|
|
PayloadSize = *DataSize;
|
|
|
|
DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
|
|
(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
|
|
sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
|
|
NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
|
|
if (NewData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if ((Payload != NULL) && (PayloadSize != 0)) {
|
|
CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
|
|
}
|
|
|
|
DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
|
|
|
|
Status = gBS->GetNextMonotonicCount (&MonotonicCount);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (NewData);
|
|
return Status;
|
|
}
|
|
DescriptorData->MonotonicCount = MonotonicCount;
|
|
|
|
DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
|
|
DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
|
|
DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
|
|
CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
|
|
|
|
if (Payload != NULL) {
|
|
FreePool (Payload);
|
|
}
|
|
|
|
*DataSize = DescriptorSize + PayloadSize;
|
|
*Data = NewData;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Delete user variable.
|
|
|
|
@param[in] DeleteAll Delete all user variables.
|
|
@param[in] VariableCleanupData Pointer to variable cleanup data.
|
|
|
|
**/
|
|
VOID
|
|
DeleteUserVariable (
|
|
IN BOOLEAN DeleteAll,
|
|
IN VARIABLE_CLEANUP_DATA *VariableCleanupData OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USER_VARIABLE_NODE *UserVariableNode;
|
|
LIST_ENTRY *Link;
|
|
USER_VARIABLE_NAME_NODE *UserVariableNameNode;
|
|
LIST_ENTRY *NameLink;
|
|
UINTN DataSize;
|
|
UINT8 *Data;
|
|
|
|
for (Link = mUserVariableList.ForwardLink
|
|
;Link != &mUserVariableList
|
|
;Link = Link->ForwardLink) {
|
|
UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
|
|
|
|
for (NameLink = UserVariableNode->NameLink.ForwardLink
|
|
;NameLink != &UserVariableNode->NameLink
|
|
;NameLink = NameLink->ForwardLink) {
|
|
UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
|
|
|
|
if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
|
|
DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
|
|
if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
|
|
DataSize = 0;
|
|
Data = NULL;
|
|
Status = CreateTimeBasedPayload (&DataSize, &Data);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
|
|
FreePool (Data);
|
|
}
|
|
} else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
|
|
DataSize = 0;
|
|
Data = NULL;
|
|
Status = CreateCounterBasedPayload (&DataSize, &Data);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
|
|
FreePool (Data);
|
|
}
|
|
} else {
|
|
Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
|
|
}
|
|
if (!EFI_ERROR (Status)) {
|
|
UserVariableNameNode->Deleted = TRUE;
|
|
} else {
|
|
DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function allows a caller to extract the current configuration for one
|
|
or more named elements from the target driver.
|
|
|
|
@param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param[in] Request A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param[out] Progress On return, points to a character in the Request string.
|
|
Points to the string's null terminator if request was successful.
|
|
Points to the most recent '&' before the first failing name/value
|
|
pair (or the beginning of the string if the failure is in the
|
|
first name/value pair) if the request was not successful.
|
|
@param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which
|
|
has all values filled in for the names in the Request string.
|
|
String to be allocated by the called function.
|
|
|
|
@retval EFI_SUCCESS The Results is filled with the requested values.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableCleanupHiiExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
|
|
UINTN BufferSize;
|
|
EFI_STRING ConfigRequestHdr;
|
|
EFI_STRING ConfigRequest;
|
|
BOOLEAN AllocatedRequest;
|
|
UINTN Size;
|
|
|
|
if (Progress == NULL || Results == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Progress = Request;
|
|
if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ConfigRequestHdr = NULL;
|
|
ConfigRequest = NULL;
|
|
AllocatedRequest = FALSE;
|
|
Size = 0;
|
|
|
|
Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
|
|
//
|
|
// Convert buffer data to <ConfigResp> by helper function BlockToConfig().
|
|
//
|
|
BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
|
|
ConfigRequest = Request;
|
|
if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
|
|
//
|
|
// Request has no request element, construct full request string.
|
|
// Allocate and fill a buffer large enough to hold the <ConfigHdr> template
|
|
// followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
|
|
//
|
|
ConfigRequestHdr = HiiConstructConfigHdr (&mVariableCleanupHiiGuid, mVarStoreName, Private->HiiHandle);
|
|
Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
|
|
ConfigRequest = AllocateZeroPool (Size);
|
|
ASSERT (ConfigRequest != NULL);
|
|
AllocatedRequest = TRUE;
|
|
UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
|
|
FreePool (ConfigRequestHdr);
|
|
}
|
|
|
|
Status = Private->ConfigRouting->BlockToConfig (
|
|
Private->ConfigRouting,
|
|
ConfigRequest,
|
|
(UINT8 *) &Private->VariableCleanupData,
|
|
BufferSize,
|
|
Results,
|
|
Progress
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Free the allocated config request string.
|
|
//
|
|
if (AllocatedRequest) {
|
|
FreePool (ConfigRequest);
|
|
ConfigRequest = NULL;
|
|
}
|
|
//
|
|
// Set Progress string to the original request string or the string's null terminator.
|
|
//
|
|
if (Request == NULL) {
|
|
*Progress = NULL;
|
|
} else if (StrStr (Request, L"OFFSET") == NULL) {
|
|
*Progress = Request + StrLen (Request);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update user variable form.
|
|
|
|
@param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
|
|
|
|
**/
|
|
VOID
|
|
UpdateUserVariableForm (
|
|
IN VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private
|
|
)
|
|
{
|
|
EFI_STRING_ID PromptStringToken;
|
|
EFI_STRING_ID HelpStringToken;
|
|
VOID *StartOpCodeHandle;
|
|
VOID *EndOpCodeHandle;
|
|
EFI_IFR_GUID_LABEL *StartLabel;
|
|
EFI_IFR_GUID_LABEL *EndLabel;
|
|
USER_VARIABLE_NODE *UserVariableNode;
|
|
LIST_ENTRY *Link;
|
|
USER_VARIABLE_NAME_NODE *UserVariableNameNode;
|
|
LIST_ENTRY *NameLink;
|
|
BOOLEAN Created;
|
|
|
|
//
|
|
// Init OpCode Handle.
|
|
//
|
|
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (StartOpCodeHandle != NULL);
|
|
|
|
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (EndOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode.
|
|
//
|
|
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
StartLabel->Number = LABEL_START;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the end opcode.
|
|
//
|
|
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
EndLabel->Number = LABEL_END;
|
|
|
|
HiiUpdateForm (
|
|
Private->HiiHandle,
|
|
&mVariableCleanupHiiGuid,
|
|
FORM_ID_VARIABLE_CLEANUP,
|
|
StartOpCodeHandle, // LABEL_START
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
for (Link = mUserVariableList.ForwardLink
|
|
;Link != &mUserVariableList
|
|
;Link = Link->ForwardLink) {
|
|
UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
|
|
|
|
//
|
|
// Create checkbox opcode for variables in the same variable GUID space.
|
|
//
|
|
Created = FALSE;
|
|
for (NameLink = UserVariableNode->NameLink.ForwardLink
|
|
;NameLink != &UserVariableNode->NameLink
|
|
;NameLink = NameLink->ForwardLink) {
|
|
UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
|
|
|
|
if (!UserVariableNameNode->Deleted) {
|
|
if (!Created) {
|
|
//
|
|
// Create subtitle opcode for variable GUID.
|
|
//
|
|
PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
|
|
HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
|
|
Created = TRUE;
|
|
}
|
|
|
|
//
|
|
// Only create opcode for the non-deleted variables.
|
|
//
|
|
PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
|
|
HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
|
|
HiiCreateCheckBoxOpCode (
|
|
StartOpCodeHandle,
|
|
UserVariableNameNode->QuestionId,
|
|
VARIABLE_CLEANUP_VARSTORE_ID,
|
|
(UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
|
|
PromptStringToken,
|
|
HelpStringToken,
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
HiiCreateSubTitleOpCode (
|
|
StartOpCodeHandle,
|
|
STRING_TOKEN (STR_NULL_STRING),
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Create the "Apply changes" and "Discard changes" tags.
|
|
//
|
|
HiiCreateActionOpCode (
|
|
StartOpCodeHandle,
|
|
SAVE_AND_EXIT_QUESTION_ID,
|
|
STRING_TOKEN (STR_SAVE_AND_EXIT),
|
|
STRING_TOKEN (STR_NULL_STRING),
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
0
|
|
);
|
|
HiiCreateActionOpCode (
|
|
StartOpCodeHandle,
|
|
NO_SAVE_AND_EXIT_QUESTION_ID,
|
|
STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
|
|
STRING_TOKEN (STR_NULL_STRING),
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
0
|
|
);
|
|
|
|
HiiUpdateForm (
|
|
Private->HiiHandle,
|
|
&mVariableCleanupHiiGuid,
|
|
FORM_ID_VARIABLE_CLEANUP,
|
|
StartOpCodeHandle, // LABEL_START
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (StartOpCodeHandle);
|
|
HiiFreeOpCodeHandle (EndOpCodeHandle);
|
|
}
|
|
|
|
/**
|
|
This function applies changes in a driver's configuration.
|
|
Input is a Configuration, which has the routing data for this
|
|
driver followed by name / value configuration pairs. The driver
|
|
must apply those pairs to its configurable storage. If the
|
|
driver's configuration is stored in a linear block of data
|
|
and the driver's name / value pairs are in <BlockConfig>
|
|
format, it may use the ConfigToBlock helper function (above) to
|
|
simplify the job. Currently not implemented.
|
|
|
|
@param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param[in] Configuration A null-terminated Unicode string in
|
|
<ConfigString> format.
|
|
@param[out] Progress A pointer to a string filled in with the
|
|
offset of the most recent '&' before the
|
|
first failing name / value pair (or the
|
|
beginn ing of the string if the failure
|
|
is in the first name / value pair) or
|
|
the terminating NULL if all was
|
|
successful.
|
|
|
|
@retval EFI_SUCCESS The results have been distributed or are
|
|
awaiting distribution.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the
|
|
parts of the results that must be
|
|
stored awaiting possible future
|
|
protocols.
|
|
@retval EFI_INVALID_PARAMETERS Passing in a NULL for the
|
|
Results parameter would result
|
|
in this type of error.
|
|
@retval EFI_NOT_FOUND Target for the specified routing data
|
|
was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableCleanupHiiRouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
|
|
UINTN BufferSize;
|
|
|
|
if (Progress == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*Progress = Configuration;
|
|
|
|
if (Configuration == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check routing data in <ConfigHdr>.
|
|
// Note: there is no name for Name/Value storage, only GUID will be checked.
|
|
//
|
|
if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
|
|
//
|
|
// Get Buffer Storage data.
|
|
//
|
|
BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
|
|
//
|
|
// Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
|
|
//
|
|
Status = Private->ConfigRouting->ConfigToBlock (
|
|
Private->ConfigRouting,
|
|
Configuration,
|
|
(UINT8 *) &Private->VariableCleanupData,
|
|
&BufferSize,
|
|
Progress
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DeleteUserVariable (FALSE, &Private->VariableCleanupData);
|
|
//
|
|
// For "F10" hotkey to refresh the form.
|
|
//
|
|
// UpdateUserVariableForm (Private);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called to provide results data to the driver.
|
|
This data consists of a unique key that is used to identify
|
|
which data is either being passed back or being asked for.
|
|
|
|
@param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param[in] Action Specifies the type of action taken by the browser.
|
|
@param[in] QuestionId A unique value which is sent to the original
|
|
exporting driver so that it can identify the type
|
|
of data to expect. The format of the data tends to
|
|
vary based on the opcode that generated the callback.
|
|
@param[in] Type The type of value for the question.
|
|
@param[in] Value A pointer to the data being sent to the original
|
|
exporting driver.
|
|
@param[out] ActionRequest On return, points to the action requested by the
|
|
callback function.
|
|
|
|
@retval EFI_SUCCESS The callback successfully handled the action.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
|
|
variable and its data.
|
|
@retval EFI_DEVICE_ERROR The variable could not be saved.
|
|
@retval EFI_UNSUPPORTED The specified Action is not supported by the
|
|
callback.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableCleanupHiiCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
|
|
VARIABLE_CLEANUP_DATA *VariableCleanupData;
|
|
|
|
Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
|
|
|
|
if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
|
|
//
|
|
// All other action return unsupported.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Retrieve uncommitted data from Form Browser.
|
|
//
|
|
VariableCleanupData = &Private->VariableCleanupData;
|
|
HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
|
|
if (Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
if (Value == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if (Action == EFI_BROWSER_ACTION_CHANGED) {
|
|
if ((Value == NULL) || (ActionRequest == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
|
|
if (Value->b){
|
|
//
|
|
// Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
|
|
//
|
|
mMarkedUserVariableCount++;
|
|
ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
|
|
if (mMarkedUserVariableCount == mUserVariableCount) {
|
|
//
|
|
// All user variables have been marked, then also mark the SelectAll checkbox.
|
|
//
|
|
VariableCleanupData->SelectAll = TRUE;
|
|
}
|
|
} else {
|
|
//
|
|
// Means one user variable checkbox is unmarked.
|
|
//
|
|
mMarkedUserVariableCount--;
|
|
//
|
|
// Also unmark the SelectAll checkbox.
|
|
//
|
|
VariableCleanupData->SelectAll = FALSE;
|
|
}
|
|
} else {
|
|
switch (QuestionId) {
|
|
case SELECT_ALL_QUESTION_ID:
|
|
if (Value->b){
|
|
//
|
|
// Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
|
|
//
|
|
SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
|
|
mMarkedUserVariableCount = mUserVariableCount;
|
|
} else {
|
|
//
|
|
// Means the SelectAll checkbox is unmarked.
|
|
//
|
|
SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
|
|
mMarkedUserVariableCount = 0;
|
|
}
|
|
break;
|
|
case SAVE_AND_EXIT_QUESTION_ID:
|
|
DeleteUserVariable (FALSE, VariableCleanupData);
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
|
|
break;
|
|
|
|
case NO_SAVE_AND_EXIT_QUESTION_ID:
|
|
//
|
|
// Restore local maintain data.
|
|
//
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pass changed uncommitted data back to Form Browser.
|
|
//
|
|
HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Platform variable cleanup.
|
|
|
|
@param[in] Flag Variable error flag.
|
|
@param[in] Type Variable cleanup type.
|
|
If it is VarCleanupManually, the interface must be called after console connected.
|
|
|
|
@retval EFI_SUCCESS No error or error processed.
|
|
@retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
|
|
For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
|
|
Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
|
|
@retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
|
|
@retval Others Other failure occurs.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformVarCleanup (
|
|
IN VAR_ERROR_FLAG Flag,
|
|
IN VAR_CLEANUP_TYPE Type
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
|
|
VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
|
|
|
|
if (!mEndOfDxe) {
|
|
//
|
|
// This implementation must be called after EndOfDxe.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
|
|
//
|
|
// Just return success if no error.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
|
|
//
|
|
// This sample does not support system variables cleanup.
|
|
//
|
|
DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
|
|
DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Continue to process VAR_ERROR_FLAG_USER_ERROR.
|
|
//
|
|
|
|
//
|
|
// Create user variable nodes for the following processing.
|
|
//
|
|
CreateUserVariableNode ();
|
|
|
|
switch (Type) {
|
|
case VarCleanupAll:
|
|
DeleteUserVariable (TRUE, NULL);
|
|
//
|
|
// Destroyed the created user variable nodes
|
|
//
|
|
DestroyUserVariableNode ();
|
|
return EFI_SUCCESS;
|
|
break;
|
|
|
|
case VarCleanupManually:
|
|
//
|
|
// Locate FormBrowser2 protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
|
|
if (Private == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
|
|
Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
|
|
Private->ConfigAccess.RouteConfig = VariableCleanupHiiRouteConfig;
|
|
Private->ConfigAccess.Callback = VariableCleanupHiiCallback;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiConfigRoutingProtocolGuid,
|
|
NULL,
|
|
(VOID **) &Private->ConfigRouting
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Install Device Path Protocol and Config Access protocol to driver handle.
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Private->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mVarCleanupHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&Private->ConfigAccess,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Publish our HII data.
|
|
//
|
|
Private->HiiHandle = HiiAddPackages (
|
|
&mVariableCleanupHiiGuid,
|
|
Private->DriverHandle,
|
|
PlatformVarCleanupLibStrings,
|
|
PlatVarCleanupBin,
|
|
NULL
|
|
);
|
|
if (Private->HiiHandle == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
UpdateUserVariableForm (Private);
|
|
|
|
Status = FormBrowser2->SendForm (
|
|
FormBrowser2,
|
|
&Private->HiiHandle,
|
|
1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
break;
|
|
}
|
|
|
|
Done:
|
|
if (Private->DriverHandle != NULL) {
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Private->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mVarCleanupHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&Private->ConfigAccess,
|
|
NULL
|
|
);
|
|
}
|
|
if (Private->HiiHandle != NULL) {
|
|
HiiRemovePackages (Private->HiiHandle);
|
|
}
|
|
|
|
FreePool (Private);
|
|
|
|
//
|
|
// Destroyed the created user variable nodes
|
|
//
|
|
DestroyUserVariableNode ();
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get last boot variable error flag.
|
|
|
|
@return Last boot variable error flag.
|
|
|
|
**/
|
|
VAR_ERROR_FLAG
|
|
EFIAPI
|
|
GetLastBootVarErrorFlag (
|
|
VOID
|
|
)
|
|
{
|
|
return mLastVarErrorFlag;
|
|
}
|
|
|
|
/**
|
|
Notification function of END_OF_DXE.
|
|
|
|
This is a notification function registered on END_OF_DXE event.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformVarCleanupEndOfDxeEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
mEndOfDxe = TRUE;
|
|
}
|
|
|
|
/**
|
|
The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
|
|
|
|
The constructor function locates VarCheck protocol from protocol database.
|
|
It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformVarCleanupLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
mLastVarErrorFlag = InternalGetVarErrorFlag ();
|
|
DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
|
|
|
|
//
|
|
// Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
PlatformVarCleanupEndOfDxeEvent,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&mPlatVarCleanupLibEndOfDxeEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The destructor function closes the End of DXE event.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The destructor completed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformVarCleanupLibDestructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Close the End of DXE event.
|
|
//
|
|
Status = gBS->CloseEvent (mPlatVarCleanupLibEndOfDxeEvent);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|