summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Library/PlatformVarCleanupLib
diff options
context:
space:
mode:
authorStar Zeng <star.zeng@intel.com>2015-08-25 03:11:06 +0000
committerlzeng14 <lzeng14@Edk2>2015-08-25 03:11:06 +0000
commitc95d9ab81a1382b11989c691c3934306417fc019 (patch)
tree78ac6e3e4ff08e252736781b2ee3d516a231d37c /MdeModulePkg/Library/PlatformVarCleanupLib
parenta2918326ac6aa7acfc696dcd46c42037474e1540 (diff)
downloadedk2-c95d9ab81a1382b11989c691c3934306417fc019.tar.gz
edk2-c95d9ab81a1382b11989c691c3934306417fc019.tar.bz2
edk2-c95d9ab81a1382b11989c691c3934306417fc019.zip
MdeModulePkg: Add PlatformVarCleanupLib library
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18295 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Library/PlatformVarCleanupLib')
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h108
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr41
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h59
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c1250
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf73
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.unibin0 -> 1766 bytes
-rw-r--r--MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.unibin0 -> 4528 bytes
7 files changed, 1531 insertions, 0 deletions
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
new file mode 100644
index 0000000000..5290aae158
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
@@ -0,0 +1,108 @@
+/** @file
+ Include file for platform variable cleanup.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_
+#define _PLAT_VAR_CLEANUP_
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PlatformVarCleanupLib.h>
+
+#include <Protocol/Variable.h>
+#include <Protocol/VarCheck.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/VarErrorFlag.h>
+
+#include "PlatVarCleanupHii.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatVarCleanupBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatformVarCleanupLibStrings[];
+
+#define USER_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_GUID Guid;
+ CHAR16 *PromptString;
+ LIST_ENTRY NameLink;
+} USER_VARIABLE_NODE;
+
+#define USER_VARIABLE_FROM_LINK(a) CR (a, USER_VARIABLE_NODE, Link, USER_VARIABLE_NODE_SIGNATURE)
+
+#define USER_VARIABLE_NAME_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'N')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ UINTN DataSize;
+ UINT32 Attributes;
+ UINT16 Index;
+ EFI_QUESTION_ID QuestionId;
+ CHAR16 *PromptString;
+ CHAR16 *HelpString;
+ BOOLEAN Deleted;
+} USER_VARIABLE_NAME_NODE;
+
+#define USER_VARIABLE_NAME_FROM_LINK(a) CR (a, USER_VARIABLE_NAME_NODE, Link, USER_VARIABLE_NAME_NODE_SIGNATURE)
+
+#pragma pack(1)
+//
+// HII specific Vendor Device Path definition.
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+#pragma pack()
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ VARIABLE_CLEANUP_DATA VariableCleanupData;
+} VARIABLE_CLEANUP_HII_PRIVATE_DATA;
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS(a) CR (a, VARIABLE_CLEANUP_HII_PRIVATE_DATA, ConfigAccess, VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE)
+
+#endif
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
new file mode 100644
index 0000000000..7dfeafa2c4
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
@@ -0,0 +1,41 @@
+/** @file
+ Platform variable cleanup Formset.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PlatVarCleanupHii.h"
+
+formset
+ guid = VARIABLE_CLEANUP_HII_GUID,
+ title = STRING_TOKEN(STR_ENTRY_TITLE),
+ help = STRING_TOKEN(STR_TITLE_HELP),
+
+ varstore VARIABLE_CLEANUP_DATA,
+ varid = VARIABLE_CLEANUP_VARSTORE_ID,
+ name = VariableCleanup,
+ guid = VARIABLE_CLEANUP_HII_GUID;
+
+ form formid = FORM_ID_VARIABLE_CLEANUP,
+ title = STRING_TOKEN(STR_TITLE);
+
+ checkbox varid = VARIABLE_CLEANUP_DATA.SelectAll,
+ prompt = STRING_TOKEN(STR_SELECT_ALL_PROMPT),
+ help = STRING_TOKEN(STR_SELECT_ALL_HELP),
+ flags = INTERACTIVE,
+ key = SELECT_ALL_QUESTION_ID,
+ endcheckbox;
+
+ label LABEL_START;
+ label LABEL_END;
+
+ endform;
+endformset;
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
new file mode 100644
index 0000000000..02af877b44
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
@@ -0,0 +1,59 @@
+/** @file
+ Include file for platform variable cleanup HII.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_HII_
+#define _PLAT_VAR_CLEANUP_HII_
+
+//
+// {24F14D8A-D7A8-4991-91E0-96C3B7DB8456}
+//
+#define VARIABLE_CLEANUP_HII_GUID \
+ { \
+ 0x24f14d8a, 0xd7a8, 0x4991, { 0x91, 0xe0, 0x96, 0xc3, 0xb7, 0xdb, 0x84, 0x56 } \
+ }
+
+#define MAX_USER_VARIABLE_COUNT 0x1000
+
+typedef struct {
+ UINT8 SelectAll;
+ //
+ // FALSE is to not delete, TRUE is to delete.
+ //
+ UINT8 UserVariable[MAX_USER_VARIABLE_COUNT];
+} VARIABLE_CLEANUP_DATA;
+
+#define VARIABLE_CLEANUP_VARSTORE_ID 0x8000
+
+//
+// Field offset of structure VARIABLE_CLEANUP_DATA
+//
+#define VAR_OFFSET(Field) ((UINTN) &(((VARIABLE_CLEANUP_DATA *) 0)->Field))
+#define USER_VARIABLE_VAR_OFFSET (VAR_OFFSET (UserVariable))
+
+#define FORM_ID_VARIABLE_CLEANUP 0x8000
+
+#define LABEL_START 0x0000
+#define LABEL_END 0xFFFF
+
+#define SELECT_ALL_QUESTION_ID 0x7FFD
+#define SAVE_AND_EXIT_QUESTION_ID 0x7FFE
+#define NO_SAVE_AND_EXIT_QUESTION_ID 0x7FFF
+
+//
+// Tool automatic generated Question Id start from 1.
+// In order to avoid to conflict them, the user variable QuestionID offset is defined from 0x8000.
+//
+#define USER_VARIABLE_QUESTION_ID 0x8000
+
+#endif
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
new file mode 100644
index 0000000000..d99174c4b9
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
@@ -0,0 +1,1250 @@
+/** @file
+ Sample platform variable cleanup library implementation.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+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;
+
+ 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;
+ }
+
+ //
+ // Retrive 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 (
+ )
+{
+ 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;
+ EFI_EVENT Event;
+
+ mLastVarErrorFlag = InternalGetVarErrorFlag ();
+ DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
+
+ Status = gBS->LocateProtocol (
+ &gEdkiiVarCheckProtocolGuid,
+ NULL,
+ (VOID **) &mVarCheck
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PlatformVarCleanupEndOfDxeEvent,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
new file mode 100644
index 0000000000..c56a17584a
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
@@ -0,0 +1,73 @@
+## @file
+# Sample platform variable cleanup library instance.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformVarCleanupLib
+ MODULE_UNI_FILE = PlatformVarCleanupLib.uni
+ FILE_GUID = 9C9623EB-4EF3-44e0-A931-F3A340D1A0F9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformVarCleanupLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = PlatformVarCleanupLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ PlatVarCleanupLib.c
+ PlatVarCleanup.h
+ PlatVarCleanupHii.h
+ PlatVarCleanup.vfr
+ VfrStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PrintLib
+ MemoryAllocationLib
+ HiiLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## GUID
+ gEdkiiVarErrorFlagGuid ## CONSUMES ## Variable:L"VarErrorFlag"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID
+ gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEdkiiVarCheckProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiHiiConfigRoutingProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEdkiiVarCheckProtocolGuid AND
+ gEfiVariableArchProtocolGuid
+
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
new file mode 100644
index 0000000000..e4a0debafa
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
Binary files differ
diff --git a/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni b/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
new file mode 100644
index 0000000000..56f8e3625f
--- /dev/null
+++ b/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
Binary files differ